        .dropdown-toggle::after {
            display: none !important;
        }
        .page-title-row > :first-child {
            min-width: 0;
            max-width: 100%;
            overflow: hidden;
        }
        .page-title-row > :last-child {
            flex-shrink: 0;
        }
                html, body {
            overflow-x: hidden;
            height:100%;
            background-color: var(--orbit-body-bg)
        }
        body {
            font-family: 'Public Sans', sans-serif;
            font-size:15px;
            height: 100vh
        }
        :root {
            color-scheme: light;
            --orbit-radius: 10px;

            /* ---- xYnta brand tokens (cycle E iteratie 5)
               Gesynched met www.xynta.com main_min.css. Brand-colors
               blijven constant in dark-mode; context-tokens (bg,
               border, text) rebinden wel in dark.css. */
            --x-brand-blue: #2F6FB3;
            --x-brand-blue-rgb: 47, 111, 179;
            --x-brand-blue-deep: #3B5F86;
            --x-brand-blue-deep-rgb: 59, 95, 134;
            --x-brand-blue-soft: #91B2D2;
            --x-brand-blue-soft-rgb: 145, 178, 210;
            --x-brand-orange: #F28C38;
            --x-brand-orange-rgb: 244, 138, 58;
            --x-brand-orange-soft: #F2A55F;
            --x-brand-orange-soft-rgb: 242, 165, 95;

            /* xYnta brand palette (matches www.xynta.com).
               Override Bootstrap so all bg-X / text-X / border-X / btn-X
               classes use brand-consistent colors. Warning is bewust geel/goud
               (matcht --orbit-stat-card-warning, --orbit-chart-warning,
               --x-alert-warning + Bootstrap's eigen warning-text-emphasis #664d03).
               Brand-orange #F28C38 leeft door als --x-brand-orange en
               --orbit-accent voor CTAs/gradients — niet als waarschuwingskleur. */
            --bs-primary:   #2F6FB3;
            --bs-secondary: #3B5F86;
            --bs-success:   #96bd5e;
            --bs-info:      #6E9EC2;
            --bs-warning:   #E8B93C;
            --bs-danger:    #DC3545;
            --bs-primary-rgb:   47, 111, 179;
            --bs-secondary-rgb: 59, 95, 134;
            --bs-success-rgb:   150, 189, 94;
            --bs-info-rgb:      110, 158, 194;
            --bs-warning-rgb:   232, 185, 60;
            --bs-danger-rgb:    220, 53, 69;
            --bs-body-bg:       #F4F7FB;
            --bs-body-color:    #2D3F5A;
            --bs-border-color:  #D8E2EE;
            --bs-link-color:    #2F6FB3;
            --bs-link-hover-color: #255B94;

            /* Alle surface-bg tokens (modal/card/list-group/accordion/
               dropdown/nav-tabs/form-control) staan op component-level
               verderop in deze file — Bootstrap 5.3 defineert die
               tokens lokaal in `.modal{...}` / `.card{...}` / etc.,
               wat :root-override shadowt. Component-level scope werkt
               wel (gelijke specificity, later in source-order). */

            /* Orbit brand product-semantic tokens (theme-invariant). */
            --orbit-primary-deep: #1a3150;
            --orbit-primary: #254672;

            /* Info theme accents (theme-invariant; --helios-info-accent is
               a separate theme-varying token for form-focus borders etc). */
            --orbit-info-accent: #8ab2d2;
            --orbit-info-bg-subtle: #e6f0f7;

            /* Body background (html, body). */
            --orbit-body-bg: #ededed;

            /* User-menu segmented sub-system (4-color cohesive set used on
               the userManageMenu dropdown's dark-blue inline background). */
            --orbit-segmented-border: #1b355a;
            --orbit-segmented-bg: #203d63;
            --orbit-segmented-bg-hover: #274a78;
            --orbit-segmented-bg-selected: #2c568f;

            --orbit-stat-card-neutral-bg: #f5f8fc;
            --orbit-stat-card-neutral-border: #d7e0eb;
            --orbit-stat-card-neutral-value: #1f2f44;
            --orbit-stat-card-neutral-label: #4e6077;

            --orbit-stat-card-info-bg: #ecf6ff;
            --orbit-stat-card-info-border: #b9d9f4;
            --orbit-stat-card-info-value: #174f7f;

            --orbit-stat-card-success-bg: #f1f7e6;
            --orbit-stat-card-success-border: #cfe1aa;
            --orbit-stat-card-success-value: #4f6f2a;

            --orbit-stat-card-primary-bg: #eef3fb;
            --orbit-stat-card-primary-border: #c7d9ef;
            --orbit-stat-card-primary-value: #1e4d82;

            --orbit-stat-card-warning-bg: #fff7e0;
            --orbit-stat-card-warning-border: #f0d28a;
            --orbit-stat-card-warning-value: #7a5a14;

            --orbit-stat-card-danger-bg: #fdeff1;
            --orbit-stat-card-danger-border: #f1c2c8;
            --orbit-stat-card-danger-value: #8b1e2c;

            /* Orbit-notice icon-tile bg — gebruikt door tpl/orbit-notice.php
               voor de 40px rounded-square icon-tile op de role-tinted card.
               Light-mode: 60% wit overlay (subtiele "raised" tile). Dark-mode
               override hieronder geeft een donkere recess zodat de saturated
               value-color icoon (bv. #d4ecaa op success) leesbaar blijft. */
            --orbit-notice-tile-bg: rgba(255, 255, 255, 0.6);

            --orbit-chart-primary: #2F6FB3;
            --orbit-chart-success: #96bd5e;
            --orbit-chart-warning: #f0c36d;
            --orbit-chart-danger:  #DC3545;
            --orbit-chart-info:    #6E9EC2;
            --orbit-chart-secondary: #6c757d;
            --orbit-chart-grid: #dfe6ef;
            --orbit-chart-fore: #5f7087;
            /* OK-bar fill: heel zachte grijs voor "ok"-segmenten in stacked
               bars — visueel rustig zoals de 30d-status-strip ok-dagen
               (`.bg-secondary-subtle`). Dark variant in :dark/auto blokken. */
            --orbit-chart-ok-bar: #e2e3e5;
            --orbit-chart-tooltip-bg: #ffffff;
            --orbit-chart-tooltip-text: #1f2f44;
            --orbit-chart-tooltip-border: #d7dde6;
            --orbit-chart-empty-text: #4f5f75;
            --orbit-chart-empty-bg: linear-gradient(180deg, rgba(110,158,194,0.12) 0%, rgba(245,248,252,0.95) 100%);
            --orbit-chart-empty-border: rgba(47, 111, 179, 0.2);

            /* Card surface used for pie/donut segment strokes (theme-aware). */
            --orbit-card-bg: #ffffff;

            /* ---------------------------------------------------------------
               Accent family — brand oranje/rood for primary CTAs, sidebar
               active-state, and gradient endpoints. Introduced in cycle D
               for visual alignment with xynta.com. See design-system.md §8
               for use-cases. Not a replacement for --bs-primary (that stays
               the standard "save/submit" color); accent is ONE CTA per page.
               --------------------------------------------------------------- */
            --orbit-accent: #F28C38;
            --orbit-accent-hover: #DD7A25;
            --orbit-accent-subtle: rgba(244, 138, 58, 0.12);
            --orbit-accent-deep: #BE6720;
            --orbit-accent-light: #F5A867;
            --orbit-on-accent: #ffffff;

            /* Brand gradients — CTA for accent buttons with gradient
               fills. Hero gradients live in the hero-v2 token-block. */
            --orbit-gradient-cta: linear-gradient(135deg, #F5A867 0%, #F28C38 100%);

            /* Light-mode fallback for the subtle border used on cards.
               dark.css defines its own value; this lets rules reference
               var(--helios-border-subtle) without needing a fallback. */
            --helios-border-subtle: rgba(0, 0, 0, 0.08);

            /* Helios dark-surface tokens (light-mode fallbacks).
               Used by rules in dark.css to avoid hardcoded hex; these
               defaults apply when no dark theme is active. */
            --helios-text: #212529;
            --helios-surface-raised: #ffffff;
            --helios-surface-sunken: #f8f9fa;
            --helios-surface-deep: #223f67;
            --helios-surface-hover: #e9ecef;
            --helios-surface-selected: #dee2e6;
            --helios-info-accent: #6E9EC2;
            --helios-muted: #6c757d;
            --helios-timeline-line: #dee2e6;

            /* Alert-specifieke warning — historisch los token toen --bs-warning
               nog brand-oranje was; nu identiek aan --bs-warning en behouden
               voor .alert-warning's eigen color-mix recipes. Dark-mode rebind
               in dark.css. */
            --x-alert-warning: #E8B93C;

            /* Status-chip tokens — xynta-aligned (1-op-1 recipe).
               Used by .badge.bg-{success,warning,danger,info} variants
               (incl. -subtle and text-bg-*). Primary/secondary badges
               stay Bootstrap-default (solid, wit-op-role). Dark-mode
               overrides live in dark.css. */
            --x-status-success-chip-bg:     color-mix(in srgb, #96bd5e 11%, white);
            --x-status-success-chip-border: color-mix(in srgb, #96bd5e 30%, white);
            --x-status-success-chip-ink:    color-mix(in srgb, #96bd5e 72%, #2D3F5A);

            --x-status-warning-chip-bg:     color-mix(in srgb, #E8B93C 14%, white);
            --x-status-warning-chip-border: color-mix(in srgb, #E8B93C 34%, #D8E2EE);
            --x-status-warning-chip-ink:    color-mix(in srgb, #E8B93C 78%, #2D3F5A);

            --x-status-danger-chip-bg:      color-mix(in srgb, #DC3545 14%, white);
            --x-status-danger-chip-border:  color-mix(in srgb, #DC3545 32%, #D8E2EE);
            --x-status-danger-chip-ink:     color-mix(in srgb, #DC3545 68%, #2D3F5A);

            --x-status-info-chip-bg:        color-mix(in srgb, #6E9EC2 14%, white);
            --x-status-info-chip-border:    color-mix(in srgb, #6E9EC2 30%, #D8E2EE);
            --x-status-info-chip-ink:       color-mix(in srgb, #6E9EC2 70%, #2D3F5A);
        }

        [data-theme="dark"],
        [data-bs-theme="dark"] {
            --orbit-stat-card-neutral-bg: #263445;
            --orbit-stat-card-neutral-border: #3a4d63;
            --orbit-stat-card-neutral-value: #e6edf7;
            --orbit-stat-card-neutral-label: #b8c7d9;

            /* Subtle info-tint voor klant-intro-cards (frontend-canon §37).
               Iets donkerder dan --orbit-stat-card-info-bg zodat een tile in
               die laatste kleur er als raised inset op leest. */
            --orbit-info-bg-subtle: #1a2f40;

            --orbit-stat-card-info-bg: #213849;
            --orbit-stat-card-info-border: #355872;
            --orbit-stat-card-info-value: #d6e9fb;

            --orbit-stat-card-success-bg: #2a3a1f;
            --orbit-stat-card-success-border: #4d6831;
            --orbit-stat-card-success-value: #d4ecaa;

            --orbit-stat-card-primary-bg: #22364b;
            --orbit-stat-card-primary-border: #35506f;
            --orbit-stat-card-primary-value: #d9e8fa;

            --orbit-stat-card-warning-bg: #4a3320;
            --orbit-stat-card-warning-border: #75522e;
            --orbit-stat-card-warning-value: #ffd5a8;

            --orbit-stat-card-danger-bg: #472b31;
            --orbit-stat-card-danger-border: #6c3c45;
            --orbit-stat-card-danger-value: #ffd6dc;

            /* Donkere recess i.p.v. 60% wit overlay — voorkomt washed-out
               tile waarop de lichte value-color icoon onleesbaar wordt. */
            --orbit-notice-tile-bg: rgba(0, 0, 0, 0.28);

            --orbit-chart-primary: #5f8fb3;
            --orbit-chart-success: #b9da82;
            --orbit-chart-warning: #f5b27a;
            --orbit-chart-danger:  #f07a89;
            --orbit-chart-info:    #7aa7c7;
            --orbit-chart-secondary: #95a8bd;
            --orbit-chart-grid: #32465f;
            --orbit-chart-fore: #b6c2d1;
            /* Dark-variant ok-bar — surface-raised + 6% white, mirror van het
               .bg-secondary-subtle dark-effect in dark.css. */
            --orbit-chart-ok-bar: #232c3a;
            --orbit-chart-tooltip-bg: #1d2a3b;
            --orbit-chart-tooltip-text: #e6edf5;
            --orbit-chart-tooltip-border: #32465f;
            --orbit-chart-empty-text: #c7d4e2;
            --orbit-chart-empty-bg: linear-gradient(180deg, rgba(47,111,179,0.18) 0%, rgba(21,30,40,0.95) 100%);
            --orbit-chart-empty-border: rgba(110, 158, 194, 0.25);

            /* Dark-mode card surface for pie/donut segment strokes. */
            --orbit-card-bg: #1d2a3b;

            /* Helios dark-surface tokens (dark-mode values). */
            --helios-text: #e6eaf0;
            --helios-surface-raised: #151e28;
            --helios-surface-sunken: #131b24;
            --helios-surface-deep: #0b1220;
            --helios-surface-hover: #1a2533;
            --helios-surface-selected: #2a3446;
            --helios-info-accent: #8ab2d2;
            --helios-muted: #94a3b8;
            --helios-timeline-line: #334155;
        }

        /* Auto theme: mirror dark-mode CSS vars when OS prefers dark.
           Closes a gap where [data-theme="auto"] previously inherited the
           light :root tokens on a dark-preferring OS. */
        @media (prefers-color-scheme: dark) {
            [data-theme="auto"],
            [data-bs-theme="auto"] {
                --orbit-stat-card-neutral-bg: #263445;
                --orbit-stat-card-neutral-border: #3a4d63;
                --orbit-stat-card-neutral-value: #e6edf7;
                --orbit-stat-card-neutral-label: #b8c7d9;

                /* Subtle info-tint voor klant-intro-cards — frontend-canon §37
                   (mirror van het [data-theme="dark"] override-blok hierboven). */
                --orbit-info-bg-subtle: #1a2f40;

                --orbit-stat-card-info-bg: #213849;
                --orbit-stat-card-info-border: #355872;
                --orbit-stat-card-info-value: #d6e9fb;

                --orbit-stat-card-success-bg: #2a3a1f;
                --orbit-stat-card-success-border: #4d6831;
                --orbit-stat-card-success-value: #d4ecaa;

                --orbit-stat-card-primary-bg: #22364b;
                --orbit-stat-card-primary-border: #35506f;
                --orbit-stat-card-primary-value: #d9e8fa;

                --orbit-stat-card-warning-bg: #4a3320;
                --orbit-stat-card-warning-border: #75522e;
                --orbit-stat-card-warning-value: #ffd5a8;

                --orbit-stat-card-danger-bg: #472b31;
                --orbit-stat-card-danger-border: #6c3c45;
                --orbit-stat-card-danger-value: #ffd6dc;

                /* Mirror dark-mode notice tile bg (zie [data-theme="dark"] hierboven). */
                --orbit-notice-tile-bg: rgba(0, 0, 0, 0.28);

                --orbit-chart-primary: #5f8fb3;
                --orbit-chart-success: #b9da82;
                --orbit-chart-warning: #f5b27a;
                --orbit-chart-danger:  #f07a89;
                --orbit-chart-info:    #7aa7c7;
                --orbit-chart-secondary: #95a8bd;
                --orbit-chart-grid: #32465f;
                --orbit-chart-fore: #b6c2d1;
                --orbit-chart-ok-bar: #232c3a;
                --orbit-chart-tooltip-bg: #1d2a3b;
                --orbit-chart-tooltip-text: #e6edf5;
                --orbit-chart-tooltip-border: #32465f;
                --orbit-chart-empty-text: #c7d4e2;
                --orbit-chart-empty-bg: linear-gradient(180deg, rgba(47,111,179,0.18) 0%, rgba(21,30,40,0.95) 100%);
                --orbit-chart-empty-border: rgba(110, 158, 194, 0.25);

                --orbit-card-bg: #1d2a3b;

                --helios-text: #e6eaf0;
                --helios-surface-raised: #151e28;
                --helios-surface-sunken: #131b24;
                --helios-surface-deep: #0b1220;
                --helios-surface-hover: #1a2533;
                --helios-surface-selected: #2a3446;
                --helios-info-accent: #8ab2d2;
                --helios-muted: #94a3b8;
                --helios-timeline-line: #334155;
            }
        }
        body.offcanvas-open {
            position: fixed;
            width: 100%;
            overflow-x: hidden !important;
        }
        img.invert {
            filter: invert(1);
        }
        /* Select2-dropdown (de open popup met opties) boven Bootstrap modal
           (1055) zodat select2 buiten een modal werkt zonder dropdownParent.
           Voor select2 BINNEN een modal gebruikt de project-code expliciet
           `dropdownParent: $modal` (zie helios-user-select.js, view.php
           modal-scoped init) — dan zit de dropdown in de modal-stacking-
           context en heeft deze regel geen effect.

           NB: het select2-CONTAINER-element (de visuele select-vervanger)
           krijgt GEEN z-index. Een hoge z-index op de container laat het
           veld door modal-backdrops heen lekken (modal-backdrop = 1050,
           modal = 1055) en breekt elke modal die over een form met
           select2-velden opent. */
        .select2-dropdown,
        .select2-container--open .select2-dropdown {
            z-index: 10000 !important;
        }

        /* Make modal body scrollable with max height */
        #manageGeneralDiscountsModal .modal-body,
        #manageCustomerDiscountsModal .modal-body,
        #managePriceChangesModal .modal-body,
        #viewPriceHistoryModal .modal-body {
            max-height: calc(100vh - 200px);
            overflow-y: auto;
        }
        /* Frontend auth helpers */
        .auth-helper a {
            color: var(--bs-primary);
        }
        /* Make entire list item show draggable cursor and improve drag feedback */
        #orderList .list-group-item { cursor: grab; }
        #orderList .list-group-item:active { cursor: grabbing; }
        #orderList .list-group-item .drag-handle { cursor: grab; }
        .sortable-ghost { opacity: 0.7; }
        .auth-helper a:hover {
            text-decoration: underline;
        }
        .html-content h1,
        .html-content h2,
        .html-content h3,
        .html-content h4,
        .html-content h5,
        .html-content h6 {
            font-family: 'Public Sans', sans-serif;
            line-height: 1.25;
            margin: 0 0 0.75rem;
            font-weight: 700;
            text-transform:none;
        }

        .html-content h1 { font-size: 1.6rem; }
        .html-content h2 { font-size: 1.35rem; }
        .html-content h3 { font-size: 1.15rem; }
        .html-content h4 { font-size: 1.0rem; }
        .html-content h5 { font-size: 0.95rem; }
        .html-content h6 { font-size: 0.9rem; }

        .html-content img {
            max-width: 100%;
            height:auto
        }
        /* Orbit divider */
        .orbit-divider {
            display: flex;
            align-items: center;
            text-align: center;
            color: #9ca3af;
            font-size: 0.85rem;
        }

        .orbit-divider::before,
        .orbit-divider::after {
            content: '';
            flex: 1;
            border-bottom: 1px solid rgba(0,0,0,.1);
        }

        .orbit-divider span {
            padding: 0 .75rem;
        }
                .offcanvas-backdrop-less {
                    overflow: hidden;
                }

                /* Orbit language switcher */
                .orbit-language-switch .orbit-flag {
                    width: 34px;
                    height: 34px;
                    border-radius: 50%;
                    background: #ffffff;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    overflow: hidden;
                    box-shadow: 0 1px 3px rgba(0,0,0,.15);
                }

                .orbit-language-switch .orbit-flag img {
                    width: 26px;
                    height: 26px;
                }

                .orbit-language-switch .orbit-chevron {
                    width: 12px;
                    opacity: .6;
                }

                /* Prevent flag icons from being inverted in dark mode */
                .orbit-language-switch .orbit-flag img,
                .orbit-language-switch .dropdown-menu img {
                    filter: none !important;
                }

                .orbit-language-switch button:hover .orbit-flag {
                    box-shadow: 0 0 0 3px rgba(255,255,255,.25);
                }
        /* Mobile hamburger-toggle — accent-oranje gradient als
           herkenbare "open-sidebar" CTA. Icon erft kleur via
           currentColor; wit in light (contrast op oranje),
           zwart in dark-mode (dark.css rebindt).
           Twee Lucide-icons (open/close) crossfaden via opacity-
           transition op aria-expanded. Button houdt vaste 44×44px
           zodat absolute-centered icons layout niet verschuiven. */
        .mobile-nav {
            position: relative;
            width: 44px;
            height: 44px;
            background: linear-gradient(
                135deg,
                var(--orbit-accent),
                var(--orbit-accent-hover)
            );
            color: #ffffff;
            border: 0 !important;
            box-shadow: 0 2px 6px rgba(var(--x-brand-orange-rgb), 0.25);
            transition: transform 0.1s ease, box-shadow 0.15s ease;
        }
        .mobile-nav:hover,
        .mobile-nav:focus-visible {
            background: linear-gradient(
                135deg,
                var(--orbit-accent-hover),
                var(--orbit-accent-deep)
            );
            box-shadow: 0 4px 10px rgba(var(--x-brand-orange-rgb), 0.35);
            transform: translateY(-1px);
        }
        .mobile-nav:active {
            transform: translateY(1px);
            box-shadow: 0 1px 3px rgba(var(--x-brand-orange-rgb), 0.20);
        }
        /* Icon crossfade via opacity-transition op aria-expanded.
           Beide icons gelaagd op zelfde positie (absolute-centered);
           closed zichtbaar in rust, open fade-in bij aria-expanded="true".
           200ms ease-out iets sneller dan sidebar-slide (250ms) zodat
           icon al klaar is voor volledige sidebar-open. */
        .mobile-nav .mobile-nav-icon-closed,
        .mobile-nav .mobile-nav-icon-open {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            transition: opacity 200ms ease-out;
        }
        .mobile-nav .mobile-nav-icon-closed {
            opacity: 1;
        }
        .mobile-nav .mobile-nav-icon-open {
            opacity: 0;
        }
        .mobile-nav[aria-expanded="true"] .mobile-nav-icon-closed {
            opacity: 0;
        }
        .mobile-nav[aria-expanded="true"] .mobile-nav-icon-open {
            opacity: 1;
        }
        .helios-logo {
            content: url("/assets/img/logo_orbit_light.webp");
        }
        #mobileHeader {
            height: 64px;
            min-height: 64px;
            z-index: 1200;
            background: var(--orbit-primary);
            backdrop-filter: blur(6px);
        }
        .helios-hover-lift {
            transition: transform .12s ease, box-shadow .12s ease;
        }
        .helios-hover-lift:hover {
            transform: translateY(-1px);
            box-shadow: 0 .25rem .75rem rgba(0,0,0,.05);
        }
        .helios-badge {
            font-size: .65rem;
            font-weight: 500;
            padding: .15rem .4rem;
            border-radius: .375rem;
            background: #f1f3f5;
            color: var(--helios-muted);
        }
        .dataTables_wrapper {
            overflow: visible!important;
        }

        /* ======================================================================
           DataTables 2.x — mobile controls override (Orbit, 2026-05-25)
           ----------------------------------------------------------------------
           Upstream `dataTables.bootstrap5.min.css` centert .dt-length, .dt-search,
           .dt-info en .dt-paging op <768px en houdt inputs op `width:auto;
           display:inline-block`. Resultaat: smalle, gecentreerde controls die
           niet matchen met de Orbit-mobile UX. Dit block overrulet alléén de
           mobile-laag — desktop (>=768px) blijft 1:1 zoals upstream.

           CRITICAL — selector-specificity: upstream gebruikt overal
           `div.dt-container div.dt-X` (specificity 0,3,3). Onze overrides
           moeten datzelfde patroon volgen, anders verliezen non-!important
           properties (zoals `margin-left:.5em` op de search-input) van
           upstream — dat geeft rechts-overflow en linker-indent. Met gelijke
           specificity wint main.css via source-order (main.css laadt ná
           dataTables.bootstrap5.min.css in header.php).

           Canonical project-dom (zie design-system.md §15) ondersteunt deze
           overrides door:
             · `align-items-md-center` (i.p.v. `align-items-center`) zodat
               mobile-children full-width strekken in plaats van content-width;
             · `flex-column-reverse` op de footer-wrapper zodat paging boven
               de info-tekst staat op mobiel (primary action zichtbaar zonder
               scroll), terwijl `flex-md-row` op desktop links-rechts oplevert.

           Search-styling spiegelt het canonical input-group-pattern uit
           `backend/domains/contacts/index.php` (design-system §17 stap 2):
           label visually-hidden, full-width input met Lucide-search icon
           als background-image-prepend. Geen DOM-changes nodig — pure CSS.
           ======================================================================*/
        @media (max-width: 767.98px) {
            /* Search — input-group-stijl (mirror van contacts/index.php canon).
               Label visually-hidden (a11y intact via for-binding op de input);
               input full-width met Lucide-search icon als background-prepend.   */
            div.dt-container div.dt-search {
                width: 100%;
                position: relative;
            }
            div.dt-container div.dt-search label {
                position: absolute !important;
                width: 1px !important;
                height: 1px !important;
                padding: 0 !important;
                margin: -1px !important;
                overflow: hidden !important;
                clip: rect(0, 0, 0, 0) !important;
                white-space: nowrap !important;
                border: 0 !important;
            }
            div.dt-container div.dt-search input {
                width: 100% !important;
                margin: 0 !important;
                display: block;
                padding-left: 2.4rem;
                background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='11' cy='11' r='8'/><path d='m21 21-4.3-4.3'/></svg>");
                background-repeat: no-repeat;
                background-position: 0.875rem center;
                background-size: 16px 16px;
            }

            /* Length — links uitgelijnd, klein, muted (secundaire control) */
            div.dt-container div.dt-length {
                width: 100%;
                text-align: left !important;
                font-size: 0.8125rem;
                color: var(--helios-muted);
            }
            div.dt-container div.dt-length label {
                margin: 0;
                white-space: normal;
            }
            /* Houd de upstream `.5em` tussen <select> en de "resultaten
               per pagina" text-node — anders kleven ze tegen elkaar
               omdat `gap` niet betrouwbaar tussen flex-items en
               anonymous text-nodes werkt.                              */
            div.dt-container div.dt-length select {
                margin-right: 0.5em;
            }

            /* Info — klein, links, muted (tertiair) */
            div.dt-container div.dt-info {
                width: 100%;
                text-align: left !important;
                font-size: 0.75rem;
                color: var(--helios-muted);
                padding-top: 0;
            }

            /* Paging — rechts uitgelijnd, compact pills.
               Selector matched upstream specificity (0,3,3) zodat onze
               `justify-content:flex-end !important` wint via source-order
               van upstream `justify-content:center !important`.            */
            div.dt-container div.dt-paging {
                width: 100%;
            }
            /* Geen `gap` op .pagination — BS5 rendert page-items als
               joined button-group met gedeelde borders. Een gap breekt
               die visuele unit.                                         */
            div.dt-container div.dt-paging ul.pagination {
                justify-content: flex-end !important;
                margin: 0;
                flex-wrap: wrap;
            }
            div.dt-container div.dt-paging .page-link {
                padding: 0.3rem 0.55rem;
                font-size: 0.8125rem;
                /* Touch-target 44px (Apple HIG / Material). page-link
                   krijgt inline-flex zodat zowel min-width als min-height
                   correct centered worden ongeacht text-content.        */
                min-width: 44px;
                min-height: 44px;
                display: inline-flex;
                align-items: center;
                justify-content: center;
            }
            /* Touch-targets op search-input + length-select. */
            div.dt-container div.dt-search input,
            div.dt-container div.dt-length select {
                min-height: 44px;
            }
            /* Dark-mode variant van het Lucide-search icon — lichtere
               stroke (#cbd5e1, slate-300) voor leesbaarheid op donkere
               input-bg. Selector matched mobile-rule specificity. */
            html[data-theme="dark"] div.dt-container div.dt-search input {
                background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23cbd5e1' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='11' cy='11' r='8'/><path d='m21 21-4.3-4.3'/></svg>");
            }
        }

        /* DataTables — length-selector verbergen op extra-small viewports
           (<480px). Page-size tunen op een phone is zeldzaam, en de default
           (25) is bijna altijd OK. Gratis schermruimte voor de tabel.    */
        @media (max-width: 479.98px) {
            div.dt-container div.dt-length {
                display: none !important;
            }
        }

        /* ======================================================================
           DataTables — clear-button (✕) in search-input
           ----------------------------------------------------------------------
           Geïnjecteerd door orbit-datatables-defaults.js op elke DT-instance
           (mirror van het canonical input-group pattern in
           backend/domains/contacts/index.php). Globaal voor alle viewports —
           hetzelfde a11y-helper-element op desktop en mobile.
           ====================================================================== */
        .dt-container .dt-search {
            position: relative;
        }
        .orbit-dt-search-clear {
            position: absolute;
            right: 0.5rem;
            top: 50%;
            transform: translateY(-50%);
            width: 26px;
            height: 26px;
            padding: 0;
            border: 0;
            background: transparent;
            color: var(--helios-muted);
            font-size: 1.25rem;
            line-height: 1;
            cursor: pointer;
            border-radius: 50%;
            transition: color .15s ease, background-color .15s ease;
            z-index: 2;
            display: inline-flex;
            align-items: center;
            justify-content: center;
        }
        .orbit-dt-search-clear:hover,
        .orbit-dt-search-clear:focus-visible {
            color: var(--bs-body-color);
            background-color: rgba(0, 0, 0, 0.06);
            outline: 0;
        }
        html[data-theme="dark"] .orbit-dt-search-clear:hover,
        html[data-theme="dark"] .orbit-dt-search-clear:focus-visible {
            background-color: rgba(255, 255, 255, 0.08);
        }
        /* Padding rechts in de input zodat tekst niet onder de clear-button
           verdwijnt. Op mobile (waar input full-width is) komt dit bovenop
           de bestaande padding-left van 2.4rem voor het search-icon.     */
        .dt-container .dt-search input {
            padding-right: 2.25rem;
        }
        /* Native cancel-X verbergen op <input type="search">. Browsers
           (Webkit/Chromium + oude Edge) renderen een eigen ✕ rechts in de
           input; daardoor krijg je samen met onze ge-injecteerde
           orbit-dt-search-clear een dubbele clear-button. Hier weghalen
           zodat onze custom variant de enige is — cross-browser consistent
           en stijlbaar in beide thema's.                                  */
        .dt-container .dt-search input::-webkit-search-cancel-button,
        .dt-container .dt-search input::-webkit-search-decoration,
        .dt-container .dt-search input::-webkit-search-results-button,
        .dt-container .dt-search input::-webkit-search-results-decoration {
            -webkit-appearance: none;
            appearance: none;
            display: none;
        }
        .dt-container .dt-search input::-ms-clear,
        .dt-container .dt-search input::-ms-reveal {
            display: none;
            width: 0;
            height: 0;
        }

        /* ======================================================================
           DataTables — empty-state global styling
           ----------------------------------------------------------------------
           DT 2.x rendert "geen resultaten" als <tr><td class="dt-empty"
           colspan="N">…</td></tr>. De colspan-attr regelt full-width
           spanning op desktop automatisch — we hoeven hier alleen visueel
           te stylen (centering + padding + icon-pseudo).

           NIET `display: block` zetten op desktop: dat haalt de td uit
           table-layout en negeert de colspan-attr, waardoor het lege
           bericht slechts één kolom breed wordt i.p.v. de hele rij.
           De mobile-card override leeft binnen de @media-block hieronder
           (zoek op ".orbit-table-mobile tbody td.dt-empty").
           ====================================================================== */
        td.dt-empty {
            text-align: center !important;
            padding: 2rem 1rem !important;
            color: var(--helios-muted) !important;
            font-size: 0.875rem;
            background: transparent !important;
        }
        td.dt-empty::before {
            content: "";
            display: block;
            width: 32px;
            height: 32px;
            margin: 0 auto 0.75rem;
            background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><circle cx='11' cy='11' r='8'/><path d='m21 21-4.3-4.3'/></svg>");
            background-repeat: no-repeat;
            background-position: center;
            background-size: contain;
            opacity: 0.7;
        }
        html[data-theme="dark"] td.dt-empty::before {
            background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 24 24' fill='none' stroke='%23cbd5e1' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><circle cx='11' cy='11' r='8'/><path d='m21 21-4.3-4.3'/></svg>");
        }
        /* Wanneer de empty-td binnen een orbit-table-mobile tbody zit, hoort
           de ::before-content-rule met `attr(data-label)` niet te matchen
           (geen data-label op empty-row). Maar voor de zekerheid forceren
           we ons icon-pseudo-element ook hier. */
        .orbit-table-mobile tbody td.dt-empty::before {
            content: "" !important;
            background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><circle cx='11' cy='11' r='8'/><path d='m21 21-4.3-4.3'/></svg>");
        }
        html[data-theme="dark"] .orbit-table-mobile tbody td.dt-empty::before {
            background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 24 24' fill='none' stroke='%23cbd5e1' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><circle cx='11' cy='11' r='8'/><path d='m21 21-4.3-4.3'/></svg>");
        }

        /* ======================================================================
           DataTables — loading skeleton (modern alternative for `Processing...`)
           ----------------------------------------------------------------------
           DT 2.x rendert bij `processing: true` een overlay met:
             <div class="dt-processing">
               <div>Processing...</div>        ← :first-child = text
               <div>4 loader-dots</div>        ← :last-child = default spinner
             </div>
           Wij vervangen first-child door een Linear / Vercel-stijl shimmer-bar
           en verbergen de default 4-dot loader. Subtiele backdrop-blur over de
           tabel-area zorgt dat oude content tijdens filter/sort-operaties
           "stil" wordt zonder volledig te verdwijnen.

           CRITICAL — display NIET overrulen.
           DT toggelt visibility via inline-style (display:none → block);
           een !important-override hier zou de overlay permanent aanzetten.
           Wij stylen alleen het visible state.

           CRITICAL — upstream `width: 200px; margin-left: -100px;
           margin-top: -22px; top: 50%; left: 50%;` expliciet overrulen.
           Zonder dat blijft de overlay een 200px-brede linker-anchored
           strip (over-constrained: width + left + right → right genegeerd).

           Activatie: globaal via `processing: true` default in
           orbit-datatables-defaults.js.
           ====================================================================== */
        .dt-container .dt-processing {
            top: 0 !important;
            right: 0 !important;
            bottom: 0 !important;
            left: 0 !important;
            width: auto !important;
            height: auto !important;
            margin: 0 !important;
            z-index: 10;
            background-color: rgba(255, 255, 255, 0.65);
            backdrop-filter: blur(1px);
            -webkit-backdrop-filter: blur(1px);
            pointer-events: none;
            border-radius: var(--orbit-radius, 10px);
        }
        html[data-theme="dark"] .dt-container .dt-processing {
            background-color: rgba(10, 14, 26, 0.65);
        }
        /* Eerste inner-div = text "Processing...". Vervangen door een
           absolute-positioned shimmer-bar in het midden van de overlay. */
        .dt-container .dt-processing > div:first-child {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            color: transparent !important;
            font-size: 0 !important;
            width: min(60%, 240px);
            height: 4px;
            background-color: rgba(0, 0, 0, 0.06);
            border-radius: 999px;
            overflow: hidden;
            margin: 0;
            padding: 0;
        }
        html[data-theme="dark"] .dt-container .dt-processing > div:first-child {
            background-color: rgba(255, 255, 255, 0.08);
        }
        .dt-container .dt-processing > div:first-child::after {
            content: "";
            position: absolute;
            inset: 0;
            background-image: linear-gradient(
                90deg,
                transparent 0%,
                var(--orbit-primary, #254672) 50%,
                transparent 100%
            );
            transform: translateX(-100%);
            animation: orbit-dt-shimmer 1.4s ease-in-out infinite;
        }
        html[data-theme="dark"] .dt-container .dt-processing > div:first-child::after {
            background-image: linear-gradient(
                90deg,
                transparent 0%,
                var(--orbit-chart-primary, #8ab4f8) 50%,
                transparent 100%
            );
        }
        /* DT's default 4-dot loader (last-child div) verbergen — we
           gebruiken de shimmer-bar als enige loading-indicator. */
        .dt-container .dt-processing > div:last-child {
            display: none !important;
        }
        @keyframes orbit-dt-shimmer {
            0%   { transform: translateX(-100%); }
            100% { transform: translateX(100%); }
        }
        /* Respecteer prefers-reduced-motion: pulse i.p.v. lopende bar */
        @media (prefers-reduced-motion: reduce) {
            .dt-container .dt-processing > div:first-child::after {
                animation: orbit-dt-pulse 1.6s ease-in-out infinite;
                transform: none;
            }
            @keyframes orbit-dt-pulse {
                0%, 100% { opacity: 0.3; }
                50%      { opacity: 0.9; }
            }
        }

        .form-control-warning {
            background-color: #fff8e1;
            border: 1px solid var(--bs-warning);
            color: #000;
        }
        .helios-avatar {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            font-weight: 600;
            color: #fff;
            background: var(--helios-avatar-bg, var(--helios-muted));
            border-radius: 10px;
            overflow: hidden;
            flex-shrink: 0;
        }

        .helios-avatar img {
            width: 100%;
            height: 100%;
            object-fit: cover;
        }

        /* Sizes */
        .helios-avatar-sm { width: 32px; height: 32px; font-size: 0.75rem; }
        .helios-avatar-md { width: 48px; height: 48px; font-size: 0.95rem; }
        .helios-avatar-lg { width: 96px; height: 96px; font-size: 1.5rem; }
        .no-first-spacing > :first-child {
            margin-top: 0;
            padding-top: 0;
        }
        .no-last-spacing > :last-child {
            margin-bottom: 0;
            padding-bottom: 0;
        }
        .helios-clickable-rows tbody tr.session-row {
            cursor: pointer;
        }
        .helios-clickable-rows tbody tr.session-row:hover {
            background-color: rgba(0, 0, 0, 0.025);
        }
        .helios-clickable-rows tbody tr.known-ip-row,
        #knownIpsTable tbody tr.known-ip-row {
            cursor: pointer;
        }
        .helios-clickable-rows tbody tr.known-ip-row:hover,
        #knownIpsTable tbody tr.known-ip-row:hover {
            background-color: rgba(0, 0, 0, 0.025);
        }

        /* Globale row-link affordance — werkt samen met helios-row-link.js.
           Toont cursor:pointer op rijen die door de globale handler als
           navigatie-target herkend worden:
           · expliciet: tr[data-href] / tr[data-row-href] (sommige views
             hebben hier al inline style="cursor:pointer", deze regel
             dekt de rest die dat per ongeluk niet heeft).
           · auto-derive: rij waar de eerste <td> een primary <a href>
             bevat (excl. .btn / .dropdown-toggle). Voor de :has()-selector
             kunnen we niet gemakkelijk .btn uitsluiten op het anker zelf,
             dus we matchen de canonical "primary cell" patroon: een <a>
             die geen .btn-modifier heeft. In de praktijk zit zo'n action-
             style anker nooit in de eerste td van een primary list-table.
           Escape-hatch: [data-no-row-link] op de tr blokkeert affordance
           én de JS-handler.                                                */
        .orbit-table-mobile tbody tr[data-href]:not([data-no-row-link]),
        .orbit-table-mobile tbody tr[data-row-href]:not([data-no-row-link]),
        .orbit-table-mobile tbody tr:not([data-no-row-link]):has(> td:first-child a[href]:not(.btn):not(.dropdown-toggle)) {
            cursor: pointer;
        }
        tr.user-separator {
            pointer-events: none;
        }
        #suspiciousSessionsModal tbody tr {
            cursor: pointer;
        }
        #suspiciousSessionsModal tbody tr:hover {
            background-color: rgba(0, 0, 0, 0.03);
        }
        .device-list-item {
            padding: .5rem .75rem;
            border-bottom: 1px solid var(--bs-border-color);
        }
        /* Select2 Placeholder Font */
        .select2-container,
        .select2-container * {
            font-family: 'Public Sans', sans-serif !important;
        }
        /* Default: netjes afgerond */
        .helios-collapsible {
            border-radius: .5rem;
            overflow: hidden;
        }

        /* Als de collapse OPEN is */
        .helios-collapsible
        .card-header
        button[aria-expanded="true"] {
            border-bottom-left-radius: 0;
            border-bottom-right-radius: 0;
        }

        /* Als de collapse DICHT is → card blijft mooi afgerond */
        .helios-collapsible
        .card-header
        button[aria-expanded="false"] {
            border-radius: .5rem;
        }
        /* Basis: geen dubbele randen */
        .helios-collapsible .card-header {
            border-bottom: 0;
        }

        /* Alleen als de collapse OPEN is, weer een scheidingslijn */
        .helios-collapsible .card-header:focus-within {
            border-bottom: 1px solid var(--bs-border-color);
        }
        .visually-hidden {
            position: absolute !important;
            width: 1px !important;
            height: 1px !important;
            padding: 0 !important;
            margin: -1px !important;
            overflow: hidden !important;
            clip: rect(0,0,0,0) !important;
            white-space: nowrap !important;
            border: 0 !important;
        }

        /* Filter dropdown refinements */
        .dropdown-menu .filter-item {
            margin: 0;
        }

        .dropdown-menu .filter-item:hover {
            background-color: rgba(0, 0, 0, 0.025);
        }

        .dropdown-menu .filter-item input:checked ~ .filter-count,
        .dropdown-menu .filter-item input:checked + .form-check-label {
            font-weight: 500;
        }

        .dropdown-menu .filter-item input:checked {
            /* no visual checkbox, but keeps state */
        }

        .dropdown-menu .filter-item input:checked ~ * {
            /* hook for future styling if needed */
        }

        .dropdown-menu .filter-item input:checked {
            /* no-op, state carrier only */
        }

        .dropdown-menu .filter-item input:checked ~ .filter-count {
            color: #000;
        }
        #activeFilters .remove-icon {
            margin-left: .35rem;
        }
        .helios-segmented .btn {
            border-radius: 0 !important;
        }
        .helios-segmented .btn.is-selected {
            background-color: rgba(var(--bs-primary-rgb), .12);
            color: var(--bs-primary);
            border-color: rgba(var(--bs-primary-rgb), .35);
        }
        .helios-segmented.btn-group-vertical .btn:first-of-type {
            border-top-left-radius: 10px !important;
            border-top-right-radius: 10px !important;
        }
        .helios-segmented.btn-group-vertical {
            border-top: 1px solid var(--bs-border-color);
            border-top-left-radius: 10px !important;
            border-top-right-radius: 10px !important;
        }
        .helios-segmented.btn-group-vertical {
            border-top: 1px solid var(--bs-border-color);
            border-top-left-radius: 10px !important;
            border-top-right-radius: 10px !important;
        }
        .helios-segmented .btn.is-selected,
        .helios-segmented label.btn.is-selected {
            background-color: var(--orbit-primary);
            border-color: var(--orbit-primary);
            color: #ffffff;
        }
        .helios-segmented.btn-group-vertical .btn:first-of-type {
            border-top-width: 1px!important;
        }
        .helios-segmented.btn-group-vertical .btn:last-of-type {
            border-bottom-left-radius: 10px !important;
            border-bottom-right-radius: 10px !important;
        }
        .helios-segmented.btn-group:not(.btn-group-vertical) .btn:first-of-type {
            border-top-left-radius: 10px !important;
            border-bottom-left-radius: 10px !important;
        }
        .helios-segmented.btn-group:not(.btn-group-vertical) .btn:last-of-type {
            border-top-right-radius: 10px !important;
            border-bottom-right-radius: 10px !important;
        }

        /* User-menu dropdown (avatar rechtsboven sidebar).
           Design-patroon overgenomen van page-header Beheren-dropdown:
           - Container-padding 0.5rem, radius 12px
           - Items padding 0.75rem, subtle radius 0.375rem, margin 2px
           - Font-size 1rem, line-height 1.4, gap 0.75rem voor icons
           - Divider edge-to-edge via negatieve margin

           Kleur-strategie: user-menu is iets LICHTER dan sidebar +
           NEUTRALER (minder blauw-verzadigd). Voorkomt dat dropdown
           in light mode visueel wegsmelt in sidebar, en in dark mode
           "ingeplakte blauw-vlek" voelt tegen bijna-zwarte sidebar.

           - Light bg: #3d5470 (HSL 213°/30%/34%) — vs sidebar
             #223f67 (HSL 215°/50%/27%): +7 L-punten, -20 S-punten.
             Zelfde hue-familie voor visuele connectie, maar grijzer
             en lichter voor container-pop.
           - Dark bg (dark.css): #2a2f38 (HSL 219°/14%/19%) — vs
             sidebar #0b1220 (HSL 220°/49%/8%): +11 L-punten, -35
             S-punten. Sterk gedesatureerd naar neutraal-grijs met
             subtiele blauw-undertone.
           - Tekst: wit
           - Hover: subtle wit-tint (rgba-wit 0.06) — werkt op beide
             bgs als subtiele lift
           - Active (match current route): blue-soft 20% tint — op
             neutraal-grijs bg duidelijker onderscheiden dan
             voorheen op blue bg, dus beter leesbare cue
           - Divider: wit-12% edge-to-edge */
        #userManageMenu {
            width: 240px;
            /* !important om dark.css `#sidebar .dropdown-menu { bg: helios-
               surface-raised !important }` te overrulen. Dark-mode krijgt
               eigen override in dark.css. */
            background-color: #3d5470 !important;
            border: 1px solid rgba(255, 255, 255, 0.08);
            border-radius: 12px;
            padding: 0.5rem;
            box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
        }
        #userManageMenu .dropdown-item {
            color: rgba(255, 255, 255, 0.92);
            border-radius: 0.375rem;
            padding: 0.75rem;
            margin: 2px 0;
            font-size: 1rem;
            line-height: 1.4;
            display: flex;
            align-items: center;
            gap: 0.75rem;
        }
        #userManageMenu .dropdown-item:hover,
        #userManageMenu .dropdown-item:focus {
            background-color: rgba(255, 255, 255, 0.06);
            color: #ffffff;
        }
        #userManageMenu .dropdown-item.active,
        #userManageMenu .dropdown-item[aria-current="page"] {
            background-color: rgba(var(--x-brand-blue-soft-rgb), 0.20);
            color: #ffffff;
            font-weight: 600;
        }
        #userManageMenu .dropdown-item.active:hover,
        #userManageMenu .dropdown-item[aria-current="page"]:hover {
            background-color: rgba(var(--x-brand-blue-soft-rgb), 0.26);
        }
        #userManageMenu .dropdown-item.text-danger {
            color: rgb(255, 138, 138);
        }
        #userManageMenu .dropdown-item.text-danger:hover,
        #userManageMenu .dropdown-item.text-danger:focus {
            background-color: rgba(var(--bs-danger-rgb), 0.18);
            color: rgb(255, 168, 168);
        }
        #userManageMenu .user-menu-icon {
            width: 18px;
            height: 18px;
            stroke-width: 2;
            opacity: 0.9;
            flex-shrink: 0;
        }
        /* Edge-to-edge divider via negatieve horizontale margin =
           container-padding. Verticale margin voor ritmische
           scheiding tussen actie-groepen. */
        #userManageMenu .dropdown-divider {
            margin: 0.5rem -0.5rem;
            border-top: 1px solid rgba(255, 255, 255, 0.12);
            opacity: 1;
        }
        /* Appearance section (theme-selector): subtle dark-tone label.
           Segmented-buttons behouden hun dark-blue palette (dark.css
           #userManageMenu .helios-segmented rules) omdat container
           zelf dark is in alle modes. */
        #userManageMenu .small.text-muted {
            color: rgba(255, 255, 255, 0.55) !important;
        }
        #userManageMenu .helios-segmented {
            border: 1px solid rgba(255, 255, 255, 0.14);
            border-radius: .375rem;
            overflow: hidden;
        }
        #userManageMenu .helios-segmented .btn {
            /* Transparante rust-state + blauw-tint active, zodat de
               segmented-group dezelfde kleur-taal gebruikt als de
               user-menu items (hover 6% wit, active 20% blue-soft).
               !important op background-color overschrijft Bootstrap's
               .btn-light (--bs-btn-bg: #f8f9fa), die anders als
               "ingeplakt" witte vlak doorschijnt.

               Base-border 0 + right-border-1 op non-last-child = één
               gedeelde divider-lijn tussen knoppen. Geen dubbele lines
               door aangrenzende borders die optellen. Laatste knop
               heeft geen right-border want container zelf heeft die. */
            background-color: transparent !important;
            border: 0 !important;
            border-right: 1px solid rgba(255, 255, 255, 0.14) !important;
            color: rgba(255, 255, 255, 0.85);
            --bs-btn-bg: transparent;
            --bs-btn-hover-bg: transparent;
            --bs-btn-active-bg: transparent;
            --bs-btn-color: rgba(255, 255, 255, 0.85);
            --bs-btn-hover-color: #ffffff;
            --bs-btn-active-color: #ffffff;
            border-radius: 0 !important;
            box-shadow: none !important;
        }
        #userManageMenu .helios-segmented .btn:last-child {
            border-right: 0 !important;
        }
        #userManageMenu .helios-segmented .btn:hover,
        #userManageMenu .helios-segmented .btn:focus-visible {
            background-color: rgba(255, 255, 255, 0.06) !important;
            color: #ffffff;
        }
        #userManageMenu .helios-segmented .btn.is-selected {
            background-color: rgba(var(--x-brand-blue-soft-rgb), 0.20) !important;
            color: #ffffff !important;
            font-weight: 600;
        }
        #userManageMenu .helios-segmented .btn.is-selected:hover {
            background-color: rgba(var(--x-brand-blue-soft-rgb), 0.26) !important;
        }

        html[data-theme="light"] #userManageMenu .helios-segmented .btn,
        html[data-theme="auto"] #userManageMenu .helios-segmented .btn {
            border-radius: 0;
        }

        html[data-theme="light"] #userManageMenu .helios-segmented .btn:first-child,
        html[data-theme="auto"] #userManageMenu .helios-segmented .btn:first-child {
            border-top-left-radius: .375rem;
            border-bottom-left-radius: .375rem;
        }

        html[data-theme="light"] #userManageMenu .helios-segmented .btn:last-child,
        html[data-theme="auto"] #userManageMenu .helios-segmented .btn:last-child {
            border-top-right-radius: .375rem;
            border-bottom-right-radius: .375rem;
        }

        span.small {
            font-size:12px;
        }
        .rounded {
            border-radius:10px;
        }
        /* Cards */
        .card:not(.rounded):not(.rounded-pill) {
            border-radius: var(--orbit-radius);
        }
        .card:not(.rounded):not(.rounded-pill) {
            border-radius: var(--orbit-radius);
        }
        .card:not(.rounded):not(.rounded-pill) .card-header {
            border-top-left-radius: inherit;
            border-top-right-radius: inherit;
        }
        .card:not(.rounded):not(.rounded-pill) .card-footer {
            border-bottom-left-radius: inherit;
            border-bottom-right-radius: inherit;
        }
        .alert:not(.rounded):not(.rounded-pill) {
            border-radius: var(--orbit-radius);
        }
        .btn:not(.rounded):not(.rounded-pill) {
            border-radius: var(--orbit-radius);
        }
        /* Re-apply Bootstrap btn-group corner-stripping after Orbit's .btn radius
           override above. The shorthand `border-radius: var(--orbit-radius)` resets
           all four corners, clobbering Bootstrap's per-corner zeros for middle/edge
           buttons inside a .btn-group. Without this, a 3-button group ends up with
           four rounded buttons instead of the expected round-square-round shape.
           Bootstrap 5's btn-check pattern (radio/checkbox + label) is btn-check-aware
           because the input is :first-child and the LABEL needs the left-radius —
           use `:not(.btn-check:first-child) + .btn` so the label after the first
           hidden input still gets a left-radius, and intermediate labels stay
           stripped. Was a real bug: weekday-pickers and yml/explicit switches
           rendered as all-square instead of round-square-round. */
        .btn-group > :not(.btn-check:first-child) + .btn,
        .btn-group > .btn-group:not(:first-child) {
            border-top-left-radius: 0;
            border-bottom-left-radius: 0;
        }
        .btn-group > .btn:not(:last-child):not(.dropdown-toggle),
        .btn-group > .btn-group:not(:last-child) > .btn {
            border-top-right-radius: 0;
            border-bottom-right-radius: 0;
        }

        /* ----------------------------------------------------------------
           orbit-state-bg utility — gebruik DEZELFDE color-vars als de
           .badge.bg-{state}-subtle overrides hierboven, zodat status-tiles
           (bv. agent diagnostics service-tile, alert-icons) visueel matchen
           met de chips. Bootstrap's vanilla .bg-success-subtle wijkt af
           omdat die uit --bs-success-rgb wordt gemengd en niet de
           Orbit-tuned chip-vars gebruikt.
           ---------------------------------------------------------------- */
        .orbit-state-bg-success {
            background-color: var(--x-status-success-chip-bg);
            color:            var(--x-status-success-chip-ink);
        }
        .orbit-state-bg-warning {
            background-color: var(--x-status-warning-chip-bg);
            color:            var(--x-status-warning-chip-ink);
        }
        .orbit-state-bg-danger {
            background-color: var(--x-status-danger-chip-bg);
            color:            var(--x-status-danger-chip-ink);
        }
        .orbit-state-bg-info {
            background-color: var(--x-status-info-chip-bg, color-mix(in srgb, var(--bs-info) 14%, var(--bs-body-bg)));
            color:            var(--x-status-info-chip-ink, var(--bs-info-text-emphasis));
        }
        .orbit-state-bg-secondary {
            background-color: var(--bs-secondary-bg-subtle);
            color:            var(--bs-secondary-text-emphasis);
        }

        /* helios-day-chips — chip-style multi-select pills voor weekday-pickers
           (auto-update window etc).

           Mobile (<576px): CSS Grid met 7 equal-width kolommen — chips altijd
           naast elkaar, full-row, ~45px breed elk op 320px viewport zodat de
           afkortingen leesbaar blijven.

           Desktop (≥576px): inline flex met content-sized chips — ze nemen
           alleen de breedte van hun label ("Ma"/"Mon") + comfortable padding,
           niet de volle rij-breedte. Anders zien 7 brede chips er logger uit
           dan nodig op desktop. Dark-mode override in dark.css. */
        .helios-day-chips {
            display: grid;
            grid-template-columns: repeat(7, 1fr);
            gap: 0.5rem;
        }
        .helios-day-chips .btn-check + .btn {
            padding-left: 0.25rem;
            padding-right: 0.25rem;
            text-align: center;
            border-color: var(--bs-border-color);
            color: var(--helios-text, var(--bs-body-color));
            background-color: transparent;
            font-weight: 500;
            transition: background-color .12s ease, color .12s ease, border-color .12s ease;
        }
        .helios-day-chips .btn-check + .btn:hover {
            background-color: var(--bs-tertiary-bg);
            border-color: var(--bs-border-color-translucent);
        }
        .helios-day-chips .btn-check:checked + .btn,
        .helios-day-chips .btn-check:active + .btn {
            background-color: var(--bs-primary);
            border-color: var(--bs-primary);
            color: #ffffff;
        }
        .helios-day-chips .btn-check:focus-visible + .btn {
            box-shadow: 0 0 0 0.2rem rgba(var(--bs-primary-rgb), 0.18);
        }
        /* Desktop override — moet NA de default-rules komen zodat cascade
           de bredere padding wint. sm-breakpoint (≥576px) is genoeg ruimte
           om chips content-sized te tonen i.p.v. full-row. Padding bewust
           ruim (~1.25rem h, .45rem v) zodat chips een comfortable tap/click-
           target zijn — WCAG 2.5.5 advies is ~44px. Met btn-sm font-size
           .875rem en line-height 1.5 wordt het ~36-38px hoog × ~52-58px
           breed voor "Ma"/"Mon" — duidelijke klikbare pill. */
        @media (min-width: 576px) {
            .helios-day-chips {
                display: flex;
                flex-wrap: wrap;
            }
            .helios-day-chips .btn-check + .btn {
                padding-top: 0.45rem;
                padding-bottom: 0.45rem;
                padding-left: 1.25rem;
                padding-right: 1.25rem;
            }
        }
        .dropdown-menu:not(.rounded):not(.rounded-pill) {
            border-radius: var(--orbit-radius);
        }
        /* :where() laat de exclude-chain z'n specificity-bijdrage droppen,
           zodat de hele rule slechts (0,1,0) is i.p.v. (0,3,0). Bootstrap's
           eigen `.modal-fullscreen[-X-down] .modal-content { border-radius:0 }`
           is (0,2,0) en wint daardoor automatisch voor àlle fullscreen-
           varianten (sm/md/lg/xl/xxl-down + .modal-fullscreen). Zonder
           :where() bleven hoeken afgerond → page-content schemerde door bij
           fullscreen modals. Geen expliciete per-variant overrides meer
           nodig; dit dekt alle Bootstrap-breakpoints in één regel. */
        .modal-content:where(:not(.rounded):not(.rounded-pill)) {
            border-radius: var(--orbit-radius);
        }
        .form-control-plaintext {
            padding: .375rem .75rem;
            background-color: var(--helios-surface-sunken);
            border: 1px solid var(--helios-surface-selected);
            border-radius: 10px;
            color: #495057;
        }

        /* Slightly dim truly readonly values */
        .form-control-plaintext[readonly] {
            opacity: .9;
        }
        .form-control:not(.rounded):not(.rounded-pill),
        .form-select:not(.rounded):not(.rounded-pill),
        .form-select-sm:not(.rounded):not(.rounded-pill) {
            border-radius: var(--orbit-radius);
        }
        .badge:not(.rounded):not(.rounded-pill) {
            border-radius: calc(var(--orbit-radius) / 1.5);
        }
        .no-focus-ring:focus,
        .no-focus-ring:focus-visible,
        .no-focus-ring:focus:not(:focus-visible) {
            outline: none !important;
            box-shadow: none !important;
        }
        .no-focus-ring {
            -webkit-tap-highlight-color: transparent;
        }
        .dropdown-menu.dropdown-menu-primary {
            background:var(--orbit-primary)!important;
        }
        .dropdown-menu.dropdown-menu-primary li .dropdown-item {
            font-weight:500!important
        }
        .badge {
            display: inline-flex;
            align-items: center;
            line-height: 1;
            vertical-align: middle;
        }
        .timeline {
            position: relative;
            padding-left: 24px;
        }
        .timeline::before {
            content: '';
            position: absolute;
            top: 0;
            bottom: 0;
            left: 8px;
            width: 2px;
            background: rgba(0,0,0,.1);
        }
        .timeline-marker {
            position: relative;
            width: 16px;
            flex-shrink: 0;
        }
          .timeline-dot {
              position: absolute;
              left: -20px;
              top: 10px;
              z-index: 1;
              width: 10px;
              height: 10px;
              background: var(--helios-muted);
              border-radius: 50%;
          }
          .card-body-update ul:last-child,
          .card-body-update p:last-child {
              margin-bottom: 0;
          }
        /* Must beat Bootstrap utility classes like .d-flex { display:flex !important; } */
        .timeline-item.is-hidden {
            display: none !important;
        }
        .card-body.card-body-preview p:last-child,
        .card-body.card-body-preview ul:last-child,
        .card-body.card-body-preview ol:last-child {
            margin-bottom:0
        }
        th[data-sort] {
            cursor: pointer;
            user-select: none;
            position: relative;
            padding-right: 18px;
        }
        th[data-sort]::after {
            content: "⇅";
            font-size: 10px;
            opacity: 0.35;
            position: absolute;
            right: 6px;
            top: 50%;
            transform: translateY(-50%);
        }
        th[data-sort].sort-asc::after {
            content: "▲";
            opacity: 1;
        }
        th[data-sort].sort-desc::after {
            content: "▼";
            opacity: 1;
        }
        .chart-container {
            position: relative;
            height: 180px; /* desktop */
        }
        /* ================================================================
           Alerts — xynta soft-wash recipe (primary 10%/18%, rest 14%/22%).
           All 6 roles uniform: text = body-color, signalering via bg+border.
           Dark-mode overrides (transparent ipv body-bg) live in dark.css.
           ================================================================ */
        .alert-primary {
            background-color: color-mix(in srgb, var(--bs-primary) 10%, var(--bs-body-bg));
            border-color:     color-mix(in srgb, var(--bs-primary) 18%, var(--bs-border-color));
            color:            var(--bs-body-color);
        }
        .alert-secondary {
            background-color: color-mix(in srgb, var(--bs-secondary) 10%, var(--bs-body-bg));
            border-color:     color-mix(in srgb, var(--bs-secondary) 18%, var(--bs-border-color));
            color:            var(--bs-body-color);
        }
        .alert-success {
            background-color: color-mix(in srgb, var(--bs-success) 14%, var(--bs-body-bg));
            border-color:     color-mix(in srgb, var(--bs-success) 22%, var(--bs-border-color));
            color:            var(--bs-body-color);
        }
        .alert-warning {
            /* Gebruikt --x-alert-warning (geel-er) ipv --bs-warning (brand-oranje).
               Alleen alert-context; badges/buttons blijven brand-aligned. */
            background-color: color-mix(in srgb, var(--x-alert-warning) 14%, var(--bs-body-bg));
            border-color:     color-mix(in srgb, var(--x-alert-warning) 22%, var(--bs-border-color));
            color:            var(--bs-body-color);
        }
        .alert-danger {
            background-color: color-mix(in srgb, var(--bs-danger) 14%, var(--bs-body-bg));
            border-color:     color-mix(in srgb, var(--bs-danger) 22%, var(--bs-border-color));
            color:            var(--bs-body-color);
        }
        .alert-info {
            background-color: color-mix(in srgb, var(--bs-info) 14%, var(--bs-body-bg));
            border-color:     color-mix(in srgb, var(--bs-info) 22%, var(--bs-border-color));
            color:            var(--bs-body-color);
        }

        /* ================================================================
           Status badges — chip-token tripel per role (success/warning/
           danger/info). Covers .bg-*, .badge-*, .bg-*-subtle en
           .text-bg-* varianten. !important overrides markup text-color
           (bv. `badge bg-warning text-dark`) — xynta-pattern.
           Primary/secondary badges: geen override (Bootstrap-default).
           ================================================================ */
        .badge.bg-success,
        .badge.badge-success,
        .badge.bg-success-subtle,
        .badge.text-bg-success {
            color:            var(--x-status-success-chip-ink) !important;
            background-color: var(--x-status-success-chip-bg) !important;
            border: 1px solid var(--x-status-success-chip-border) !important;
        }
        .badge.bg-warning,
        .badge.badge-warning,
        .badge.bg-warning-subtle,
        .badge.text-bg-warning {
            color:            var(--x-status-warning-chip-ink) !important;
            background-color: var(--x-status-warning-chip-bg) !important;
            border: 1px solid var(--x-status-warning-chip-border) !important;
        }
        .badge.bg-danger,
        .badge.badge-danger,
        .badge.bg-danger-subtle,
        .badge.text-bg-danger {
            color:            var(--x-status-danger-chip-ink) !important;
            background-color: var(--x-status-danger-chip-bg) !important;
            border: 1px solid var(--x-status-danger-chip-border) !important;
        }
        .badge.bg-info,
        .badge.badge-info,
        .badge.bg-info-subtle,
        .badge.text-bg-info {
            color:            var(--x-status-info-chip-ink) !important;
            background-color: var(--x-status-info-chip-bg) !important;
            border: 1px solid var(--x-status-info-chip-border) !important;
        }
        .drag-zone,
        .drag-handle {
            cursor: grab;
        }
        .drag-zone:active,
        .drag-handle:active {
            cursor: grabbing;
        }
        [data-sortable-item] {
            user-select: none;
        }
        .backend-mode-indicator {
            background-color: rgba(0, 0, 0, 0.2);
            background-image: linear-gradient(
                45deg,
                rgba(0, 0, 0, 0.1) 25%,
                transparent 25%,
                transparent 50%,
                rgba(0, 0, 0, 0.1) 50%,
                rgba(0, 0, 0, 0.1) 75%,
                transparent 75%,
                transparent
            );
            background-size: 1rem 1rem;
            border-top: 1px solid rgba(0, 0, 0, 0.08);
        }
        .component-actions {
            display: flex;
            align-items: center;
            gap: 6px;
            flex-wrap: nowrap;
        }
        .component-count {
            font-family: var(--bs-font-monospace);
        }
        .component-actions .badge {
            font-size: 0.75rem;
            padding: 0.35em 0.55em;
            line-height: 1;
            white-space: nowrap;
        }
        .component-visibility img {
            display: inline-block;
            opacity: .7;
        }
        .component-actions .btn,
        .component-actions .dropdown-toggle {
            padding: 0.25rem 0.45rem;
            font-size: 0.75rem;
            line-height: 1;
        }
        .component-actions img {
            width: 14px;
            height: 14px;
        }
        .component-actions .dropdown-menu {
            font-size: 0.85rem;
        }
        .component-item:last-child {
            margin-bottom: 0 !important;
        }
        .btn {
            font-weight:500
        }
        .btn.btn-info {
            background-color: var(--orbit-info-accent);
            border-color: var(--orbit-info-accent);
            color: #ffffff;
        }
        .btn.btn-info:hover {
            background-color: var(--bs-info);
            border-color: var(--bs-info);
            color: #ffffff;
        }
        .btn-outline-info {
            border: 1px solid var(--orbit-info-accent);
            color: var(--orbit-primary-deep);
            background-color: transparent;
        }
        .btn-outline-info:hover {
            background-color: var(--orbit-info-accent);
            border-color: var(--orbit-info-accent);
            color: #ffffff;
        }
        .border-info {
            border-color: var(--orbit-info-accent) !important;
        }
        .text-info {
            color: var(--bs-info) !important;
        }
        .form-check.form-switch {
            display: flex;
            align-items: center;
            gap: 0.5rem;
        }
        .form-check.form-switch .form-check-input {
            margin-top: 0;
            flex-shrink: 0;
        }
        .form-check.form-switch .form-check-label {
            margin-bottom: 0;
            line-height: 1.4;
        }
        /* Uitlijning van .form-text direct onder een .form-switch.
           Omdat .form-check.form-switch display:flex is (zie boven), kan
           een omschrijving NIET binnen de switch — die komt dan naast
           label op dezelfde rij. Plaats de .form-text als SIBLING en
           deze regel tilt de tekst uit onder het label (toggle 2em +
           gap 0.5rem, met kleine tolerantie voor sub-pixel rendering). */
        .form-check.form-switch + .form-text {
            padding-left: 2.6rem;
        }
        /* Loader spinner – Helios primary */
        .spinner-border.text-primary,
        .spinner-grow.text-primary {
            color: var(--orbit-primary-deep) !important;
        }
        .bg-info-soft {
            background-color: var(--orbit-info-bg-subtle) !important;
        }
        .nav-item .nav-link,
        a {
        color:var(--orbit-primary-deep);
        }
        a:hover {
        color:#162a45;
        }
        .collapse-arrow {
            display: inline-flex;
            align-items: center;
            transition: transform .2s ease;
        }
        .card-header[aria-expanded="true"] .collapse-arrow {
            transform: rotate(180deg);
        }
        .pagination .page-link {
            color: var(--orbit-primary-deep);
            border-color: rgba(26, 49, 80, 0.15);
            background-color: #ffffff;
            font-weight: 500;
            min-width: 34px;
            text-align: center;
        }

        .pagination .page-link:hover {
            color: #ffffff;
            background-color: var(--orbit-primary-deep);
            border-color: var(--orbit-primary-deep);
        }

        .pagination .page-item.active .page-link {
            background-color: var(--orbit-primary-deep);
            border-color: var(--orbit-primary-deep);
            color: #ffffff;
            font-weight: 600;
        }

        .pagination .page-item.disabled .page-link {
            color: rgba(26, 49, 80, 0.4);
            background-color: #f5f6f8;
            border-color: rgba(26, 49, 80, 0.1);
            cursor: default;
        }

        .pagination .page-link:focus {
            box-shadow: none;
        }

        /* Form toggle buttons – Helios style */
        .form-check-input {
            cursor: pointer;
        }

        .form-check-input:checked {
            background-color: var(--orbit-primary-deep);
            border-color: var(--orbit-primary-deep);
        }

        .form-check-input:focus {
            box-shadow: none;
            border-color: rgba(26, 49, 80, 0.4);
        }

        /* Switch specific */
        .form-switch .form-check-input {
            width: 2.25em;
            height: 1.25em;
        }

        .form-switch .form-check-input:checked {
            background-color: var(--orbit-primary-deep);
        }

        .form-switch .form-check-input:checked::before {
            background-color: #ffffff;
        }

        /* Button toggle groups (btn-check) */
        .btn-check:checked + .btn.btn-secondary,
        .btn-check:checked + .btn.btn-primary {
            background-color: var(--orbit-primary-deep);
            border-color: var(--orbit-primary-deep);
            color: #ffffff;
        }
        .bg-primary {
            background-color: var(--orbit-primary) !important;
            color: #fff;
            --bs-badge-bg: var(--orbit-primary);
            --bs-badge-color: #fff;
        }
        .btn-check:focus + .btn,
        .btn-check:hover + .btn {
            box-shadow: none;
        }
        label.btn-outline-tertiary.is-selected {
            background-color: var(--orbit-primary);
            border-color: var(--orbit-primary);
            color: #ffffff;
        }
        label.btn-outline-tertiary.is-selected {
            background-color: var(--bs-tertiary-bg);
            color: var(--bs-tertiary-color);
            border-color: var(--bs-tertiary-border-subtle);
        }
        label.btn.is-selected:focus,
        label.btn.is-selected:focus-visible,
        label.btn.is-selected:hover {
            background-color: inherit;
            color: inherit;
        }
        .btn-outline-secondary.btn-toggle {
            color: var(--orbit-primary-deep);
            border-color: rgba(26, 49, 80, 0.25);
        }
        .btn-outline-secondary.btn-toggle:hover {
            background-color: var(--orbit-primary-deep);
            color: #ffffff;
        }
        #serverDropdown.btn-outline-secondary {
            background-color: #ffffff;
            color: var(--orbit-primary-deep);
        }
        #serverDropdown.btn-outline-secondary:hover,
        #serverDropdown.btn-outline-secondary:focus {
            background-color: #f8f9fb;
            color: var(--orbit-primary-deep);
            border-color: rgba(26, 49, 80, 0.25);
            box-shadow: none;
        }
        #serverDropdown.btn-outline-secondary.show,
        #serverDropdown.btn-outline-secondary:active {
            background-color: #ffffff;
            color: var(--orbit-primary-deep);
            border-color: rgba(26, 49, 80, 0.35);
            box-shadow: none;
        }
        .badge .lock-icon {
            height: 10px;
            width: auto;
            display: block;
        }
        .remove-icon {
            width: 16px;
            height: 16px;
            transition: filter 0.15s ease-in-out;
        }
        .btn-outline-primary:hover .invert-icon,
        .btn-outline-secondary:hover .invert-icon {
            filter: invert(1);
        }
        .btn-outline-danger:hover .remove-icon {
            filter: brightness(0) invert(1);
        }
        .agent-alt-card {
            opacity: 0.3;
            transition: opacity 0.2s ease-in-out;
        }
        .agent-alt-card:hover {
            opacity: 1;
        }
        .card .card-header {
            padding-top:10px;
            padding-bottom:10px
        }
        .card .card-header p.fw-semibold,
        .nav.nav-pills .nav-link {
            font-size:16px
        }
        /* Prevent tab titles from wrapping to multiple lines (centered text) */
        .nav.nav-pills .nav-link {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 4px;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }

        /* Ensure tab title truncates while badge remains visible */
        .nav.nav-pills .nav-link > span:first-of-type {
            overflow: hidden;
            text-overflow: ellipsis;
        }
       .chart-container {
            height: 300px;
        }
        .card.card-login {
            border-radius:10px
        }
        .nav.nav-pills .nav-link.active {
            background:var(--orbit-primary);
        }
        /* Tab count badges – subtle Helios style.
           !important nodig om Bootstrap's `.bg-*` utility-overrides te
           neutraliseren. Eén regel dekt alle bg-varianten af zodat
           templates `bg-primary`, `bg-secondary`, `bg-info`, etc.
           kunnen gebruiken zonder visuele inconsistentie. */
        .nav.nav-pills .nav-link .badge {
            margin-left: 6px;
            font-size: 11px;
            font-weight: 600;
            padding: 3px 7px;
            border-radius: 999px;
            line-height: 1;
            background-color: rgba(26, 49, 80, 0.08) !important;
            color: rgba(26, 49, 80, 0.75) !important;
        }

        /* Active tab count badge – iets prominenter tegen donkere pill */
        .nav.nav-pills .nav-link.active .badge {
            background-color: rgba(255, 255, 255, 0.55) !important;
            color: rgba(26, 49, 80, 0.9) !important;
        }

        /* Dark backgrounds (safety for reused pills) */
        .nav.nav-pills.bg-dark .nav-link .badge,
        .nav.nav-pills.bg-tertiary .nav-link .badge {
            background-color: rgba(255, 255, 255, 0.25) !important;
            color: #ffffff !important;
        }
        .table tr.table-dark th {
            background:var(--orbit-primary-deep)
        }
        .status-field.is-invalid .invalid-feedback {
            display: block;
        }
        .btn-outline-primary {
            border:1px solid var(--orbit-primary)!important;
            color:var(--orbit-primary);
        }
        .btn-outline-primary:hover {
            border:1px solid var(--orbit-primary)!important;
            background:var(--orbit-primary);
            color:#fff
        }
        .btn-outline-primary {
            border:1px solid var(--orbit-primary)!important;
            color:#8e8e8e;
        }
        .btn-outline-primary:hover {
            border:1px solid var(--orbit-primary)!important;
            background:var(--orbit-primary);
            color:#fff
        }
        .btn-check:checked + .btn-outline-primary {
            --bs-btn-active-bg: var(--orbit-primary);
            --bs-btn-active-border-color: var(--orbit-primary);
            --bs-btn-active-color: #ffffff;
        }
        .btn.btn-link {
            color:var(--orbit-primary)
        }
        .btn.btn-primary {
            background:var(--orbit-primary);
            border:1px solid var(--orbit-primary);
        }
        .card .card-header.bg-primary {
            background-color: var(--orbit-primary)!important;
            color: #ffffff!important;
            border-bottom: 1px solid rgba(0, 0, 0, 0.08)!important;
        }
        .text-success {
            color:var(--bs-success)!important;
        }
        /* .alert-success override removed — vervangen door xynta soft-wash
           recipe hierboven (search: "Alerts — xynta soft-wash recipe").
           .badge.bg-success verwijderd uit onderstaande grouped selector —
           vervangen door chip-token recipe (search: "Status badges"). */
        .progress-bar.bg-success,
        .btn.btn-success {
            background:var(--bs-success)!important;
        }
        .btn.btn-success:hover {
            background:#88AB57!important;
        }
        .toast.text-bg-success {
            background-color: var(--bs-success) !important;
            color: #ffffff;
        }
        .toast.text-bg-success .btn-close {
            filter: invert(1);
        }
        /* Info-toast: helios-blauw + witte tekst in light mode; dark-mode
           rebindt --helios-info-accent naar #8ab2d2 (lichtere variant) en
           dark.css zet de tekstkleur op zwart — zie alert-info pattern. */
        .toast.text-bg-info {
            background-color: var(--helios-info-accent) !important;
            color: #ffffff !important;
        }
        .toast.text-bg-info .btn-close {
            filter: invert(1);
        }
        /* Top-positioned toast-containers (zoals .helios-toast-container uit
           helios-toast.js) moeten op mobile (<xxl) onder #mobileHeader (64px,
           d-xxl-none) uitschuiven, anders verdwijnen ze achter de balk.
           Sibling-combinator scopet de regel tot pagina's waar de mobile
           header daadwerkelijk gerenderd is (logged-in pages — zie
           tpl/header.php #mobileHeader). */
        @media (max-width: 1399.98px) {
            #mobileHeader ~ .toast-container.top-0 {
                top: 64px !important;
            }
        }
        .dropdown-menu .dropdown-item.active,
        .dropdown-menu .dropdown-item:active {
            background-color: rgba(26, 49, 80, 0.12); /* subtiele Helios-blauw tint */
            color: var(--orbit-primary-deep);
            font-weight: 600;
        }
        .dropdown-menu .dropdown-item.active:hover {
            background-color: rgba(26, 49, 80, 0.18);
            color: var(--orbit-primary-deep);
        }
        .btn.btn-success {
            border:1px solid var(--bs-success);
        }
        .border-success {
            border-color:var(--bs-success)!important;
        }
        .border-primary {
            border-color:var(--orbit-primary)!important;
        }
        h1, h2, h3, h4, h5, h6 {
        word-break: break-word;
        overflow-wrap: break-word;
        }

        table td,
        table th {
        white-space: nowrap;
        }

        /* DataTables sort icons: Bootstrap Icons chevrons via SVG (font file not available) */
        table.dataTable thead > tr > th span.dt-column-order::before,
        table.dataTable thead > tr > td span.dt-column-order::before {
            content: "" !important;
            background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' viewBox='0 0 16 16'%3E%3Cpath d='M7.646 4.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1-.708.708L8 5.707l-5.646 5.647a.5.5 0 0 1-.708-.708z'/%3E%3C/svg%3E");
            background-size: contain;
            background-repeat: no-repeat;
            background-position: center;
            width: 10px;
            height: 10px;
            opacity: 0.55;
        }

        table.dataTable thead > tr > th span.dt-column-order::after,
        table.dataTable thead > tr > td span.dt-column-order::after {
            content: "" !important;
            background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' viewBox='0 0 16 16'%3E%3Cpath d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3E%3C/svg%3E");
            background-size: contain;
            background-repeat: no-repeat;
            background-position: center;
            width: 10px;
            height: 10px;
            opacity: 0.55;
        }

        table.dataTable thead > tr > th.dt-ordering-asc span.dt-column-order::before,
        table.dataTable thead > tr > td.dt-ordering-asc span.dt-column-order::before,
        table.dataTable thead > tr > th.dt-ordering-desc span.dt-column-order::after,
        table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order::after {
            opacity: 1;
        }

        /* Rounded corners on bordered tables. Bootstrap's .rounded utility
           doesn't visually apply to tables with default border-collapse:
           collapse because inner-cell borders paint over outer corners.
           Fix: switch to border-collapse: separate, hide overflow on the
           table, and apply corner-specific radii to outermost cells.
           Works for tables with or without <thead> by targeting both th
           and td on first/last rows. */
        /* Stat-card tinted footer for Δ-indicator / trend context.
           Distinct from Bootstrap's .card-footer (which dark.css already styles
           as a sunken neutral block). Use as a sibling to .card-body inside
           a stat-card. Each semantic variant pairs with the matching card-color
           per design-system.md §7b. Light-mode uses Bootstrap's *-text-emphasis
           vars for guaranteed contrast on the soft tint. Dark-mode overrides
           live in dark.css. */
        /* .stat-card-footer + .stat-card-info-icon verwijderd — vervangen
           door .counter-card-footer + .counter-card-tooltip uit de
           tpl/counter-cards.php partial (advanced variant, deel 2b).
           shortener/index.php was enige view die de oude selectors
           gebruikte; die is gemigreerd naar de partial. */

        /* Consistent spacing between an icon and text inside a .badge.
           Single-space-character separator is unreliable across font/zoom
           combinations; this rule guarantees the gap. Affects every badge
           in Orbit. */
        .badge > .bi:first-child,
        .badge > i.bi:first-child {
            margin-right: 0.3em;
        }
        .badge > .bi:last-child:not(:first-child),
        .badge > i.bi:last-child:not(:first-child) {
            margin-right: 0;
            margin-left: 0.3em;
        }

        /* ============================================================
           Cycle E redesign — Page-header architectuur-reset
           ============================================================
           Platte layout zonder card-wrapper. Breadcrumb boven, title +
           icon-badge links, actions rechts (desktop) of onderin (mobile).
           Dotted divider onder het geheel. Acties zijn `.page-header-btn`
           componenten; mobile Beheren-menu gebruikt Bootstrap Offcanvas
           (bottom). 100% Lucide icons. */

        /* Spacing-hiërarchie (foundation-iteratie — sectie-feel):
           De header ademt onder (margin-bottom op wrapper + margin-top
           op divider) zodat hij als eigen sectie leest, niet als prefix
           van content. Interne gaps zijn ritmisch: breadcrumb→title
           tight (ze horen bij elkaar als "page-label"), title→intro
           nog tighter (intro is continuation van title), intro→divider
           generous (signaal sectie-einde). Mobile gebruikt dezelfde
           ritmiek gecompressed.

           Top-padding is 0: de view-container wrap (`.container-fluid
           py-4`) levert al 1.5rem padding-top, wat gelijk is aan de
           horizontal padding `px-md-4` (1.5rem) op desktop. Zo zijn
           top-offset en side-offset symmetrisch zonder dat we de
           container hoeven aan te raken. Op mobiel blijft de
           container's `py-4` 1.5rem dominant; een strikte mobile-
           symmetry met `px-3` (1rem) of `px-2` (0.5rem) zou container-
           padding requires, buiten scope van deze iteratie. */
        .page-header {
            padding-top: 0;
            padding-bottom: 0;
            margin-bottom: 2rem;
        }
        .page-header-breadcrumb {
            margin-bottom: 0.75rem;
        }
        .page-header-breadcrumb .breadcrumb {
            font-size: 0.75rem;
            letter-spacing: 0.04em;
            text-transform: uppercase;
            margin: 0;
            color: var(--bs-secondary-color);
        }
        .page-header-breadcrumb .breadcrumb-item,
        .page-header-breadcrumb .breadcrumb-item.active {
            color: var(--bs-secondary-color);
        }
        .page-header-breadcrumb .breadcrumb a {
            color: var(--bs-secondary-color);
            text-decoration: none;
            opacity: 0.85;
        }
        .page-header-breadcrumb .breadcrumb a:hover {
            opacity: 1;
            color: var(--bs-body-color);
        }
        /* Collapse-button binnen mobile-breadcrumb (zie page-header.php).
           Rendert als pure inline-tekst — zelfde behandeling als de
           reguliere breadcrumb-links (`.page-header-breadcrumb .breadcrumb
           a`) — zodat de spacing voor/na de "…" gelijk is aan de spacing
           tussen tekst-items. Geen chip-stijl, geen extra padding, geen
           min-width. */
        .page-header-breadcrumb-collapse {
            background: transparent;
            border: 0;
            padding: 0;
            margin: 0;
            color: var(--bs-secondary-color);
            opacity: 0.85;
            font: inherit;
            line-height: inherit;
            cursor: pointer;
        }
        .page-header-breadcrumb-collapse:hover,
        .page-header-breadcrumb-collapse:focus-visible,
        .page-header-breadcrumb-collapse[aria-expanded="true"] {
            color: var(--bs-body-color);
            opacity: 1;
            outline: none;
        }
        .page-header-breadcrumb-collapse-item .dropdown-menu {
            /* Dropdown-items zelf gebruiken default Bootstrap-typografie —
               niet de caps/0.75rem van het breadcrumb-pad zelf. */
            font-size: 0.875rem;
            text-transform: none;
            letter-spacing: 0;
            min-width: 12rem;
        }

        .page-header-row {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 1rem;
            flex-wrap: wrap;
            /* Uniform hoogte: title-row heeft altijd minstens button-
               hoogte, ongeacht of er actions staan. Zonder deze
               min-height zou de row collapsen naar title-height op
               views zonder actions → title-baseline schuift omhoog,
               breadcrumb-naar-title spacing oogt inconsistent
               vergeleken met views waar row button-hoog is. */
            min-height: 2.75rem;
        }
        .page-header-title-block {
            /* Column-stacking voor title + optioneel intro als child.
               Vóór de intro-verhuizing (sibling van .page-header-row) was
               dit een row-flex met centered icon-badge — die is cycle E
               verwijderd, dus één child was default. Na intro-verhuizing
               stapelt title + intro verticaal in de linker flex-kolom. */
            display: flex;
            flex-direction: column;
            align-items: flex-start;
            min-width: 0;
            flex: 1 1 auto;
        }
        .page-header-title {
            font-size: 2.25rem;
            font-weight: 600;
            letter-spacing: -0.015em;
            line-height: 1.15;
            color: var(--bs-body-color);
            margin: 0;
            min-width: 0;
            word-break: break-word;
        }
        .page-header-intro {
            margin: 0.5rem 0 0;
            font-size: 0.9375rem;
            color: var(--bs-secondary-color);
            max-width: 72ch;
        }
        .page-header-divider {
            margin: 1.5rem 0 0;
            border: 0;
            border-top: 1px dotted var(--bs-border-color);
            opacity: 1;
            height: 0;
        }

        /* Inline section-break voor close-container → <hr> → open-container
           patroon (zie design-system.md §"Tab structure for related data
           tables"). Dotted-stijl matcht .page-header-divider en
           categoriseert dit als inline divider (gebonden aan sidebar /
           content-area), in tegenstelling tot solid dividers die voor
           true full-width separators zijn gereserveerd.
           1px dotted matcht .page-header-divider qua dikte; --bs-secondary-
           color ipv --bs-border-color geeft net iets meer contrast — genoeg
           om als section-break leesbaar te zijn zonder te dominant te
           worden. */
        .helios-section-divider {
            margin: 1.5rem 0;
            border: 0;
            border-top: 1px dotted var(--bs-secondary-color);
            opacity: 1;
            height: 0;
        }

        /* Compact-modifier voor page-header wanneer de view direct na de
           header een section-divider plaatst (config: 'divider' => false).
           Reduceert margin-bottom van 2rem → 1rem zodat de above/below
           spacing rond de section-divider symmetrisch leest (= ~2.5rem
           gecombineerd met container-pt-4 zonder pb). */
        .page-header--no-divider {
            margin-bottom: 1rem;
        }

        /* ---- Actions-row ---- */
        .page-header-actions {
            display: flex;
            gap: 0.5rem;
            align-items: center;
            flex-shrink: 0;
            flex-wrap: wrap;
        }

        /* ---- Button component ---- */
        .page-header-btn {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            gap: 0.4rem;
            min-height: 2.75rem;
            padding: 0.5rem 0.9rem;
            font-size: 0.9375rem;
            font-weight: 600;
            line-height: 1.3;
            border-radius: 8px;
            border: 1px solid transparent;
            background-color: transparent;
            color: var(--bs-body-color);
            text-decoration: none;
            cursor: pointer;
            transition: transform 0.1s ease,
                        box-shadow 0.15s ease,
                        background-color 0.15s ease,
                        border-color 0.15s ease;
            white-space: nowrap;
        }
        .page-header-btn svg,
        .page-header-btn i {
            width: 16px;
            height: 16px;
            stroke-width: 2;
            flex: 0 0 auto;
        }
        .page-header-btn:focus-visible {
            outline: 2px solid rgba(var(--x-brand-blue-rgb), 0.50);
            outline-offset: 2px;
        }
        .page-header-btn:active {
            transform: translateY(1px);
        }
        /* Dropdown-toggle: caret-less (cleaner with Lucide chevron-icon in label) */
        .page-header-btn.dropdown-toggle::after {
            display: none;
        }

        /* Back modifier — icon-only, neutraal tint */
        .page-header-btn-back {
            min-width: 2.75rem;
            padding: 0.5rem 0.75rem;
            background-color: rgba(var(--x-brand-blue-deep-rgb), 0.04);
            color: var(--x-brand-blue-deep);
            border-color: rgba(var(--x-brand-blue-deep-rgb), 0.14);
            box-shadow: 0 1px 2px rgba(var(--x-brand-blue-deep-rgb), 0.04);
        }
        /* :focus-visible blijft buiten @media (hover) zodat keyboard-nav
           op touch-devices (iPad-keyboard, externe BT-toetsenborden) de
           lift-state nog steeds krijgt. :hover wordt achter `@media
           (hover: hover)` gezet om sticky-hover op iOS Safari te voorkomen
           — anders blijft de lift-state hangen ná een tap totdat de user
           elders tapt. */
        .page-header-btn-back:focus-visible {
            background-color: rgba(var(--x-brand-blue-deep-rgb), 0.10);
            color: var(--x-brand-blue-deep);
            border-color: rgba(var(--x-brand-blue-deep-rgb), 0.22);
            transform: translateY(-1px);
            box-shadow: 0 3px 8px rgba(var(--x-brand-blue-deep-rgb), 0.10);
        }
        @media (hover: hover) {
            .page-header-btn-back:hover {
                background-color: rgba(var(--x-brand-blue-deep-rgb), 0.10);
                color: var(--x-brand-blue-deep);
                border-color: rgba(var(--x-brand-blue-deep-rgb), 0.22);
                transform: translateY(-1px);
                box-shadow: 0 3px 8px rgba(var(--x-brand-blue-deep-rgb), 0.10);
            }
        }

        /* Primary modifier — accent-oranje, prominent */
        .page-header-btn-primary {
            background-color: var(--orbit-accent);
            color: var(--orbit-on-accent);
            border-color: var(--orbit-accent);
            border-bottom: 2px solid var(--orbit-accent-deep);
            box-shadow: 0 2px 6px rgba(var(--x-brand-orange-rgb), 0.25);
        }
        .page-header-btn-primary:focus-visible {
            background-color: var(--orbit-accent-hover);
            color: var(--orbit-on-accent);
            border-color: var(--orbit-accent-hover);
            border-bottom-color: var(--orbit-accent-deep);
            transform: translateY(-1px);
            box-shadow: 0 4px 10px rgba(var(--x-brand-orange-rgb), 0.35);
        }
        @media (hover: hover) {
            .page-header-btn-primary:hover {
                background-color: var(--orbit-accent-hover);
                color: var(--orbit-on-accent);
                border-color: var(--orbit-accent-hover);
                border-bottom-color: var(--orbit-accent-deep);
                transform: translateY(-1px);
                box-shadow: 0 4px 10px rgba(var(--x-brand-orange-rgb), 0.35);
            }
        }
        .page-header-btn-primary:active {
            background-color: var(--orbit-accent-deep);
            border-color: var(--orbit-accent-deep);
            border-bottom-width: 1px;
            color: var(--orbit-on-accent);
            transform: translateY(1px);
            box-shadow: 0 1px 3px rgba(var(--x-brand-orange-rgb), 0.20);
        }

        /* Secondary modifier — licht blauw-tint */
        .page-header-btn-secondary {
            background-color: rgba(var(--x-brand-blue-rgb), 0.06);
            color: var(--x-brand-blue-deep);
            border-color: rgba(var(--x-brand-blue-deep-rgb), 0.18);
            box-shadow: 0 1px 2px rgba(var(--x-brand-blue-deep-rgb), 0.04);
        }
        .page-header-btn-secondary:focus-visible {
            background-color: rgba(var(--x-brand-blue-rgb), 0.10);
            color: var(--x-brand-blue-deep);
            border-color: rgba(var(--x-brand-blue-deep-rgb), 0.28);
            transform: translateY(-1px);
            box-shadow: 0 3px 8px rgba(var(--x-brand-blue-deep-rgb), 0.10);
        }
        @media (hover: hover) {
            .page-header-btn-secondary:hover {
                background-color: rgba(var(--x-brand-blue-rgb), 0.10);
                color: var(--x-brand-blue-deep);
                border-color: rgba(var(--x-brand-blue-deep-rgb), 0.28);
                transform: translateY(-1px);
                box-shadow: 0 3px 8px rgba(var(--x-brand-blue-deep-rgb), 0.10);
            }
        }

        /* ---- Desktop dropdown-menu (Bootstrap, Popper-positioned) */
        /* Container: eigen radius, padding rondom items zodat items
           tile-achtig in container "drijven" met subtle gap. */
        .page-header-actions .dropdown-menu {
            --bs-dropdown-bg: #ffffff;
            border: 1px solid var(--bs-border-color);
            border-radius: 12px;
            padding: 0.5rem;
            box-shadow: 0 8px 24px rgba(var(--x-brand-blue-deep-rgb), 0.14);
            min-width: 240px;
        }
        /* Items: body-font-size (1rem), ruimere padding, subtiele radius
           (tile-look), icon-label gap 0.75rem voor Lucide stroke-icons. */
        .page-header-actions .dropdown-menu .dropdown-item {
            border-radius: 0.375rem;
            padding: 0.75rem;
            margin: 2px 0;
            font-size: 1rem;
            line-height: 1.4;
            display: flex;
            align-items: center;
            gap: 0.75rem;
        }
        .page-header-actions .dropdown-menu .dropdown-item svg,
        .page-header-actions .dropdown-menu .dropdown-item i {
            width: 18px;
            height: 18px;
            stroke-width: 2;
            flex: 0 0 auto;
        }
        /* Divider: edge-to-edge door container-padding via negatieve
           horizontale margin. Verticale margin behouden voor ritmische
           scheiding tussen actie-groepen. */
        .page-header-actions .dropdown-menu .dropdown-divider {
            margin: 0.5rem -0.5rem;
            border-top: 1px solid var(--bs-border-color);
            opacity: 1;
        }
        /* Danger-items: zelfde radius + body als regular items; alleen
           bg + text-color wijken af. */
        .page-header-actions .dropdown-menu li.bg-danger {
            background-color: rgba(var(--bs-danger-rgb), 0.9) !important;
            border-radius: 0.375rem;
            margin: 2px 0;
        }
        .page-header-actions .dropdown-menu li.bg-danger .dropdown-item {
            color: #ffffff;
            background-color: transparent;
        }
        .page-header-actions .dropdown-menu li.bg-danger .dropdown-item:hover {
            background-color: rgba(0, 0, 0, 0.15);
            color: #ffffff;
        }

        /* ---- Mobile offcanvas-bottom (Beheren menu)
           Sticky mini-header met drag-handle + close-X. Sluit via X-knop,
           grip-pill tap, swipe-down (helios-offcanvas-swipe.js — opt-in via
           data-orbit-swipe-close) of buiten-tap. Z-index 1250 staat boven
           #mobileHeader (z-1200) zodat de offcanvas niet onder de mobile-nav
           duikt; backdrop-boost is geconsolideerd onderaan deze block. */
        .page-header-offcanvas {
            z-index: 1250;
            height: auto !important;
            /* Cap onder de mobile-header (64px) zodat de top altijd vrij
               blijft. dvh handelt mobile-browser chrome (Safari address bar);
               vh-fallback voor oudere engines. */
            max-height: calc(100vh - 64px - 1rem);
            max-height: calc(100dvh - 64px - 1rem);
            border-top-left-radius: 1rem;
            border-top-right-radius: 1rem;
            border-top: 1px solid var(--bs-border-color);
            background-color: #ffffff;
            display: flex;
            flex-direction: column;
        }
        /* Sticky grip-bar: drag-handle pill (visuele swipe-affordance,
           iOS/Material conventie) gecentreerd, close-X rechts. Compact
           (44px) zodat de sheet niet onnodig hoog wordt bij weinig items. */
        .page-header-offcanvas-grip {
            position: relative;
            flex: 0 0 auto;
            display: flex;
            align-items: center;
            justify-content: center;
            min-height: 2.75rem;
            padding: 0.5rem 0.75rem;
            border-top-left-radius: 1rem;
            border-top-right-radius: 1rem;
            background-color: inherit;
        }
        .page-header-offcanvas-grip-pill {
            display: block;
            width: 2.5rem;
            height: 0.25rem;
            border-radius: 999px;
            background-color: var(--bs-border-color);
            opacity: 0.9;
        }
        .page-header-offcanvas-close {
            position: absolute;
            top: 50%;
            right: 0.75rem;
            transform: translateY(-50%);
            padding: 0.5rem;
            opacity: 0.65;
        }
        .page-header-offcanvas-close:hover,
        .page-header-offcanvas-close:focus-visible {
            opacity: 1;
        }
        /* Body-padding 0.5rem matcht dropdown — items tile-achtig
           binnen container. Divider breekt uit via negatieve margin.
           flex:1 + overflow zorgt dat alleen de body scrolt, niet de grip.
           overscroll-behavior:contain voorkomt dat een swipe-down door de
           menu-content de page erachter scrollt. */
        .page-header-offcanvas .offcanvas-body {
            flex: 1 1 auto;
            padding: 0.5rem;
            padding-bottom: calc(0.5rem + env(safe-area-inset-bottom, 0px));
            overflow-y: auto;
            -webkit-overflow-scrolling: touch;
            overscroll-behavior: contain;
        }
        .page-header-offcanvas-list {
            list-style: none;
            margin: 0;
            padding: 0;
        }
        .page-header-offcanvas-list > li {
            margin: 0;
        }
        /* Items: body-font-size (1rem), subtiele radius voor tile-look,
           ruime padding voor comfortabele tap-targets op mobile. */
        .page-header-offcanvas-item {
            display: flex;
            align-items: center;
            gap: 0.75rem;
            width: 100%;
            padding: 0.875rem 0.75rem;
            margin: 2px 0;
            min-height: 3rem;
            color: var(--bs-body-color);
            background-color: transparent;
            border: 0;
            border-radius: 0.375rem;
            text-align: left;
            text-decoration: none;
            font-size: 1rem;
            font-weight: 500;
            line-height: 1.4;
            cursor: pointer;
            transition: background-color 0.12s ease;
        }
        .page-header-offcanvas-item:hover,
        .page-header-offcanvas-item:focus-visible {
            background-color: rgba(var(--x-brand-blue-rgb), 0.08);
            color: var(--x-brand-blue-deep);
            outline: none;
        }
        .page-header-offcanvas-item svg,
        .page-header-offcanvas-item i {
            width: 18px;
            height: 18px;
            stroke-width: 2;
            flex: 0 0 auto;
        }
        .page-header-offcanvas-item.is-danger {
            color: var(--bs-danger);
        }
        .page-header-offcanvas-item.is-danger:hover,
        .page-header-offcanvas-item.is-danger:focus-visible {
            background-color: rgba(var(--bs-danger-rgb), 0.10);
            color: var(--bs-danger);
        }
        /* Disabled state — gebruikt door helios-row-actions-mobile.js
           wanneer de bron-action `disabled` of `.disabled` is. */
        .page-header-offcanvas-item.is-disabled {
            opacity: 0.5;
            pointer-events: none;
        }
        /* Divider edge-to-edge via negatieve horizontale margin =
           container-padding. */
        .page-header-offcanvas-divider {
            border: 0;
            border-top: 1px solid var(--bs-border-color);
            margin: 0.5rem -0.5rem;
        }
        /* Section label: horizontaal-align met items (0.75rem padding
           + container's 0.5rem = 1.25rem van offcanvas-rand). */
        .page-header-offcanvas-section {
            padding: 0.75rem 0.75rem 0.25rem;
            font-size: 0.75rem;
            letter-spacing: 0.06em;
            text-transform: uppercase;
            color: var(--bs-secondary-color);
            font-weight: 600;
        }

        /* Backdrop boven mobile-header (z-1200) zolang een swipeable
           bottom-sheet open is — bottom-sheet conventie waarbij open
           context-menu de hele UI dimt inclusief de nav. Generic selector
           dekt page-header- én row-actions-offcanvas (en elk toekomstig
           bottom-sheet met opt-in attribuut). `:has()` is veilig in de
           May 2026 baseline. */
        body:has(.offcanvas-bottom[data-orbit-swipe-close].show) .offcanvas-backdrop,
        body:has(.offcanvas-bottom[data-orbit-swipe-close].showing) .offcanvas-backdrop {
            z-index: 1245;
        }

        /* ---- Row-actions offcanvas (globale tabel-Beheren menu op mobiel)
           Hergebruikt `.page-header-offcanvas-*` klassen volledig — zelfde
           grip-bar, items, dividers, sections, dark-mode. `.orbit-row-actions-
           offcanvas` blijft alléén als JS/DevTools-marker; geen eigen visuele
           rules meer. Implementatie: helios-row-actions-mobile.js (intercept
           op <md, builds DOM met page-header-offcanvas-* classes). */

        /* ---- Filter-offcanvas: multi-toggle variant van het page-header-
           offcanvas-item. Item-tap togglet bron-checkbox; offcanvas blijft
           open. `.is-filter` voegt een leading checkbox-indicator toe en
           een trailing meta-count. `.is-active` markeert de aangevinkte
           state (mirror van iOS/Material multi-select bottom-sheets).
           Implementatie: helios-filter-mobile.js. */
        .page-header-offcanvas-item.is-filter {
            gap: 0.875rem;
        }
        .page-header-offcanvas-item-check {
            flex: 0 0 auto;
            width: 1.25rem;
            height: 1.25rem;
            border: 1.5px solid var(--bs-border-color);
            border-radius: 0.25rem;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            background-color: transparent;
            transition: background-color 0.12s ease, border-color 0.12s ease;
        }
        /* Override default page-header-offcanvas-item svg sizing (18px) —
           check-icon is kleiner zodat hij in de 1.25rem indicator past. */
        .page-header-offcanvas-item.is-filter .page-header-offcanvas-item-check svg,
        .page-header-offcanvas-item.is-filter .page-header-offcanvas-item-check i {
            width: 14px;
            height: 14px;
            stroke-width: 2.75;
            color: #ffffff;
            opacity: 0;
            transition: opacity 0.12s ease;
        }
        .page-header-offcanvas-item.is-filter.is-active .page-header-offcanvas-item-check {
            background-color: var(--x-brand-blue-deep, #0d6efd);
            border-color: var(--x-brand-blue-deep, #0d6efd);
        }
        .page-header-offcanvas-item.is-filter.is-active .page-header-offcanvas-item-check svg,
        .page-header-offcanvas-item.is-filter.is-active .page-header-offcanvas-item-check i {
            opacity: 1;
        }
        .page-header-offcanvas-item-text {
            flex: 1 1 auto;
            min-width: 0;
            overflow: hidden;
            text-overflow: ellipsis;
        }
        .page-header-offcanvas-item-meta {
            flex: 0 0 auto;
            margin-left: auto;
            color: var(--bs-secondary-color);
            font-size: 0.875rem;
            font-weight: 400;
            font-variant-numeric: tabular-nums;
        }
        .page-header-offcanvas-item.is-filter.is-active .page-header-offcanvas-item-text {
            font-weight: 600;
            color: var(--x-brand-blue-deep, #0d6efd);
        }
        .page-header-offcanvas-item.is-filter.is-active .page-header-offcanvas-item-meta {
            color: var(--x-brand-blue-deep, #0d6efd);
            font-weight: 500;
        }
        /* Hover/focus mag het is-active accent niet wegspoelen — het hover-
           bg-tint past al op alle items (van .page-header-offcanvas-item rule). */

        /* ---- Mobile tabs trigger (tablist → offcanvas converter) ----
           Vervangt op <md de wrappende pill-row door één compacte "huidige
           tab"-knop met chevron-down. Tap opent dezelfde page-header-
           offcanvas met alle tabs als single-select items (mirror filter
           visuele state). Implementatie: helios-tabs-mobile.js.

           Visueel ontwerp: subtiele brand-blue tint + brand-blue rand/
           tekst — leest direct als "actieve tab-selectie" (Material
           exposed-picker / iOS segment-control conventie) zonder agressief
           te zijn. Badges blijven leesbaar dankzij witte pill-bg achter
           de badge-class. */
        .helios-tabs-mobile-trigger {
            display: flex;
            align-items: center;
            gap: 0.625rem;
            width: 100%;
            padding: 0.75rem 1rem;
            margin-bottom: 1rem;
            background-color: rgba(13, 110, 253, 0.06);
            background-color: color-mix(in srgb, var(--x-brand-blue-deep, #0d6efd) 7%, transparent);
            border: 1.5px solid var(--x-brand-blue-deep, #0d6efd);
            border-radius: var(--orbit-radius, 10px);
            color: var(--x-brand-blue-deep, #0d6efd);
            font-size: 1rem;
            font-weight: 600;
            line-height: 1.3;
            text-align: left;
            cursor: pointer;
            transition: background-color 0.12s ease;
        }
        .helios-tabs-mobile-trigger:hover,
        .helios-tabs-mobile-trigger:focus-visible {
            background-color: color-mix(in srgb, var(--x-brand-blue-deep, #0d6efd) 12%, transparent);
            outline: none;
        }
        .helios-tabs-mobile-trigger-label {
            flex: 1 1 auto;
            min-width: 0;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }
        /* Badge-slot — leeg = onzichtbaar, gevuld = clone van source-badge.
           Source-badge brengt eigen styling mee (.bg-primary, .bg-secondary,
           etc.). Op brand-blue tinted trigger achtergrond zijn die nog
           leesbaar; geen override nodig. */
        .helios-tabs-mobile-trigger-badge {
            flex: 0 0 auto;
            display: inline-flex;
            align-items: center;
        }
        .helios-tabs-mobile-trigger-badge:empty {
            display: none;
        }
        .helios-tabs-mobile-trigger-chevron {
            flex: 0 0 auto;
            width: 18px;
            height: 18px;
            color: var(--x-brand-blue-deep, #0d6efd);
            transition: transform 0.15s ease;
        }
        .helios-tabs-mobile-trigger[aria-expanded="true"] .helios-tabs-mobile-trigger-chevron {
            transform: rotate(180deg);
        }
        /* Verberg de bron-tablist op mobiel zodra JS 'm gemarkeerd heeft.
           !important wint van bestaande display utilities (nav-fill = flex). */
        @media (max-width: 767.98px) {
            .helios-tabs-mobile-source {
                display: none !important;
            }
        }

        /* ---- Tab-picker offcanvas item (.is-tab) ----
           Single-select radio variant van page-header-offcanvas-item:
           geen leading checkbox (multi-select-affordance is misleidend voor
           tabs); rechts een lucide check die alleen verschijnt op het
           actieve item. Mirror van iOS Settings / Material exposed-picker.
           Badge-clone tussen label en check. Implementatie: helios-tabs-
           mobile.js. */
        .page-header-offcanvas-item.is-tab {
            gap: 0.625rem;
        }
        .page-header-offcanvas-item.is-tab .page-header-offcanvas-item-text {
            flex: 1 1 auto;
            min-width: 0;
            overflow: hidden;
            text-overflow: ellipsis;
        }
        .page-header-offcanvas-item-tab-badge {
            flex: 0 0 auto;
            display: inline-flex;
            align-items: center;
        }
        .page-header-offcanvas-item-tab-badge:empty {
            display: none;
        }
        .page-header-offcanvas-item-tab-check {
            flex: 0 0 auto;
            width: 1.25rem;
            height: 1.25rem;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            color: var(--x-brand-blue-deep, #0d6efd);
            opacity: 0;
            transition: opacity 0.12s ease;
        }
        .page-header-offcanvas-item.is-tab .page-header-offcanvas-item-tab-check svg,
        .page-header-offcanvas-item.is-tab .page-header-offcanvas-item-tab-check i {
            width: 18px;
            height: 18px;
            stroke-width: 2.75;
        }
        .page-header-offcanvas-item.is-tab.is-active .page-header-offcanvas-item-tab-check {
            opacity: 1;
        }
        .page-header-offcanvas-item.is-tab.is-active .page-header-offcanvas-item-text {
            font-weight: 600;
            color: var(--x-brand-blue-deep, #0d6efd);
        }

        /* ---- Mobile layout ----
           Compacte spacing met dezelfde ritme-verhoudingen als desktop
           (breadcrumb tight, intro tight onder title, divider met extra
           ruimte erboven als sectie-einde-signaal). */
        @media (max-width: 575.98px) {
            .page-header {
                padding-top: 0;
                padding-bottom: 0;
                margin-bottom: 1.25rem;
            }
            .page-header-breadcrumb {
                margin-bottom: 0.5rem;
            }
            /* Mobile-breadcrumb: forceer single-line, ellipsis op active.
               Voorkomt 2-3 regelige wrap bij diepe paden met een lange
               laatste segment (hostname FQDN, klantnaam) of een
               niet-active label met whitespace (bv. "Server agents" →
               zonder nowrap wrapt 'agents' naar regel 2 binnen z'n eigen
               li). De collapse-dropdown wordt door page-header.php
               gerenderd zodra count >= 4.

               Strategie:
               - Container: flex-wrap nowrap, overflow-x hidden (vangt
                 extreme edge-cases af zonder horizontale scroll).
               - Alle items: white-space nowrap (geen interne tekst-wrap).
               - Niet-active items: flex-shrink 0 (natuurlijke breedte
                 behouden, zodat alleen de active wordt afgekapt).
               - Active item: flex-shrink 1 + ellipsis (krimpt eerst,
                 truncate met …). */
            .page-header-breadcrumb-mobile .breadcrumb {
                flex-wrap: nowrap;
                min-width: 0;
                overflow: hidden;
            }
            .page-header-breadcrumb-mobile .breadcrumb-item {
                white-space: nowrap;
                min-width: 0;
                flex-shrink: 0;
            }
            .page-header-breadcrumb-mobile .breadcrumb-item.active {
                flex-shrink: 1;
                overflow: hidden;
                text-overflow: ellipsis;
            }
            .page-header-row {
                flex-direction: column;
                align-items: stretch;
                gap: 0.625rem;
            }
            .page-header-title-block {
                width: 100%;
            }
            .page-header-title {
                font-size: 1.5rem;
                line-height: 1.2;
                /* Cap op 2 regels — extreem lange titels (FQDN's,
                   klantnamen + actie-suffix) wrappen niet eindeloos.
                   Volledige titel blijft opvraagbaar via title=""
                   attr (long-press mobiel / hover desktop). */
                display: -webkit-box;
                -webkit-line-clamp: 2;
                -webkit-box-orient: vertical;
                overflow: hidden;
            }
            .page-header-intro {
                margin-top: 0.375rem;
            }
            /* Mobiel: knoppen onder elkaar i.p.v. 50/50 naast elkaar.
               Reden: bij 2 niet-back acties (bv. secondary + primary CTA)
               gaf flex-row 50/50 te smalle touch-targets (~160px op iPhone)
               + ellipsis-risico bij langere labels, en plette de visuele
               hiërarchie omdat primary/secondary dezelfde breedte kregen.
               Stacked column → full-width tap-targets, DOM-order zet de
               primary CTA automatisch onderaan (thumb-reach). */
            .page-header-actions {
                width: 100%;
                flex-direction: column;
                align-items: stretch;
                justify-content: flex-start;
                gap: 0.5rem;
            }
            /* Override desktop row-distribution (flex:1 grow op main-axis):
               in column zou flex:1 verticaal stretchen — ongewenst. */
            .page-header-actions > .page-header-btn {
                flex: 0 0 auto;
            }
            /* Back-knop blijft compact links boven — een full-width
               "← Terug" knop is overkill voor pure navigatie. */
            .page-header-actions > .page-header-btn-back {
                align-self: flex-start;
            }
            .page-header-divider {
                margin-top: 1rem;
            }
        }

        /* ---- Accent button (brand oranje CTA) -------------------- */
        /* Physical feel: border-bottom-2px darker tint gives depth
           (the button looks "standing up"). On :active we reduce
           the border-bottom to 1px and translateY(+1px) — the button
           visibly "pushes in". */
        .btn-accent {
            background-color: var(--orbit-accent);
            border-color: var(--orbit-accent);
            border-bottom: 2px solid var(--orbit-accent-deep);
            color: var(--orbit-on-accent);
            box-shadow: 0 2px 6px rgba(var(--x-brand-orange-rgb), 0.25);
            transition: transform 0.1s ease,
                        box-shadow 0.15s ease,
                        background-color 0.15s ease,
                        border-color 0.15s ease,
                        border-bottom-width 0.1s ease;
        }
        .btn-accent:hover,
        .btn-accent:focus-visible {
            background-color: var(--orbit-accent-hover);
            border-color: var(--orbit-accent-hover);
            border-bottom-color: var(--orbit-accent-deep);
            color: var(--orbit-on-accent);
            box-shadow: 0 4px 10px rgba(var(--x-brand-orange-rgb), 0.35);
            transform: translateY(-1px);
        }
        .btn-accent:active,
        .btn-accent.active {
            background-color: var(--orbit-accent-deep);
            border-color: var(--orbit-accent-deep);
            border-bottom-width: 1px;
            color: var(--orbit-on-accent);
            box-shadow: 0 1px 3px rgba(var(--x-brand-orange-rgb), 0.20);
            transform: translateY(1px);
        }
        .btn-accent:disabled,
        .btn-accent.disabled {
            background-color: var(--orbit-accent);
            border-color: var(--orbit-accent);
            color: var(--orbit-on-accent);
            opacity: 0.6;
            box-shadow: none;
            transform: none;
        }
        /* Icon spacing consistent with other bi-icon-in-button patterns */
        .btn-accent > .bi:first-child {
            margin-right: 0.4em;
        }
        .btn-outline-accent {
            background-color: transparent;
            border-color: var(--orbit-accent);
            color: var(--orbit-accent);
            transition: background-color 0.15s ease, color 0.15s ease;
        }
        .btn-outline-accent:hover,
        .btn-outline-accent:focus-visible {
            background-color: var(--orbit-accent);
            border-color: var(--orbit-accent);
            color: var(--orbit-on-accent);
        }

        /* ---- Sidebar active-state + sub-item tints ---------------
           Active-leaf-nav-link: bg-tint (blue-soft) zonder border-left.
           Alleen voor leaf-links die naar concrete views wijzen — de
           section-header toggles hebben geen `.active` class, dus
           `#sidebar .nav-link.active` raakt alleen leaf-items. Sub-
           items krijgen nog steeds een subtle baseline-tint zodat het
           accordion-groep-gevoel behouden blijft. */
        /* Rust-state: transparent. Alleen hover + active krijgen
           tint zodat items visueel rustig zijn in idle-state. Hover
           subtle (rgba-wit 0.04), active duidelijk (blue-soft 0.18)
           — 4× alpha-sprong tussen hover en active maakt active-
           state onmiddellijk herkenbaar. */
        #sidebar .nav-link {
            background-color: transparent;
        }
        #sidebar .nav-link:hover {
            background-color: rgba(255, 255, 255, 0.04);
        }
        #sidebar .nav-link.active {
            background-color: rgba(var(--x-brand-blue-soft-rgb), 0.18);
            color: #ffffff;
        }
        /* Sub-items in collapse-accordion: identiek aan top-level,
           geen extra baseline-tint meer. */
        #sidebar .collapse .nav-link.active {
            background-color: rgba(var(--x-brand-blue-soft-rgb), 0.22);
            color: #ffffff;
        }

        /* ---- Icon badges (soft circular icon chips) -------------- */
        .icon-badge {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            width: 1.5rem;
            height: 1.5rem;
            border-radius: 50%;
            flex-shrink: 0;
            font-size: 0.875rem;
            line-height: 1;
        }
        .icon-badge-success {
            background-color: rgba(var(--bs-success-rgb), 0.15);
            color: var(--bs-success);
        }
        .icon-badge-accent {
            background-color: var(--orbit-accent-subtle);
            color: var(--orbit-accent);
        }
        .icon-badge-info {
            background-color: rgba(var(--bs-info-rgb), 0.15);
            color: var(--bs-info);
        }
        .icon-badge-warning {
            background-color: rgba(var(--bs-warning-rgb), 0.20);
            color: #b38318;
        }
        .icon-badge-danger {
            background-color: rgba(var(--bs-danger-rgb), 0.12);
            color: var(--bs-danger);
        }
        .icon-badge-secondary {
            background-color: rgba(var(--bs-secondary-rgb), 0.15);
            color: var(--bs-secondary);
        }

        /* ---- Card shadow refresh (global) ------------------------ */
        /* Softer shadow + subtle border to align with xynta.com brand.
           Replaces Bootstrap's default by being more specific / later in
           cascade. God-file views that rely on default card styling keep
           working; views with .shadow-sm / .shadow-none utility classes
           override this as before. */
        .card {
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06),
                        0 1px 2px rgba(0, 0, 0, 0.04);
            border: 1px solid var(--helios-border-subtle);
            /* Surface-bg override op component-level — Bootstrap 5.3.8
               defineert `--bs-card-bg: var(--bs-body-bg)` lokaal binnen
               `.card{...}` wat :root-override shadowt. Component-level
               override werkt wel (gelijke specificity, later in source). */
            --bs-card-bg: #ffffff;
        }
        /* Overige Bootstrap surface-components met lokale bg-tokens.
           Dezelfde shadowing-truc als .card — moet op component-level,
           :root is no-op. */
        .modal {
            --bs-modal-bg: #ffffff;
            --bs-modal-color: var(--bs-body-color);
            --bs-modal-border-color: var(--bs-border-color);
            --bs-modal-header-bg: #ffffff;
            --bs-modal-footer-bg: #ffffff;
        }
        .accordion {
            --bs-accordion-bg: #ffffff;
        }
        /* Accordion-header bevat een Bootstrap <h2> wat globally Unbounded +
           uppercase overerft uit het hN-reset blok hierboven. Voor accordions
           is dat altijd verkeerd — de "header" is een interactive button met
           lopende tekst, geen display-heading. Force body-font + normale
           casing zodat lange labels (zoals in info-modals) leesbaar blijven. */
        .accordion-header,
        .accordion-button {
            font-family: 'Public Sans', sans-serif;
            text-transform: none;
            letter-spacing: 0;
        }
        .list-group {
            --bs-list-group-bg: #ffffff;
        }
        .dropdown-menu {
            --bs-dropdown-bg: #ffffff;
        }
        .nav-tabs {
            --bs-nav-tabs-link-active-bg: #ffffff;
        }
        /* Orbit Accordion override (light mode) — Bootstrap 5.3 default
           active-state is primary-blue (#cfe2ff bg + #052c65 text); conflict
           met Orbit's neutrale brand én met .helios-activity-icon-pill.tone-*
           pills binnen accordion-headers (zoals tab-snapshots.php gebruikt).
           Dark-mode override leeft in dark.css met dezelfde token-set. */
        .accordion {
            --bs-accordion-bg: var(--helios-surface-raised);
            --bs-accordion-color: var(--helios-text);
            --bs-accordion-border-color: var(--helios-border-subtle);
            --bs-accordion-btn-bg: var(--helios-surface-raised);
            --bs-accordion-btn-color: var(--helios-text);
            --bs-accordion-active-bg: var(--helios-surface-sunken);
            --bs-accordion-active-color: var(--helios-text);
            --bs-accordion-btn-focus-border-color: var(--helios-border-subtle);
            --bs-accordion-btn-focus-box-shadow: 0 0 0 0.2rem rgba(var(--bs-secondary-rgb, 108, 117, 125), 0.18);
            /* Chevron — neutral grey SVG voor beide states (Bootstrap default
               is primary-blue). Active-state krijgt rotate via Bootstrap's
               eigen transform op .accordion-button:not(.collapsed)::after. */
            --bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236c757d'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");
            --bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236c757d'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");
        }
        .accordion-button:not(.collapsed) {
            /* Subtiele bottom-line ipv Bootstrap's default no-shadow zodat de
               active-row visueel verbonden blijft met de body eronder. */
            box-shadow: inset 0 calc(-1 * var(--bs-accordion-border-width, 1px)) 0 var(--helios-border-subtle);
        }
        /* Form-control heeft geen --bs-form-control-bg token in
           Bootstrap 5.3 — Bootstrap gebruikt `background-color:
           var(--bs-body-bg)` direct. Directe background-color override
           nodig. */
        .form-control,
        .form-select {
            background-color: #ffffff;
        }
        /* ============================================================ */

        /* Align table cells inside a .card with .card-header padding (px-3 px-md-4).
           Apply via <table class="table card-table"> when the table sits flush
           inside .card-body.p-0. Without this, table-cells use their own padding
           (often Bootstrap default 0.5rem) and visually misalign with the card
           title above. See design-system.md §7c references; pattern documented
           organically as more views adopt it. */
        .card-table > thead > tr > th:first-child,
        .card-table > tbody > tr > td:first-child {
            padding-left: 1rem;        /* matches Bootstrap .px-3 = 16px */
        }
        .card-table > thead > tr > th:last-child,
        .card-table > tbody > tr > td:last-child {
            padding-right: 1rem;
        }
        @media (min-width: 768px) {
            .card-table > thead > tr > th:first-child,
            .card-table > tbody > tr > td:first-child {
                padding-left: 1.5rem;  /* matches Bootstrap .px-md-4 = 24px */
            }
            .card-table > thead > tr > th:last-child,
            .card-table > tbody > tr > td:last-child {
                padding-right: 1.5rem;
            }
        }

        .helios-table-rounded {
            border-collapse: separate;
            border-spacing: 0;
            overflow: hidden;
        }
        .helios-table-rounded tr:first-child th:first-child,
        .helios-table-rounded tr:first-child td:first-child {
            border-top-left-radius: var(--orbit-radius);
        }
        .helios-table-rounded tr:first-child th:last-child,
        .helios-table-rounded tr:first-child td:last-child {
            border-top-right-radius: var(--orbit-radius);
        }
        .helios-table-rounded tr:last-child td:first-child,
        .helios-table-rounded tr:last-child th:first-child {
            border-bottom-left-radius: var(--orbit-radius);
        }
        .helios-table-rounded tr:last-child td:last-child,
        .helios-table-rounded tr:last-child th:last-child {
            border-bottom-right-radius: var(--orbit-radius);
        }

        /* === Bulk action bar (sticky bottom) ============================
           Reusable sticky-bottom toolbar voor bulk-acties op tabel-views.
           Toont bij ≥1 selectie (via `.d-none` toggle vanuit JS).
           Canonical markup wordt gerendered door `private/tpl/bulk-action-bar.php`:
           count-label + "Acties" dropup-trigger + Wissen-knop.
           De dropdown-menu-action class triggert helios-row-actions-mobile.js
           voor automatische omzetting naar bottom-sheet offcanvas op <md.

           Layout:
             - Default `left:0 right:0` (full-width op mobile/tablet/laptop)
             - Op xxl+ (≥1400px) waar #sidebar 300px claimt: `left:300px`
               zodat de bar netjes naast de sidebar zit, niet erachter.

           Theming:
             - `--bs-body-bg` als base (theme-aware via data-theme).
             - In dark-mode wisselen we naar `--bs-card-bg` voor een
               "floating panel"-tint die net iets oplicht t.o.v. de
               dark body-bg. Border-top transparent-light voor subtiele
               afscheiding van content erboven.

           Bulk-actions dropup-menu (.orbit-bulk-action-menu):
             - z-index > 1040 zodat menu stackt boven de bar (Bootstrap
               default 1000 zou er onder vallen).
             - min-width 240px voor leesbare labels (geen wrap).
             - max-height + scroll voor lange action-lijsten. */
        .orbit-bulk-action-bar {
            left: 0;
            right: 0;
            background: var(--bs-body-bg);
            color: var(--bs-body-color);
            border-top: 1px solid var(--bs-border-color);
        }
        @media (min-width: 1400px) {
            .orbit-bulk-action-bar { left: 300px; }
        }
        [data-theme="dark"] .orbit-bulk-action-bar {
            background: var(--bs-card-bg, #1f242c);
            border-top-color: var(--bs-border-color-translucent, rgba(255,255,255,0.15));
        }
        .orbit-bulk-action-menu {
            z-index: 1050;
            min-width: 240px;
            max-height: 60vh;
            overflow-y: auto;
        }
        .orbit-bulk-action-menu .dropdown-item {
            padding: 0.5rem 0.85rem;
        }
        .orbit-bulk-action-menu .dropdown-header {
            font-size: 0.7rem;
            font-weight: 600;
            text-transform: uppercase;
            letter-spacing: 0.04em;
            color: var(--bs-secondary-color, var(--bs-body-color));
            opacity: 0.7;
        }

        @media (max-width: 767.98px) {
        .orbit-table-mobile {
            border: 0;
            width: 100%;
            min-width: 100%;
            table-layout: fixed;
        }

        .table-responsive > .orbit-table-mobile {
            width: 100% !important;
            min-width: 100% !important;
        }

        .table-responsive.orbit-table-mobile-wrap {
            overflow-x: visible;
        }

        .orbit-table-mobile tbody,
        .orbit-table-mobile tbody tr {
            width: 100%;
            box-sizing: border-box;
        }

        .orbit-table-mobile.table-bordered > :not(caption) > * > * {
            border: 0;
        }

        .orbit-table-mobile thead {
            display: none;
        }

        .orbit-table-mobile tbody tr {
            display: block;
            background: #ffffff;
            border: 1px solid rgba(0, 0, 0, 0.1);
            border-radius: var(--orbit-radius);
            margin-bottom: 0.65rem;
            overflow: hidden;
            position: relative;
            box-shadow: none;
        }

        .orbit-table-mobile tbody td {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 0.75rem;
            padding: 0.55rem 0.8rem;
            border-top: 0;
            text-align: left !important;
            white-space: normal !important;
            background: transparent;
            /* Reset inline desktop-caps (style="max-width:340px") in card-mode —
               de tr is hier al 100% en truncate gebeurt in nested wrappers. */
            max-width: none !important;
            /* Long unbreakable tokens (e-mailadressen, URLs, subjects met
               cdn-links) hebben geen breekpunten en zijn daardoor breder dan
               hun line-box. text-align:right wordt dan een no-op (overflow
               gaat per CSS-spec rechts buiten de box; visueel start de tekst
               links). overflow-wrap:anywhere laat de browser mid-token breken
               zodat zowel rechts-uitlijning (.helios-mobile-stack) als plain
               flex-positionering (receiver-kolom) altijd werken — én de rij
               nooit breder wordt dan de viewport. */
            overflow-wrap: anywhere;
        }

        /* Multi-child name-cells — wrapt link + badges-rij in 1 flex-item zodat
           de td maar ::before + 1 child heeft. Anders worden link en badges-div
           beide flex-items en wedget de link in het midden i.p.v. flush rechts. */
        .orbit-table-mobile tbody td > .helios-mobile-stack {
            flex: 1 1 0%;
            min-width: 0;
            text-align: right;
            overflow-wrap: anywhere;
        }
        .orbit-table-mobile tbody td > .helios-mobile-stack > .d-flex {
            justify-content: flex-end;
        }

        /* Sibling-stack fallback voor cellen die NIET in een helios-mobile-stack
           gewrapped zijn. Pattern B (zie reports, ip-requests, shortener):
               <td><a>primary</a><div class="d-flex flex-wrap mt-1">badges</div>…</td>
           Zonder deze regel worden de link en de badges-div allebei flex-items
           op dezelfde rij (justify-content:space-between), wat de cel propt en
           de hele rij visueel laat verspringen. Met flex-wrap+100% basis op
           niet-eerste children stapelen badge-rijen netjes ONDER de primary
           content, rechts uitgelijnd voor visuele rust. orbit-table-actions
           uitgesloten — die heeft eigen grid-layout (zie boven).             */
        .orbit-table-mobile tbody td:not(.orbit-table-actions) {
            flex-wrap: wrap;
            align-content: flex-start;
        }
        .orbit-table-mobile tbody td:not(.orbit-table-actions) > *:not(:first-child) {
            flex: 0 0 100%;
            max-width: 100%;
            margin-left: 0;
            text-align: right;
        }
        /* Badge-rij die DIRECT child van td is (niet binnen helios-mobile-stack):
           rechts uitlijnen zodat de badges flush rechts staan in lijn met de
           primary content erboven. */
        .orbit-table-mobile tbody td:not(.orbit-table-actions) > .d-flex {
            justify-content: flex-end;
        }

        /* Empty-state td binnen orbit-table-mobile mag GEEN flex-container zijn
           (`.orbit-table-mobile tbody td` zet display:flex hierboven). Forceer
           block + 100% breedte zodat het lege bericht over de hele card-rij
           gecentreerd staat, niet als flex-item links uitgelijnd. Defeat ook
           de wrap-rule op `td:not(.orbit-table-actions)` (flex-wrap:wrap) die
           in block-mode geen effect heeft maar voor visuele rust expliciet
           uitgesloten via deze override. Op desktop is dit niet nodig — daar
           handelt DT's colspan-attr de spanning af (zie td.dt-empty boven). */
        .orbit-table-mobile tbody td.dt-empty {
            display: block !important;
            width: 100% !important;
        }

        .orbit-table-mobile tbody tr:nth-child(even) {
            background: #f8f9fb;
        }

        .orbit-table-mobile tbody td[data-label]::before {
            content: attr(data-label);
            font-weight: 600;
            color: var(--helios-muted);
            font-size: 0.75rem;
            letter-spacing: 0.02em;
            text-transform: uppercase;
            flex: 0 0 40%;
        }


        .orbit-table-mobile td.orbit-table-actions {
            display: block;
            padding: 0.65rem 0.8rem;
        }

        /* Acties-cell heeft geen kolomlabel nodig op mobiel — de knoppen
           spreken voor zich. Onderdrukt het [data-label]::before pseudo
           zodat templates met of zonder data-label op de actions-td
           consistent renderen. */
        .orbit-table-mobile td.orbit-table-actions[data-label]::before {
            content: none;
        }

        .orbit-table-mobile td.orbit-table-actions .d-grid,
        .orbit-table-mobile td.orbit-table-actions .d-md-flex,
        .orbit-table-mobile td.orbit-table-actions .d-flex {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
            align-items: stretch;
            gap: 0.5rem !important;
        }

        .orbit-table-mobile td.orbit-table-actions .dropdown {
            width: 100%;
        }

        .orbit-table-mobile td.orbit-table-actions form,
        .orbit-table-mobile td.orbit-table-actions .btn {
            width: 100%;
        }

        .orbit-table-mobile td.orbit-table-actions .btn {
            justify-content: center;
        }

        .orbit-table-mobile tbody tr:last-child {
            margin-bottom: 0;
        }

        .orbit-table-mobile code {
            white-space: normal;
            word-break: break-word;
        }

        .orbit-table-mobile .text-truncate {
            max-width: none !important;
            overflow: visible;
            text-overflow: unset;
            white-space: normal !important;
        }

        /* Verbergt secundaire inline `<span class="text-muted small">…</span>`
           noten op mobiele card-rendering. Sluit `.badge` expliciet uit:
           neutrale status-badges (`badge bg-light text-muted ... small`)
           combineren beide klassen en zouden anders volledig verdwijnen
           op viewport <768px (zie buglog: spamfilter status-badge case). */
        .orbit-table-mobile td .text-muted.small:not(.badge) {
            display: none;
        }

        /* Mono-truncate behoudt ellipsis op mobile in orbit-table-mobile cellen.
           De generieke `.text-truncate`-override hierboven cancelt truncation
           voor lange zinnen, maar identifiers (hostname, IP, SKU, path) wil je
           juist afgekapt zien met de volle waarde in het title-attribute.

           Drie samenhangende eigenschappen zijn nodig om dit binnen flex te
           laten werken:
             1. `flex: 1 1 0` — basis=0 zodat de flex-algoritme bij de
                wrap-beslissing niet uitgaat van de natural content-width
                (volle hostname-text); de span "wil" initieel 0px en groeit
                in de beschikbare ruimte na het ::before-label.
             2. `min-width: 0` — default `min-width: auto` resolveert voor
                een flex-item naar `min-content`, wat bij nowrap-text gelijk
                is aan de volle text-width. Dat heft het effect van punt 1
                weer op. Met `min-width: 0` mag het item daadwerkelijk smaller
                worden dan zijn content.
             3. `display: block` — geforceerd (overrules `inline-block` van
                de standalone-class) zodat het flex-item-gedrag rechtlijnig
                is en de inline-block intrinsic-sizing geen interferentie
                geeft met de flex-grow-allocation.
           Zonder alle drie wraps de span naar een tweede regel onder het
           ::before-label i.p.v. te truncaten binnen de beschikbare ~60vw. */
        .orbit-table-mobile .orbit-mono-truncate {
            display: block;
            flex: 1 1 0;
            min-width: 0;
            max-width: 100%;
            text-align: right;
        }

        /* Prose-variant: zelfde mobile-aware single-line truncate maar zonder
           monospace-font. Voor body-tekst in tabel-cellen (reason, description,
           notes) die op mobiel anders multi-line break't omdat de algemene
           .orbit-table-mobile .text-truncate override `white-space: normal`
           afdwingt. Standalone-class: voor cells die geen explicite max-width
           dragen valt hij terug op `max-width: 100%` zodat de truncate werkt
           binnen welke wrapper dan ook. Caller zet `title="<volle waarde>"`
           voor hover/long-press. */
        .orbit-cell-truncate {
            display: block;
            max-width: 100%;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }
        .orbit-table-mobile .orbit-cell-truncate {
            display: block;
            flex: 1 1 0;
            min-width: 0;
            max-width: 100%;
            text-align: right;
        }

        /* Tabs op mobiel: VERTICAAL stapelen i.p.v. horizontaal scrollen.
           Horizontale scroll verbergt tabs achter de viewport-rand en is
           makkelijk te missen. Een gestapelde lijst is direct zichtbaar
           en discoverable. Werkt voor zowel `.nav-tabs` als `.nav-pills`,
           en negeert Bootstrap's `row row-cols-N` grid + `g-*` gutters
           op mobiel zodat er geen dubbele spacing ontstaat. */
        .nav.nav-tabs,
        .nav.nav-pills {
            flex-direction: column;
            flex-wrap: nowrap;
            row-gap: 0.25rem;
            margin-bottom: 1rem !important;
            --bs-gutter-x: 0;
            --bs-gutter-y: 0;
        }

        .nav.nav-tabs > .nav-item,
        .nav.nav-pills > .nav-item,
        .nav.nav-tabs > .col,
        .nav.nav-pills > .col {
            padding-left: 0;
            padding-right: 0;
            margin-top: 0;
        }

        .nav.nav-tabs .nav-item,
        .nav.nav-pills .nav-item {
            flex: 0 0 auto;
            width: 100%;
            max-width: 100%;
        }

        .nav.nav-tabs .nav-link,
        .nav.nav-pills .nav-link {
            width: 100%;
            justify-content: space-between;
            text-align: left;
            white-space: normal;
        }

        .form-select,
        .form-control,
        .nav-link,
        .dropdown-item {
            min-height: 44px;
        }

        /* Native date/time-pickers centeren hun value-tekst niet automatisch
           binnen de 44px min-height (text top-aligned op iOS Safari + sommige
           Chrome-versies). Expliciete vertical-padding balanceert de waarde
           verticaal in de input — .625rem (10px) top + bottom matcht het
           visuele centrum bij font-size .875rem (form-control-sm) en 1rem
           (form-control). */
        input.form-control[type="date"],
        input.form-control[type="datetime-local"],
        input.form-control[type="time"],
        input.form-control[type="month"],
        input.form-control[type="week"] {
            padding-top: .625rem;
            padding-bottom: .625rem;
        }

        /* .btn krijgt op mobiel iets meer vertical padding i.p.v.
           een min-height: 44px forcering. min-height gaf ~14px extra
           symmetrische ruimte die door icon/baseline-verschillen
           visueel als asymmetrische bottom-padding oogde. Padding
           schaalt de knop natural mee met zijn inhoud en respecteert
           size-modifiers (.btn-sm, .btn-lg) automatisch. WCAG 2.5.5
           tap-target blijft voldaan (~42px hoogte). */
        .btn {
            --bs-btn-padding-y: 0.5625rem;
        }

        /* 2FA one-time-code cluster: 6 single-digit inputs side-by-side.
           Onder 400px krimpen ze gelijkmatig i.p.v. te overflowen. */
        #twofa-code-inputs .form-control {
            min-height: 0;
        }

        /* DNS-records-editor (zone + template-form): form-controls in cellen
           moeten op mobile de volle rij-breedte vullen. De canonical mobile
           orbit-table-mobile-pattern heeft een ::before label (40%) + content
           in flex-row, maar form-controls hebben geen intrinsic stretch —
           expliciete width:100% nodig. Scoped op .dns-records-editor zodat
           overige tables (display-only) ongemoeid blijven.

           Root-cause-fix: de row-partial heeft inline `style="width:90px"`
           (TTL), `width:80px` (priority), `width:100px` (type), `width:200px`
           (name), `width:140px` (actions) op de <td>'s — bedoeld voor
           desktop-table-layout. In card-mode is de <td> `display:flex` als
           block-niveau child van het block-niveau `<tr>`, dus die inline
           widths cap het hele td-vakje op 80-200px en de form-control daarin
           blijft daardoor truncated. `width:auto !important` reset alleen in
           card-mode (binnen deze @media-block), desktop behoudt zijn vaste
           kolomwidths. `max-width: none !important` stond al op de globale
           regel maar dekte `width:Npx` niet af. */
        .dns-records-editor.orbit-table-mobile-wrap .orbit-table-mobile tbody td {
            width: auto !important;
        }
        .dns-records-editor.orbit-table-mobile-wrap .orbit-table-mobile tbody td .form-control,
        .dns-records-editor.orbit-table-mobile-wrap .orbit-table-mobile tbody td .form-select {
            flex: 1 1 0%;
            min-width: 0;
            width: 100%;
        }

        /* Action-cell binnen records-editor: de save/delete-knoppen zitten in
           een .btn-group (50/50 layout op desktop). De globale mobile-rule
           hierboven forceert .orbit-table-actions .btn { width:100% }, wat
           binnen een flex-row .btn-group elke knop laat overflowen. Reset
           naar flex-distributie zodat de knoppen 50/50 blijven in hun
           btn-group container — die op zijn beurt `.w-100` heeft via markup. */
        .dns-records-editor .orbit-table-mobile td.orbit-table-actions .btn-group {
            display: flex;
            width: 100%;
        }
        .dns-records-editor .orbit-table-mobile td.orbit-table-actions .btn-group > .btn {
            flex: 1 1 0;
            width: auto;
        }
        }

/* ── Actieve-taken tray ───────────────────────────────────────────────
   Subtiel getint omhulsel rond de lopende-job-cards op detailpagina's
   (bestemming/server/snapshot). De witte/elevated job-cards "zweven" op
   deze laag → duidelijke scheiding tussen live-activiteit en de solide
   info/beheer-kaarten eronder. Zie design-system.md §51 (tray-variant).
   Top-level (geen @media-nesting) zodat het op alle breedtes geldt —
   mirror van de dark.css overrides. */
.helios-task-tray {
    background: var(--bs-tertiary-bg);
    border: 1px solid var(--bs-border-color-translucent);
    border-radius: var(--orbit-radius, 10px);
    padding: 1rem 1rem 0.25rem;   /* bodem krap: job-cards dragen mb-3 */
    margin-bottom: 1.5rem;
}
/* De sectie-kop zit binnen de tray; haal de eigen top-marge eraf zodat
   de kop niet dubbel inspringt. */
.helios-task-tray > .helios-task-tray-head {
    margin-top: 0;
}
/* De job-card grid krijgt geen extra onder-marge binnen de tray
   (de tray-padding regelt de ademruimte). */
.helios-task-tray > .row {
    margin-bottom: 0.75rem;
}

/* DNS-row live-save status-indicator. Klein icoon in de action-cell dat de
   save-state van een rij toont (dirty / saving / saved / invalid / failed).
   Spinner-rotatie scoped op `.dns-row-status .spin` zodat losse lucide-loader
   icons elders ongemoeid blijven. */
.dns-row-status {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 16px;
    flex: 0 0 auto;
}
.dns-row-status .spin {
    animation: dns-row-spin 0.8s linear infinite;
}
@keyframes dns-row-spin {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}

        /* Globale identifier-truncate: ellipsis voor monospace identifiers
           (hostname, IP, SKU, path, mac). Caller zet `title="<value>"` zodat
           hover/long-press de volle waarde toont. Standaard 240px op desktop,
           op mobiel valt hij terug op 100% van zijn container (zie de
           orbit-table-mobile override in de mediaquery hierboven). */
        .orbit-mono-truncate {
            display: inline-block;
            max-width: 240px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            vertical-align: bottom;
            font-family: var(--bs-font-monospace);
        }

        /* Globale bar+value component voor tabel-cellen (CPU/MEM/DISK/usage/quota).
           Desktop: progress 80px fixed, waarde rechts, nowrap op één regel.
           Mobiel  (binnen orbit-table-mobile cell, ~60vw content-area): progress
           wordt fluid (32-56px), `compact_html`-span vervangt de volle waarde
           zodat de cell-content netjes binnen één regel past i.p.v. onder de
           data-label::before te vallen. Zie private/tpl/orbit-bar-value.php. */
        .orbit-bar-value {
            display: flex;
            align-items: center;
            justify-content: flex-end;
            gap: 0.5rem;
            flex-wrap: nowrap;
            min-width: 0;
        }
        .orbit-bar-value-progress {
            flex: 0 0 80px;
            width: 80px;
            height: 6px;
            min-width: 32px;
        }
        .orbit-bar-value-full   { display: inline; }
        .orbit-bar-value-compact { display: none; }

        @media (max-width: 767.98px) {
            .orbit-bar-value-progress {
                flex: 1 1 0;
                width: auto;
                min-width: 32px;
                max-width: 56px;
            }
            .orbit-bar-value--has-compact .orbit-bar-value-full   { display: none; }
            .orbit-bar-value--has-compact .orbit-bar-value-compact { display: inline; }
        }

        /* Globale bar-stacked component voor card/panel-secties (usage, quota,
           live-metric, period-summary). Label-rij boven (label links + value
           rechts), full-width progress eronder. Variant van .orbit-bar-value
           voor layouts waar de bar NIET in een tabel-cell zit naast de waarde.
           Zie private/tpl/orbit-bar-stacked.php. */
        .orbit-bar-stacked-row {
            display: flex;
            justify-content: space-between;
            align-items: baseline;
            gap: 0.5rem;
            margin-bottom: 0.25rem;
        }
        .orbit-bar-stacked-label {
            color: var(--helios-muted, var(--bs-secondary-color));
            font-size: 0.875rem;
        }
        .orbit-bar-stacked-value {
            font-family: var(--bs-font-monospace);
            font-size: 0.875rem;
            font-weight: 500;
        }
        .orbit-bar-stacked-progress {
            /* height wordt via inline style gezet door de partial (default 6px) */
        }

        /* Orbit-merk bar-fill voor "normale" (niet-threshold) progress-bars.
           Bootstrap's .progress-bar default leest --bs-progress-bar-bg (vaste
           BS-blauw #0d6efd), NIET --bs-primary — vandaar deze utility. Light:
           dezelfde deep-navy als de table-headers (.table tr.table-dark th =
           --orbit-primary-deep) voor visuele samenhang. Dark: de bestaande
           dark.css-regel `html[data-theme="dark"] .progress-bar` (specificity
           0,2,1 > 0,2,0) wint en zet de fill op --helios-info-accent — een
           zichtbaar lichtblauw op de zwarte track; deep-navy zou daar wegvallen. */
        .progress-bar.orbit-bar-brand {
            background-color: var(--orbit-primary-deep);
        }

        /* Stats-toplijsten: waarde-tekst boven de bar in de normale UI-font —
           orbit-bar-stacked-value is default monospace (--bs-font-monospace),
           wat hier niet gewenst is. Scoped modifier, raakt andere callsites niet. */
        .orbit-bar-stacked-plainval .orbit-bar-stacked-value {
            font-family: inherit;
        }

        #twofa-code-inputs .form-control {
            width: 48px;
            font-size: 1.25rem;
            text-align: center;
        }

        /* Pre-xs edge for 2FA input cluster on small phones */
        @media (max-width: 400px) {
            #twofa-code-inputs {
                gap: 0.375rem;
            }
            #twofa-code-inputs .form-control {
                width: auto;
                flex: 1 1 0;
                min-width: 0;
                font-size: 1.1rem;
            }
        }

        /* Action-dropdowns (listings, stats, detail-toolbars). Natural
           260px op tablet+, volle viewport-breedte op smalle telefoons. */
        .dropdown-menu.dropdown-menu-action {
            width: 260px;
        }
        @media (max-width: 575.98px) {
            .dropdown-menu.dropdown-menu-action {
                width: calc(100vw - 2rem);
                max-width: 260px;
            }
        }

        /* Right-aligned dropdowns force-left-align op smalle telefoons
           om viewport-clip te voorkomen. Popper's flip-middleware zou
           dit normaal al regelen, maar de fixed-strategy patch in
           footer.php maakt flip-gedrag onbetrouwbaar. !important is
           nodig om Popper's inline left:<px> style te overrulen. */
        @media (max-width: 575.98px) {
            .dropdown-menu.dropdown-menu-end {
                --bs-position: start;
                left: 0 !important;
                right: auto !important;
            }
        }

        /* Desktop (≥md): geen overflow-overrides nodig op .table-responsive.orbit-table-mobile-wrap.
           Bootstrap's default `overflow-x: auto` doet z'n werk (tabel scrollt horizontaal
           wanneer content breder is dan de wrapper), en row-action dropdowns ontsnappen
           via de globale Popper `strategy: 'fixed'` patch in private/tpl/footer.php (regel 75-99).
           Eerdere `overflow: visible !important` regel verwijderd 2026-05-26 — dead-weight
           sinds de fixed-strategy patch landde; zonder deze override valt de tabel niet meer
           buiten de body wanneer hij te breed is (zie buglog bug-4756). */

        h1,h2,h3,h4,h5 {
        font-family:'Unbounded',sans-serif;
        text-transform:uppercase;
        }
        h5.modal-title {
            font-size:16px;
            font-weight:600!important
        }
        .badge {
        font-weight:500;
        text-transform:uppercase;
        }
        /* ────────────────────────────────────────────────────────────
           SIDEBAR
           Desktop layout + nav-link staten + inner dropdown-menu.
           Sidebar is altijd aanwezig (desktop); op mobile rendert
           dezelfde markup als offcanvas. Dark-mode overrides
           (#sidebar *) staan in dark.css C3/C8/C10/C11/C12 secties.
           ──────────────────────────────────────────────────────────── */
        /* Sidebar base — CSS Grid layout voor zowel desktop als mobile.
           `grid-template-rows: auto 1fr auto` geeft:
             Row 1 (auto): top-area
               - Desktop: .px-4.py-4.d-xxl-block (XYNTA logo-div, 71.5px)
               - Mobile:  .offcanvas-header (Bootstrap close-btn + title)
               (In elk viewport is één van beide elementen display:none
                via d-none / d-xxl-none utilities.)
             Row 2 (1fr): .offcanvas-body — neemt resterende ruimte
             Row 3 (auto): .backend-mode-indicator — alleen gerendered
                in backend-context; in frontend wordt dit een 0px row.
           Body scrollt binnen zijn grid-row via `min-height: 0 +
           overflow-y: auto` (standard grid-scrollable-child trick —
           default `min-height: auto` blokkeert scroll anders). Werkt
           identiek in Safari en Chrome zonder percentage-height of
           :has() dependencies. */
        #sidebar {
            max-width: 100vw;
            overflow-x: hidden;
            width: 300px;
            height: 100vh;
            z-index: 1100;
            border-right: 1px solid rgba(255,255,255,0.15);
            background: var(--helios-surface-deep) !important;
            /* `!important` om utility `.d-xxl-block { display: block
               !important }` te overrulen op desktop — zonder `!important`
               wint de utility en krijgt #sidebar `display: block`,
               waardoor grid-layout niet actief is. */
            display: grid !important;
            grid-template-rows: auto 1fr auto;
            backdrop-filter: blur(4px);
        }
        #sidebar .offcanvas-body {
            min-height: 0;
            overflow-y: auto;
        }
        #sidebar .backend-mode-indicator {
            position: static;
        }
        /* Sidebar slide-in/out: 250ms ease-out voor vloeiende animatie
           BEIDE richtingen (open + close). Transition staat op base-
           selector (niet op .show state) zodat close symmetrisch met
           open werkt.

           Bootstrap past de `.offcanvas-xxl` class aan (niet `.offcanvas`)
           voor offcanvas-behavior; Bootstrap's default transition staat
           binnen @media (max-width: 1399.98px). We wrappen onze
           override in dezelfde media query. Selector `#sidebar.offcanvas-
           xxl` matcht het daadwerkelijke class-patroon.

           Ook: sidebar start onder mobile-navbar (64px) zodat navbar
           persistent zichtbaar blijft als app-chrome. Alleen van
           toepassing wanneer sidebar als offcanvas rendert (<xxl). */
        @media (max-width: 1399.98px) {
            /* Sidebar mobile-modifiers — alleen sizing/positioning.
               Grid-layout (display + template-rows) is in base-regel,
               werkt voor zowel desktop als mobile.

               `top: 64px + bottom: 0 + height: auto` positioneert
               sidebar onder de mobile navbar. `height: auto` is nodig
               om base `#sidebar { height: 100vh }` te neutraliseren —
               per CSS 2.1 §10.6.4 wordt bij over-constraint (top +
               bottom + expliciete-height) `bottom` genegeerd. Met
               height:auto respecteert iOS Safari bottom:0 t.o.v. de
               werkelijk zichtbare viewport (geen vh-inflation bug).

               `transition: transform 250ms ease-out` voor close-
               animatie (250ms iets sneller dan Bootstrap default
               300ms — sync't met hamburger icon-crossfade). */
            #sidebar.offcanvas-xxl {
                transition: transform 250ms ease-out;
                top: 64px;
                bottom: 0;
                height: auto;
            }
        }
        /* Flash-guard: .offcanvas-no-transition class (applied via JS
           in header.php bij sessionStorage-restore) disabled animatie
           voor die specifieke render-cycle. Ingedefinieerd in header.php
           inline style als defensieve fallback. */

        /* .orbit-stat-grid + .orbit-stat-table-card CSS verwijderd —
           vervangen door tpl/counter-cards.php partial (discount-views
           gemigreerd). --orbit-stat-card-<role>-* tokens blijven (nog
           gebruikt door counter-card role-modifiers). */

        /* ── Bar-in-row (stat table cards: referrers, browsers) ─── */
        .orbit-bar-row {
            display: flex;
            align-items: center;
            gap: .5rem;
        }
        .orbit-bar-track {
            flex: 1;
            min-width: 40px;
            height: 6px;
            background: var(--orbit-chart-grid);
            border-radius: 3px;
            overflow: hidden;
        }
        .orbit-bar-fill {
            display: block;
            height: 100%;
            background: var(--orbit-chart-primary);
            border-radius: 3px;
            transition: width .3s ease;
        }
        .orbit-bar-value {
            flex-shrink: 0;
            font-variant-numeric: tabular-nums;
            font-size: .875rem;
            text-align: right;
            min-width: 2.5rem;
        }

        .orbit-chart-empty-state {
            display: flex;
            align-items: center;
            justify-content: center;
            text-align: center;
            border: 1px dashed var(--orbit-chart-empty-border);
            border-radius: var(--orbit-radius);
            background: var(--orbit-chart-empty-bg);
            padding: 1rem;
        }

        .orbit-chart-empty-state__message {
            max-width: 36rem;
            color: var(--orbit-chart-empty-text);
            font-size: 0.95rem;
        }
        #sidebar .nav-section-title {
            font-size: 12px;
            letter-spacing: .08em;
            color: rgba(255,255,255,.6);
        }

        #sidebar .nav-section-title a {
            display: flex;
            width: 100%;
            align-items: center;
            justify-content: space-between;
            padding: .6rem .75rem;
            border-radius: .5rem;
        }
        #sidebar .nav-section-title a:hover {
            background: rgba(255,255,255,.08);
            text-decoration: none;
        }

        #sidebar .nav {
            display: block !important;
        }
        #sidebar .nav li {
            display: block !important;
            width: 100%;
        }

        #sidebar .nav-link {
            display: flex;
            width: 100%;
            align-items: center;
            gap: .5rem;
            color: var(--helios-surface-hover);
            font-weight: 500;
            border-radius: .5rem;
            padding: .45rem .75rem;
            margin: 1px 0;
        }

        #sidebar .nav-link:hover {
            background: rgba(255,255,255,.08);
            color: #ffffff;
            text-decoration: none;
        }

        /* Active-state styling voor #sidebar .nav-link.active wordt
           beheerd in dark.css (dark/auto-mode: accent-tint bg + border-
           left-color). Geen light-mode specifieke rule hier nodig. */

        #sidebar .nav-link.text-danger:hover {
            background: rgba(220,53,69,.15);
        }

        #sidebar .nav-icon {
            width: 18px;
            height: 18px;
            flex-shrink: 0;
            opacity: .85;
            stroke-width: 2;
        }
        /* Sidebar section-collapse chevron — CSS-toggle via aria-expanded
           op parent (`.nav-section-toggle`). Twee Lucide-iconen (down +
           up) staan in DOM; default is down zichtbaar (collapsed). Bij
           aria-expanded="true" swapt zichtbaarheid. */
        #sidebar .sidebar-chevron-wrap {
            display: inline-flex;
            align-items: center;
            line-height: 0;
        }
        #sidebar .sidebar-chevron {
            width: 14px;
            height: 14px;
            opacity: .7;
            stroke-width: 2;
        }
        #sidebar .sidebar-chevron-open {
            display: none;
        }
        #sidebar [aria-expanded="true"] .sidebar-chevron-closed {
            display: none;
        }
        #sidebar [aria-expanded="true"] .sidebar-chevron-open {
            display: inline-block;
        }

        /* ---------- Nested nav-link (visuele sub-item) ----------
           Used by items met `'nested' => true` in de menu-config. Geen
           echte tree-collapse — alleen visuele indent + kleinere font om
           parent/child-relatie zichtbaar te maken (bv. IP-aanvragen onder
           IP-adressen). corner-down-right icoon vervangt de category-icon. */
        #sidebar .nav-link-nested {
            padding-left: 1.65rem;
            font-size: .9rem;
            opacity: .92;
        }
        #sidebar .nav-link-nested .nav-icon-nested {
            width: 14px;
            height: 14px;
            opacity: .55;
        }

        /* ---------- Attention badge (pending-counts in sidebar) ----------
           Aandacht-trekkende pill (warning-tint) voor "actie nodig"-counts
           zoals openstaande IP-aanvragen. Geen Bootstrap bg-warning omdat
           die op de donkere sidebar onleesbaar wordt; eigen tokens. */
        #sidebar .orbit-nav-badge {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            min-width: 22px;
            height: 20px;
            padding: 0 8px;
            border-radius: 999px;
            font-size: .72rem;
            font-weight: 700;
            line-height: 1;
            margin-left: .5rem;
        }
        #sidebar .orbit-nav-badge-attention {
            background: var(--orbit-warning-bg, #ffb300);
            color: #2a1f00;
            box-shadow: 0 0 0 1px rgba(0, 0, 0, .12) inset;
        }
        /* Op actieve-state houden we de attention-tint zichtbaar zodat de
           "actie nodig" niet wegvalt zodra de gebruiker erop klikt. */
        #sidebar .nav-link.active .orbit-nav-badge-attention {
            background: #ffd566;
            color: #2a1f00;
        }

        /* ---------- Sectie-aggregaat (collapsed-only signaal) ----------
           Som van attention-badges van child-items, naast de chevron in de
           sectie-header. Alleen zichtbaar bij ingeklapte sectie zodat per-item
           badges niet dubbelen bij uitklap. Kleiner dan per-item pill om als
           "summary"-signaal te lezen, niet als primaire count. */
        #sidebar .orbit-nav-section-badge {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            min-width: 18px;
            height: 16px;
            padding: 0 6px;
            border-radius: 999px;
            font-size: .65rem;
            font-weight: 700;
            line-height: 1;
            letter-spacing: 0;
            text-transform: none;
        }
        #sidebar [aria-expanded="true"] .orbit-nav-section-badge {
            display: none;
        }

        /* User-menu dropdown-item icons + backend-indicator: uniform
           18px met stroke-width 2 voor Lucide SVG consistency. */
        #userManageMenu .user-menu-icon {
            width: 18px;
            height: 18px;
            opacity: .85;
            stroke-width: 2;
            flex-shrink: 0;
        }
        .backend-mode-indicator .backend-indicator-icon {
            width: 16px;
            height: 16px;
            opacity: .85;
            stroke-width: 2;
            flex-shrink: 0;
        }
        .modal {
            z-index: 1300;
        }
        .modal-title {
            font-family: 'Public Sans', sans-serif !important;
            font-weight: 700 !important;
            text-transform: none !important;
        }

        /* Dropdown-menu-primary styling (used elsewhere in Orbit,
           bv. voor primary-gekleurde dropdowns in views).
           `#sidebar .dropdown-menu` is bewust verwijderd uit deze
           selector — user-menu (#userManageMenu) heeft eigen
           component-level CSS verderop in deze file die NIET door
           deze legacy rule overruled moet worden. */
        .dropdown-menu-primary {
            min-width: 220px;
            background: #1e3553 !important;
            padding: 0 !important;
            border-radius: .6rem !important;
            overflow: hidden; /* removes top/bottom line between items */
        }
        .dropdown-menu-primary .dropdown-item {
            color: var(--helios-surface-hover) !important;
            padding: .7rem 1rem !important;
            font-size: 15px !important;
            margin: 0 !important;
            border: none !important; /* prevent thin separator lines */
        }
        .dropdown-menu-primary .dropdown-item .dropdown-link:hover,
        #sidebar .dropdown-menu .dropdown-item .dropdown-link:hover {
            background: rgba(255,255,255,0.12) !important;
            color: #ffffff !important;
            border: none !important;
            padding: .7rem 1rem !important;
            border-radius:0!important;
        }
        .dropdown-menu {
            padding:0;
            z-index:1080;
        }
        .dropdown-menu .dropdown-divider {
            margin:0;
        }
        /* Match sidebar dropdown spacing for non-sidebar dropdowns */
        .dropdown-menu .dropdown-item {
            display: flex;
            align-items: center;
            gap: .5rem;
            padding: .45rem .75rem;
            margin: 1px 0;
            border-radius:0;
        }

        .dropdown-menu .dropdown-item:hover {
            background: rgba(0,0,0,.06);
        }
        /* Tooltip trigger styling */
        .text-tooltip {
            cursor: help;
            border-bottom: 1px dotted rgba(26, 49, 80, 0.6);
            text-decoration: none;
            display:inline-block;
        }
        .card .card-header .btn {
            font-size:15px
        }
        .collapse-arrow svg {
            transition: transform 0.2s ease;
        }

        button[aria-expanded="true"] .collapse-arrow svg {
            transform: rotate(180deg);
        }

        button[aria-expanded="false"] .collapse-arrow svg {
            transform: rotate(0deg);
        }
        .tooltip {
            font-size: 12px;
        }
        .tooltip .tooltip-inner {
            background-color: #000;
            /* Tooltip-bg is theme-invariant zwart, dus text moet
               theme-invariant wit zijn. Voorheen `var(--helios-surface-
               sunken)` dat in light-mode #f8f9fa (near-white, leesbaar)
               was maar in dark-mode rebindde naar #131b24 (near-black,
               onleesbaar-op-zwart). Hardcoded #fff = altijd leesbaar. */
            color: #ffffff;
            padding: 6px 10px;
            border-radius: 6px;
            max-width: 260px;
            text-align: center;
        }

        .tooltip.bs-tooltip-top .tooltip-arrow::before {
            border-top-color: #000;
        }

        .tooltip.bs-tooltip-bottom .tooltip-arrow::before {
            border-bottom-color: #000;
        }

        .tooltip.bs-tooltip-start .tooltip-arrow::before {
            border-left-color: #000;
        }

        .tooltip.bs-tooltip-end .tooltip-arrow::before {
            border-right-color: #000;
        }
        .select2-container {
            width: 100% !important;
            font-family: 'Public Sans', sans-serif;
            font-size: 15px;
            line-height: 1.4;
        }

        /* Select2 binnen Bootstrap input-group — flex-child gedrag herstellen.
           Probleem: de regel hierboven zet `.select2-container` op
           `width: 100% !important`, wat binnen een input-group de buurelementen
           (btn / input-group-text / form-control) op een nieuwe regel duwt.
           De select2-bootstrap-5-theme integreert wél met input-groups, maar
           heeft `flex: 1 1 auto; width: 1%` nodig op de container — die rule
           wordt anders door onze !important overruled.

           Border-radius: select2 wraps het `<select>` in een SPAN die NA de
           hidden select in DOM komt; daardoor pakt `:first-child` niet de
           visuele eerste positie maar de hidden select. We gebruiken
           sibling-selectors (`~`) en `:has()` om de visuele positie te
           bepalen — `:has()` heeft brede support sinds Chrome 105 / Safari
           15.4 / Firefox 121 (eind 2023+).

           Resultaat: select2 in input-group lijnt als een normale .form-select
           op één rij naast btn/input-group-text, met vlakke hoeken aan de
           zijde waar 'ie aansluit. */
        .input-group > .select2-container {
            flex: 1 1 auto;
            width: 1% !important;
        }
        /* Reset radius op `var(--orbit-radius)` met hogere specificity dan de
           generieke `.select2-container .select2-selection` rule hieronder.
           Daarna overrulen de flatten-rules ALLEEN de zijde die echt aansluit
           op een buurelement (btn / input-group-text / form-control). */
        .input-group > .select2-container .select2-selection {
            border-radius: var(--orbit-radius);
        }
        .input-group > .select2-container:has(~ .btn) .select2-selection,
        .input-group > .select2-container:has(~ .input-group-text) .select2-selection,
        .input-group > .select2-container:has(~ .form-control) .select2-selection,
        .input-group > .select2-container:has(~ .form-select) .select2-selection {
            border-top-right-radius: 0;
            border-bottom-right-radius: 0;
        }
        /* Left-flatten: select2 PRECEDED by een buurelement. De
           `:not(.select2-hidden-accessible)` exclusion is cruciaal — de
           originele `<select class="form-select">` blijft na select2-init
           in de DOM staan (verborgen via `display:none`, met extra class
           `select2-hidden-accessible`) en zou anders ELKE select2 binnen
           input-group als "preceded by form-select" matchen → linker hoeken
           ten onrechte plat. Zonder de exclusion krijgt elk select2-veld in
           input-group flat-left, ook als 'ie het leftmost element is. */
        .input-group > .btn ~ .select2-container .select2-selection,
        .input-group > .input-group-text ~ .select2-container .select2-selection,
        .input-group > .form-control:not(.select2-hidden-accessible) ~ .select2-container .select2-selection,
        .input-group > .form-select:not(.select2-hidden-accessible) ~ .select2-container .select2-selection {
            border-top-left-radius: 0;
            border-bottom-left-radius: 0;
        }
        /* Select2 selection-radius matching project tokens.
           `.form-control` en `.form-select` zijn elders ingesteld op
           `var(--orbit-radius)` (zie §form-radius hierboven, regel ~943).
           De bootstrap-5-theme + default-theme van select2 gebruiken zelf
           Bootstrap-default 0.375rem (single) of 4px (multi). Hier
           consolideren we beide varianten op één token zodat select2 visueel
           niet uit de toon valt naast normale inputs/selects.

           Specificity-noot: de specifieke rules per theme (bv.
           `.select2-container--default .select2-selection--multiple`) hebben
           drie classes dus winnen van een korte `.select2-selection`-rule.
           Vandaar de uitgebreide selector-list met alle theme-varianten. */
        .select2-container .select2-selection,
        .select2-container--default .select2-selection--single,
        .select2-container--default .select2-selection--multiple,
        .select2-container--bootstrap-5 .select2-selection,
        .select2-container--bootstrap-5 .select2-selection--single,
        .select2-container--bootstrap-5 .select2-selection--multiple {
            border-radius: var(--orbit-radius);
        }

        .select2-container--default .select2-selection--multiple {
            min-height: 42px;
            padding: 4px 8px;
            border: 1px solid rgba(26, 49, 80, 0.25);
            background-color: #ffffff;
        }

        .select2-container--default.select2-container--focus
        .select2-selection--multiple {
            border-color: var(--orbit-primary-deep);
        }

        .select2-search--inline .select2-search__field {
            margin: 0;
            padding: 0;
            font-family: 'Public Sans', sans-serif;
            font-size: 16px;
            vertical-align: middle;
        }

        .select2-dropdown {
            border-radius: var(--orbit-radius);
            border: 1px solid rgba(26, 49, 80, 0.25);
        }
        .select2-results__option {
            padding: 8px 12px;
            font-size: 15px;
            color: var(--orbit-primary-deep);
        }
        .select2-results__option--highlighted {
            background-color: rgba(26, 49, 80, 0.08) !important;
            color: var(--orbit-primary-deep) !important;
        }
        .select2-results__option--selected {
            background-color: rgba(26, 49, 80, 0.08) !important;
            color: var(--orbit-primary-deep) !important;
        }
        .select2-results__option[aria-selected="true"] {
            background-color: rgba(26, 49, 80, 0.16) !important;
            color: var(--orbit-primary-deep) !important;
        }
        .select2-selection__rendered {
            display: flex;
            align-items: center;
            flex-wrap: wrap;
            gap: 6px;
        }
        /* Legacy choice/remove styling voor de oude select2 --default theme.
           Gescoped op .select2-container--default zodat de --bootstrap-5 theme
           z'n eigen Orbit-styling uit §"Select2 multi-select choice pills"
           hieronder ongestoord kan toepassen (lichte pill + zichtbaar kruisje
           met danger-tint hover). Zonder deze scoping winnen de !important-
           regels van de --bootstrap-5 styling en blijft het kruisje wit-op-
           wit onleesbaar. */
        .select2-container--default .select2-selection__choice {
            background:var(--orbit-primary)!important;
            border: 0!important;
            font-size: 15px;
            font-weight: 500;
            color: #fff!important;
            padding-left:15px!important;
        }
        .select2-container--default .select2-selection__choice__remove {
            font-weight: 700;
            opacity: 0.7;
            padding-left:5px!important;
            padding-top:1px!important;
            color: #fff!important;
            background:none;
            border: 0!important;
        }
        .select2-container--default .select2-selection__choice__remove:hover {
            opacity: 1;
            background:none!important;
        }

        /* HostFact product selector – Bootstrap select match */
        .hostfact-product-select + .select2-container--default .select2-selection--single,
        .hostfact-debtor-select + .select2-container--default .select2-selection--single {
            height: calc(1.5em + 0.75rem + 2px);
            padding: 0.375rem 2.25rem 0.375rem 0.75rem;
            font-size: 1rem;
            font-weight: 400;
            line-height: 1.5;
            background-color: #ffffff;
            background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");
            background-repeat: no-repeat;
            background-position: right 0.75rem center;
            background-size: 16px 12px;
            border: 1px solid var(--helios-surface-selected);
            border-radius: 10px;
            appearance: none;
        }

        .hostfact-product-select + .select2-container--default .select2-selection--single .select2-selection__rendered,
        .hostfact-debtor-select + .select2-container--default .select2-selection--single .select2-selection__rendered {
            padding: 0;
            line-height: 1.5;
            color: var(--helios-text);
        }

        .hostfact-product-select + .select2-container--default .select2-selection--single .select2-selection__placeholder,
        .hostfact-debtor-select + .select2-container--default .select2-selection--single .select2-selection__placeholder {
            color: var(--helios-muted);
        }

        .hostfact-product-select + .select2-container--default .select2-selection--single .select2-selection__arrow,
        .hostfact-debtor-select + .select2-container--default .select2-selection--single .select2-selection__arrow {
            display: none;
        }

        .hostfact-product-select + .select2-container .select2-dropdown,
        .hostfact-debtor-select + .select2-container .select2-dropdown {
            border: 1px solid var(--helios-surface-selected);
            border-radius: 0.375rem;
            box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
        }

        .hostfact-product-select + .select2-container .select2-results__option,
        .hostfact-debtor-select + .select2-container .select2-results__option {
            padding: 0.375rem 0.75rem;
            font-size: 1rem;
        }

        #sidebar .helios-segmented .btn {
            background-color: transparent;
            color: rgba(255, 255, 255, 0.75);
            border-color: rgba(255, 255, 255, 0.14)!important;
            font-weight: 500;
        }
        #sidebar .helios-segmented .btn.is-selected {
            background-color: rgba(255, 255, 255, 0.14);
            color: #ffffff;
            border-color: rgba(255, 255, 255, 0.25);
            font-weight: 600;
        }
        #sidebar .helios-segmented .btn:not(.is-selected):hover {
            background-color: rgba(255, 255, 255, 0.08);
            color: #ffffff;
        }
        @media (max-width: 767.98px) {
            html, body {
                height:auto
            }
            .server-card {
                margin-bottom: 0 !important;
            }
            .device-list-item {
                padding: .5rem .75rem;
                border-bottom: 1px solid var(--bs-border-color);
            }
            label.btn-outline-secondary.is-selected,
            label.btn-outline-secondary.is-selected:focus,
            label.btn-outline-secondary.is-selected:hover {
                background-color: var(--helios-muted);
                border-color: var(--helios-muted);
                color: #ffffff;
            }
            .chart-container {
                height: 300px;
            }
            .timeline {
                    padding-left: 20px;
                }
                .timeline::before {
                    left: 10px;
                }
                .timeline-marker {
                    width: 0px;
                }
                .timeline-dot {
                    left: -14px;
                    top: 5px;
                }
                .timeline-content > .d-flex {
                    flex-direction: column;
                    align-items: flex-start !important;
                    gap: 0.5rem;
                }
                .timeline-content .btn-group {
                    width: 100%;
                    justify-content: flex-start;
                }
                .timeline-content .btn-group .btn {
                    width: auto;
                }
                .card-body,
                .card-body-update {
                    padding: 0.75rem !important;
                }
                .btn.rounded-pill,
                .btn-outline-secondary.rounded-pill {
                    width: 100%;
                }
                .nav-pills .nav-link {
                    padding: 0.5rem 0.75rem;
                }
        }
        @media (max-width: 575.98px) {
            .nav.nav-pills .nav-link {
                padding-left: .75rem;
                padding-right: .75rem;
                font-size: 14px;
            }
        }

        /* ────────────────────────────────────────────────────────────
           Tables inside cards — no double border.
           Card already provides outer border; the table only needs
           internal row separators. Applies to Bootstrap .table-bordered
           and to default .table inside any .card.
           ──────────────────────────────────────────────────────────── */
        /* Globale fix: Bootstrap zet `border-bottom-width` op td/th
           maar GEEN border-color → cellen vallen terug op currentColor
           (= tekstkleur), wat bijna-zwarte row-separators oplevert in
           light mode. Forceer hier de juiste themabewuste variabele. */
        .table > :not(caption) > * > * {
            border-color: var(--bs-table-border-color, var(--bs-border-color));
        }

        /* ────────────────────────────────────────────────────────────
           Globale tabel-typografie (light + dark identiek).
           Header: uppercase label-stijl. Cells: iets luchtiger padding.
           Eerste body-rij zonder dubbele top-border tegen de header.
           ──────────────────────────────────────────────────────────── */
        .table > thead th {
            font-weight: 600;
            font-size: 0.78rem;
            letter-spacing: 0.04em;
            text-transform: uppercase;
            border-bottom-width: 1px;
        }
        .table > :not(caption) > * > * {
            padding-top: 0.65rem;
            padding-bottom: 0.65rem;
        }
        .table > tbody > tr:first-child > * {
            border-top: 0;
        }

        /* ────────────────────────────────────────────────────────────
           Default mobiele verticale gap voor card-rows.
           Op <768px krijgt elke .row standaard --bs-gutter-y: 1rem.
           Rows met een g-X of gy-X utility worden uitgesloten zodat
           expliciete keuzes blijven gelden.
           ──────────────────────────────────────────────────────────── */
        @media (max-width: 767.98px) {
            .row:not([class*="g-"]):not([class*="gy-"]) {
                --bs-gutter-y: 1rem;
            }
        }
        /* ────────────────────────────────────────────────────────────
           Tabellen in cards: GEEN extra styling.
           De card-body padding lijnt de tabel uit met de card-header.
           Tabellen gebruiken Bootstrap default row-separators
           (themabewust via --bs-table-border-color, zie regel hierboven).
           ──────────────────────────────────────────────────────────── */

        /* ================================================================
           Counter cards — tpl/counter-cards.php partial (simple variant).
           Hergebruikt --orbit-stat-card-* tokens (light + dark via cascade,
           main.css :root + [data-theme="dark"] block). Geen nieuwe tokens.

           Structuur: outer .counter-card (border + radius) + inner
           .counter-card-inner (tinted bg panel) + optional tooltip.

           Scope: simple variant only. Advanced variant (met Δ-indicator
           footer + button-tooltip, stijl shortener/index.php) komt apart.
           ================================================================ */
        .counter-card {
            /* Flex-column zodat .counter-card-inner kan groeien (flex:1) en een
               optionele .counter-card-footer (advanced variant) altijd onderaan
               de kaart plakt — ook wanneer buurkaarten in dezelfde rij meer
               content hebben. Voorheen 'block': de footer zweefde dan net boven
               de onderkant bij ongelijke kaarthoogtes (bv. backup → statistieken,
               slaagkans-tegel zonder secondary-regel). */
            display: flex;
            flex-direction: column;
            height: 100%;
            border: 1px solid var(--bs-border-color);
            border-radius: var(--orbit-radius, 10px);
            background-color: var(--bs-card-bg);
            text-decoration: none;
            /* --helios-text is Orbit's canonical theme-aware text-token
               (#212529 light, #e6eaf0 dark). --bs-body-color is statisch
               #2D3F5A en heeft geen dark-override → gaf onleesbare
               donker-blauwe tekst op dark card-bg. Zie §9 PROJECT_CONTEXT
               "contrast-claims zonder browser-verificatie". */
            color: var(--helios-text);
            overflow: hidden;
            box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
            transition: border-color 0.15s ease-out,
                        box-shadow 0.15s ease-out,
                        transform 0.15s ease-out;
        }
        /* Hover-uniform: lift op alle counter-cards ongeacht clickability.
           Consistency-first beleid (user-keuze). Cursor-pointer + focus-outline
           blijven exclusief voor .counter-card-clickable als clickability-hint. */
        .counter-card:hover,
        .counter-card:focus-visible {
            color: var(--helios-text);
            text-decoration: none;
            transform: translateY(-1px);
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.08);
        }
        .counter-card-clickable {
            cursor: pointer;
        }
        .counter-card-clickable:focus-visible {
            outline: 2px solid color-mix(in srgb, var(--bs-primary) 45%, transparent);
            outline-offset: 2px;
        }

        .counter-card-inner {
            position: relative;
            /* Vult de resterende kaarthoogte zodat de footer (advanced variant)
               onderaan plakt i.p.v. te zweven. Bij default/transparent surface
               loopt de role-tint hierdoor ook netjes door tot de onderkant. */
            flex: 1 1 auto;
            padding: 1rem;
            text-align: center;
        }

        .counter-card-value {
            font-size: 1.5rem;
            font-weight: 600;
            line-height: 1.2;
            /* Neutraal cijfer — role-signal komt van card-bg-tint en
               (advanced variant) trend-pill. --helios-text is Orbit's
               canonical theme-aware text-token (zie .counter-card hierboven
               voor uitleg). Overschreven voor zero-state (muted) hieronder.
               Per-role value-color overrides zijn bewust verwijderd: zie
               §7 PROJECT_CONTEXT.md "role-color distributie-regel". */
            color: var(--helios-text);
        }


        .counter-card-label {
            margin-top: 0.15rem;
            margin-bottom: 0;
            font-size: 0.875rem;
            color: var(--bs-secondary-color);
            line-height: 1.2;
        }

        .counter-card-label-context {
            font-size: 0.9em;
            opacity: 0.85;
            margin-bottom: 0;
            padding-bottom: 0;
            line-height: 1.1;
        }

        .counter-card-tooltip {
            position: absolute;
            top: 0.5rem;
            right: 0.5rem;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            width: 1.25rem;
            height: 1.25rem;
            color: var(--bs-secondary-color);
            opacity: 0.6;
            cursor: help;
            transition: opacity 0.15s ease-out;
        }
        .counter-card-tooltip:hover,
        .counter-card-tooltip:focus-visible {
            opacity: 1;
        }
        .counter-card-tooltip > i[data-lucide],
        .counter-card-tooltip > svg {
            width: 14px;
            height: 14px;
        }

        /* Status-badge — deelt top-right slot met tooltip (mutually exclusive).
           State-kleuren hergebruiken chip-tokens uit alerts/badges cyclus
           (deel 1), muted krijgt een rgba fallback (geen eigen chip-token).
           Pill-vorm (radius 999px) contrasteert met ronde info-icon voor
           visuele differentiatie. */
        .counter-card-status {
            position: absolute;
            top: 0.5rem;
            right: 0.5rem;
            font-size: 0.6875rem;
            font-weight: 500;
            padding: 0.1875rem 0.5rem;
            border-radius: 999px;
            line-height: 1;
            border: 1px solid transparent;
            white-space: nowrap;
        }

        .counter-card-status-active {
            background-color: var(--x-status-info-chip-bg);
            border-color: var(--x-status-info-chip-border);
            color: var(--x-status-info-chip-ink);
        }

        .counter-card-status-success {
            background-color: var(--x-status-success-chip-bg);
            border-color: var(--x-status-success-chip-border);
            color: var(--x-status-success-chip-ink);
        }

        .counter-card-status-danger {
            background-color: var(--x-status-danger-chip-bg);
            border-color: var(--x-status-danger-chip-border);
            color: var(--x-status-danger-chip-ink);
        }

        .counter-card-status-muted {
            background-color: rgba(var(--bs-body-color-rgb), 0.06);
            border-color: rgba(var(--bs-body-color-rgb), 0.12);
            color: var(--bs-secondary-color);
        }

        /* Secondary descriptive note — subtieler dan label, staat eronder.
           Voor context die niet past in label_context (haakjes-suffix is
           kort; note is voor "Share of total: 45%"-achtige zinnen).
           Class heet .counter-card-note, niet -secondary, om collision
           met de role=secondary modifier class te voorkomen (zie §9
           PROJECT_CONTEXT "Orbit data-theme + Bootstrap tokens"). Gebruikt
           --helios-muted (theme-aware) ipv --bs-secondary-color (niet
           theme-aware in Orbit's data-theme architectuur). */
        .counter-card-note {
            font-size: 0.8125rem;
            color: var(--helios-muted);
            margin-top: 0.125rem;
        }

        /* Top-right secondary — compacte variant van .counter-card-note die
           geen verticale ruimte kost. Gerendered ipv tooltip/status_badge in
           dezelfde slot wanneer counter-config `secondary_position: top-right`
           heeft. Tabular-nums voor cijfer-uitlijning over meerdere tegels. */
        .counter-card-meta-tr {
            position: absolute;
            top: 0.5rem;
            right: 0.6rem;
            font-size: 0.75rem;
            color: var(--helios-muted);
            line-height: 1;
            white-space: nowrap;
            font-variant-numeric: tabular-nums;
            letter-spacing: -0.005em;
        }

        /* Role modifiers — alleen border + inner-bg via tokens.
           Value-cijfer kleur is sinds V2-redesign body-color (zie
           .counter-card-value rule hierboven). Role-signal concentreert
           zich op bg-tint + (advanced variant) trend-pill. */
        .counter-card-info {
            border-color: var(--orbit-stat-card-info-border);
        }
        .counter-card-info .counter-card-inner {
            background-color: var(--orbit-stat-card-info-bg);
        }

        .counter-card-success {
            border-color: var(--orbit-stat-card-success-border);
        }
        .counter-card-success .counter-card-inner {
            background-color: var(--orbit-stat-card-success-bg);
        }

        .counter-card-warning {
            border-color: var(--orbit-stat-card-warning-border);
        }
        .counter-card-warning .counter-card-inner {
            background-color: var(--orbit-stat-card-warning-bg);
        }

        .counter-card-danger {
            border-color: var(--orbit-stat-card-danger-border);
        }
        .counter-card-danger .counter-card-inner {
            background-color: var(--orbit-stat-card-danger-bg);
        }

        .counter-card-primary {
            border-color: var(--orbit-stat-card-primary-border);
        }
        .counter-card-primary .counter-card-inner {
            background-color: var(--orbit-stat-card-primary-bg);
        }

        /* Secondary deelt visueel met primary (zelfde blauw-family, geen
           eigen tokens). Alternatief toekomst: eigen --orbit-stat-card-
           secondary-* tokens als semantic onderscheid nodig wordt. */
        .counter-card-secondary {
            border-color: var(--orbit-stat-card-primary-border);
        }
        .counter-card-secondary .counter-card-inner {
            background-color: var(--orbit-stat-card-primary-bg);
        }

        /* Neutral — gebruikt voor zero-state én expliciete neutrale role */
        .counter-card-neutral,
        .counter-card-zero {
            border-color: var(--orbit-stat-card-neutral-border);
        }
        .counter-card-neutral .counter-card-inner,
        .counter-card-zero .counter-card-inner {
            background-color: var(--orbit-stat-card-neutral-bg);
        }
        .counter-card-neutral .counter-card-value,
        .counter-card-zero .counter-card-value {
            /* --helios-muted (theme-aware: #6c757d light, #94a3b8 dark)
               ipv --bs-secondary-color (niet theme-aware in Orbit).
               Zie §9 PROJECT_CONTEXT "Orbit data-theme + Bootstrap tokens". */
            color: var(--helios-muted);
        }

        /* Solid surface-variant — opt-in via $counterSurface='solid' op het
           counter-cards partial. Bedoeld voor status-overzichten met een
           "rijkere" look (monitoring/index, stats/index).

           Verschillen t.o.v. default:
             - Inner-panel: geen role-tint (transparent) — vol-vlak op de
               theme-aware card-bg, dus echt solide ipv subtiel-getint
             - Border: 1px in role-color (zachte tinted-border) ipv neutrale
               grid-color → het 'gekleurde randje'
             - Optionele icon-tile linksboven (.counter-card-icon)
             - Value-font: 1.75rem (was 1.5rem) — iets prominenter
             - Hover: extra shadow-tier voor 'richer' feel  */
        .counter-card-solid {
            position: relative;
            border-color: var(--orbit-stat-card-neutral-border);
            border-width: 1px;
        }
        .counter-card-solid.counter-card-info    { border-color: var(--orbit-stat-card-info-border); }
        .counter-card-solid.counter-card-success { border-color: var(--orbit-stat-card-success-border); }
        .counter-card-solid.counter-card-warning { border-color: var(--orbit-stat-card-warning-border); }
        .counter-card-solid.counter-card-danger  { border-color: var(--orbit-stat-card-danger-border); }
        .counter-card-solid.counter-card-primary,
        .counter-card-solid.counter-card-secondary { border-color: var(--orbit-stat-card-primary-border); }
        .counter-card-solid.counter-card-neutral,
        .counter-card-solid.counter-card-zero    { border-color: var(--orbit-stat-card-neutral-border); }

        /* Inner-panel is solid (geen tint) — overschrijft alle role-tinten */
        .counter-card-solid .counter-card-inner {
            background-color: transparent !important;
        }
        .counter-card-solid .counter-card-value {
            font-size: 1.75rem;
        }
        .counter-card-solid:hover,
        .counter-card-solid:focus-visible {
            box-shadow: 0 6px 18px rgba(0, 0, 0, 0.10);
        }

        /* Onderwerp-icon linksboven — kleine getinte tile in role-color.
           Decoratief; absolute-positioned zodat hij niet in de vertical-flow
           zit. Op zero/neutral een muted-tone. */
        .counter-card-solid .counter-card-icon {
            position: absolute;
            top: 0.875rem;
            left: 0.875rem;
            width: 28px;
            height: 28px;
            border-radius: var(--orbit-radius, 10px);
            display: inline-flex;
            align-items: center;
            justify-content: center;
            background-color: var(--orbit-stat-card-neutral-bg, #f1f3f5);
            color: var(--helios-muted, #6c757d);
            pointer-events: none;
        }
        .counter-card-solid .counter-card-icon i {
            width: 14px !important;
            height: 14px !important;
        }
        .counter-card-solid.counter-card-info    .counter-card-icon { background-color: var(--orbit-stat-card-info-bg);    color: var(--orbit-chart-info, #8ab2d2); }
        .counter-card-solid.counter-card-success .counter-card-icon { background-color: var(--orbit-stat-card-success-bg); color: var(--orbit-chart-success, #198754); }
        .counter-card-solid.counter-card-warning .counter-card-icon { background-color: var(--orbit-stat-card-warning-bg); color: var(--orbit-chart-warning, #d89b00); }
        .counter-card-solid.counter-card-danger  .counter-card-icon { background-color: var(--orbit-stat-card-danger-bg);  color: var(--orbit-chart-danger,  #dc3545); }
        .counter-card-solid.counter-card-primary  .counter-card-icon,
        .counter-card-solid.counter-card-secondary .counter-card-icon { background-color: var(--orbit-stat-card-primary-bg); color: var(--orbit-chart-primary, #254672); }

        /* ================================================================
           Counter-cards — mobiele leesbaarheid (≤575.98px, phone-breakpoint).

           Probleem: op smalle 2-up kolommen (≈150-165px op een telefoon)
           botste de gecentreerde .counter-card-value met het absoluut-
           gepositioneerde solid-icon (top-left, 28px). Lange waarden —
           bytes ("123,45 MB"), duur ("1u 23m"), grote tellingen,
           percentages — schoven onder het icoon: "cijfers verdwijnen
           achter iconen". De top-right slot (tooltip/status/meta) kon de
           value op zijn beurt rechts raken.

           Fix (mobiel-only; desktop blijft 100% ongewijzigd):
             - Solid-icon uit de absolute corner → terug in de flow, op een
               eigen regel links-boven. De value komt daardoor altijd op een
               lagere regel te staan en kan nooit meer overlappen — ongeacht
               de waarde-lengte of een gelijktijdige top-right badge/tooltip.
             - Kleinere value-font + tabular-nums + overflow-wrap, zodat
               lange waarden netjes binnen de smalle kolom passen i.p.v. uit
               te lijnen achter een icoon of de tegel te verbreden.

           Geldt voor ALLE solid counter-cards (≈40 views), niet alleen de
           backup-tabs — het is een gedeeld component (tpl/counter-cards.php).
           ================================================================ */
        @media (max-width: 575.98px) {
            .counter-card-inner {
                padding: 0.875rem 0.75rem;
            }
            .counter-card-value {
                font-size: 1.25rem;
                font-variant-numeric: tabular-nums;
                overflow-wrap: anywhere;
            }
            .counter-card-solid .counter-card-value {
                font-size: 1.375rem;
            }
            /* Icon van decoratieve absolute-corner → in-flow blok links-boven
               op een eigen regel. text-align:center op de inner laat de value
               eronder gecentreerd; het icon-blok (vaste 32px) blijft links. */
            .counter-card-solid .counter-card-icon {
                position: static;
                display: flex;
                width: 32px;
                height: 32px;
                margin: 0 0 0.45rem 0;
            }
            .counter-card-solid .counter-card-icon i {
                width: 16px !important;
                height: 16px !important;
            }
            /* #tab-stats inner spreidt content normaal met space-between; op
               mobiel met het nu in-flow icon zou dat een loze gap onder het
               icoon geven. Top-uitlijnen laat icon → value → label netjes
               aansluiten (kaarthoogte is op mobiel toch auto). */
            #tab-stats .counter-card-inner {
                justify-content: flex-start;
            }
            /* Advanced-footer (Δ-indicator) compacter op smalle kolommen. */
            .counter-card-footer {
                padding: 0.75rem;
            }
        }

        /* #tab-stats (shortener-link-stats + server-monitoring-stats): spreidt
           de inner-content verticaal (space-between) i.p.v. de component-default
           (boven-uitgelijnd). De flex-column-basis + gelijke kaarthoogte + footer-
           pinning komen nu van de .counter-card / .counter-card-inner component-
           rules hierboven — deze rule voegt enkel de space-between-spreiding toe. */
        #tab-stats .counter-card-inner {
            display: flex;
            flex-direction: column;
            justify-content: space-between;
        }

        /* Generieke mini-sparkline placeholder. Gebruikt door counter-cards
           (sparkline-config) én metrics-panel (rij-viz). ApexCharts-init kan
           licht overspill geven onderaan; klein offset compenseert dat zonder
           layout-shift. */
        .orbit-sparkline {
            display: inline-block;
            width: 100%;
            min-height: 36px;
            margin-left: -4px;
            margin-right: -4px;
        }
        /* Fail-state — JS markeert placeholder met deze class als JSON-parse of
           ApexCharts-init faalt, zodat de gebruiker niet naar een onverklaard leeg
           plekje kijkt. Subtiele dashed mid-line communiceert "data niet beschikbaar". */
        .orbit-sparkline-failed {
            border-top: 1px dashed var(--bs-border-color, #dee2e6);
            margin-top: 1.25rem;
            min-height: 1px;
            height: 1px;
            opacity: 0.5;
        }
        .counter-card-byline {
            font-size: 0.75rem;
            line-height: 1.2;
        }

        /* ============================================================
           Mini-stats — compacte secundaire metric-strip (tpl/mini-stats.php)
           ------------------------------------------------------------
           Rustiger tegenhanger van de counter-cards: kleine horizontale
           kaartjes (icon-tile + value + label) in een 6-up rij. Draagt de
           vele ondersteunende cijfers (risk, efficiency, integriteit) zodat
           ze niet als 3-4 ongelijke counter-card-grids onder elkaar staan.

           Self-contained: leest role-tints uit de bestaande
           `--orbit-stat-card-{role}-bg|border|value` + `--orbit-chart-{role}`
           tokens (één plek voor role-kleuren, theme-aware in light + dark).
           Default-canon = neutral; alleen actie-vereisende waarden krijgen een
           role-kleur (failed>0 → danger, overdue>0 → warning, ...).
        ============================================================ */
        .mini-stat {
            display: flex;
            align-items: center;
            gap: 0.625rem;
            height: 100%;
            padding: 0.625rem 0.75rem;
            background-color: var(--bs-card-bg);
            border: 1px solid var(--orbit-stat-card-neutral-border, #e3e8ef);
            border-radius: var(--orbit-radius, 10px);
            /* Zelfde subtiele shadow als .counter-card → één visuele familie. */
            box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
        }
        .mini-stat-icon {
            flex-shrink: 0;
            width: 30px;
            height: 30px;
            border-radius: var(--orbit-radius, 10px);
            display: inline-flex;
            align-items: center;
            justify-content: center;
            background-color: var(--orbit-stat-card-neutral-bg, #f1f3f5);
            color: var(--helios-muted, #6c757d);
        }
        .mini-stat-icon i { width: 16px !important; height: 16px !important; }
        .mini-stat-body {
            display: flex;
            flex-direction: column;
            min-width: 0;
            line-height: 1.15;
        }
        .mini-stat-value {
            /* Weight + neutrale kleur identiek aan .counter-card-value (600,
               --helios-text). Role-signaal komt — net als bij de grote solid-
               kaarten — van de border + de getinte icon-tile, NIET van de
               cijferkleur (role-color distributie-regel, zie PROJECT_CONTEXT). */
            font-size: 1.125rem;
            font-weight: 600;
            font-variant-numeric: tabular-nums;
            color: var(--helios-text);
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }
        .mini-stat-label {
            /* Lichter, sentence-case — weight in lijn met .counter-card-label.
               Kleur via --helios-muted (theme-aware: #6c757d light → #94a3b8
               dark). --bs-secondary-color heeft GEEN dark-override en blijft
               anders donker op dark card-bg (zelfde canon als counter-card-note
               + de --helios-text-fix). */
            font-size: 0.75rem;
            font-weight: 400;
            color: var(--helios-muted);
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }
        /* Role-varianten — border + getinte icon-tile uit de tokens. Zelfde
           mapping als .counter-card-solid zodat de twee strips visueel één
           familie vormen. De value-kleur blijft bewust neutraal (zie boven). */
        .mini-stat-info    { border-color: var(--orbit-stat-card-info-border); }
        .mini-stat-success { border-color: var(--orbit-stat-card-success-border); }
        .mini-stat-warning { border-color: var(--orbit-stat-card-warning-border); }
        .mini-stat-danger  { border-color: var(--orbit-stat-card-danger-border); }
        .mini-stat-primary,
        .mini-stat-secondary { border-color: var(--orbit-stat-card-primary-border); }

        .mini-stat-info    .mini-stat-icon { background-color: var(--orbit-stat-card-info-bg);    color: var(--orbit-chart-info, #8ab2d2); }
        .mini-stat-success .mini-stat-icon { background-color: var(--orbit-stat-card-success-bg); color: var(--orbit-chart-success, #198754); }
        .mini-stat-warning .mini-stat-icon { background-color: var(--orbit-stat-card-warning-bg); color: var(--orbit-chart-warning, #d89b00); }
        .mini-stat-danger  .mini-stat-icon { background-color: var(--orbit-stat-card-danger-bg);  color: var(--orbit-chart-danger,  #dc3545); }
        .mini-stat-primary  .mini-stat-icon,
        .mini-stat-secondary .mini-stat-icon { background-color: var(--orbit-stat-card-primary-bg); color: var(--orbit-chart-primary, #254672); }

        @media (max-width: 575.98px) {
            .mini-stat { padding: 0.5rem 0.625rem; gap: 0.5rem; }
            .mini-stat-icon { width: 26px; height: 26px; }
            .mini-stat-value { font-size: 1rem; }
        }

        /* ============================================================
           Helios filter-tiles
           ------------------------------------------------------------
           Single-row button-chip voor client-side filtering. Body font-
           size voor alle tile-content (label + cijfers) zodat de filter-
           rij visueel gelijk-gewicht heeft als de rest van de form.

           Layout per tile (single row, count right-aligned):
             ┌──────────────────────────────────────────┐
             │ [icon]  Naam (truncate)     12 · 4 vrij  │
             └──────────────────────────────────────────┘

           Self-contained styling: leest border/role-tints uit de bestaande
           `--orbit-stat-card-*` tokens (één plek voor role-kleuren) maar
           erft niet de counter-card-stat-tile markup of typografie.

           Section-heading volgt het Orbit field-label canon
           (`text-uppercase small text-muted`) zoals CODE / LICENTIE-IP in
           detail-views — geen icon, zelfde grootte als veldnaam-aanduidingen.

           Eerste use-case: licentie-type-filter op licenses/index.
        ============================================================ */
        .helios-filter-tiles-section {
            margin-bottom: 0.5rem;
        }
        .helios-filter-tiles-section:last-child {
            margin-bottom: 0;
        }

        .helios-filter-tile {
            /* Native <button> reset + chip-shell */
            appearance: none;
            display: flex;
            align-items: center;
            gap: 0.625rem;
            width: 100%;
            padding: 0.5rem 0.75rem;
            text-align: left;
            font: inherit;
            color: var(--helios-text);
            cursor: pointer;
            background-color: var(--bs-card-bg, #fff);
            border: 1px solid var(--orbit-stat-card-neutral-border, var(--bs-border-color));
            border-radius: var(--orbit-radius, 10px);
            box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
            transition: border-color 0.15s ease-out,
                        box-shadow 0.15s ease-out,
                        transform 0.15s ease-out,
                        background-color 0.15s ease-out;
        }
        .helios-filter-tile:hover {
            transform: translateY(-1px);
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.08);
        }
        .helios-filter-tile:focus-visible {
            outline: 2px solid color-mix(in srgb, var(--bs-primary) 45%, transparent);
            outline-offset: 2px;
        }

        /* Role-tinted borders — match counter-card-solid kleuren zodat
           de tile visueel familie blijft van de status-counters bovenaan. */
        .helios-filter-tile-role-info    { border-color: var(--orbit-stat-card-info-border); }
        .helios-filter-tile-role-success { border-color: var(--orbit-stat-card-success-border); }
        .helios-filter-tile-role-warning { border-color: var(--orbit-stat-card-warning-border); }
        .helios-filter-tile-role-danger  { border-color: var(--orbit-stat-card-danger-border); }
        .helios-filter-tile-role-primary,
        .helios-filter-tile-role-secondary { border-color: var(--orbit-stat-card-primary-border); }

        /* Head — icon + label, expandeert; label truncate'd */
        .helios-filter-tile-head {
            display: flex;
            align-items: center;
            gap: 0.5rem;
            flex: 1 1 auto;
            min-width: 0;
        }
        /* Icon-tile — visueel identiek aan helios-entity-tile-sm in tabellen
           (22px, subtiele border-radius, soft surface-hover bg, overflow-hidden
           clipt image-fill). Houdt de filter-rij visueel uniform met de tabel
           eronder waar dezelfde icon-style gebruikt wordt. */
        .helios-filter-tile-icon {
            flex: 0 0 22px;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            width: 22px;
            height: 22px;
            border-radius: 5px;
            background-color: var(--helios-surface-hover, rgba(0, 0, 0, .05));
            color: var(--helios-text, var(--bs-body-color));
            overflow: hidden;
        }
        .helios-filter-tile-icon img {
            width: 100%;
            height: 100%;
            object-fit: contain;
            padding: 2px;          /* kleine inset zodat logo-edges niet aan de tile-rand kleven */
        }
        .helios-filter-tile-icon i {
            width: 14px !important;
            height: 14px !important;
            color: var(--helios-muted, #6c757d);
        }
        /* Letter-fallback — zelfde tile-formaat, eerste letter van de label.
           Gebruikt wanneer er geen image én geen icon is (bv. een merk dat
           we nog geen logo voor hebben). */
        .helios-filter-tile-letter {
            font-size: 0.75rem;
            font-weight: 700;
            line-height: 1;
            color: var(--helios-text);
            text-transform: uppercase;
        }
        .helios-filter-tile-label {
            flex: 1 1 auto;
            min-width: 0;
            font-size: 1rem;
            font-weight: 500;
            line-height: 1.25;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        /* Stats — total · secondary, right-aligned, small font-size (canon
           voor metadata-cijfers in de hele app). Vertical-center align met
           icon en label op de hoofdrij. */
        .helios-filter-tile-stats {
            flex: 0 0 auto;
            display: inline-flex;
            align-items: center;
            gap: 0.375rem;
            font-size: 0.875rem;
            line-height: 1.25;
            color: var(--bs-secondary-color);
            white-space: nowrap;
        }
        .helios-filter-tile-total {
            font-weight: 600;
            color: var(--helios-text);
        }
        .helios-filter-tile-sep {
            color: var(--bs-secondary-color);
            opacity: 0.5;
        }
        /* .helios-filter-tile-free krijgt zijn kleur via text-{success,warning,danger,muted} */

        /* Active-state — tinted bg in role-color + thicker border. Padding
           compenseert de border-width-shift zodat de tile niet 1px verschuift. */
        .helios-filter-tile.is-active {
            border-width: 2px;
            padding: calc(0.5rem - 1px) calc(0.75rem - 1px);
            background-color: var(--orbit-stat-card-neutral-bg, #f1f3f5);
        }
        .helios-filter-tile.is-active.helios-filter-tile-role-info    { background-color: var(--orbit-stat-card-info-bg); }
        .helios-filter-tile.is-active.helios-filter-tile-role-success { background-color: var(--orbit-stat-card-success-bg); }
        .helios-filter-tile.is-active.helios-filter-tile-role-warning { background-color: var(--orbit-stat-card-warning-bg); }
        .helios-filter-tile.is-active.helios-filter-tile-role-danger  { background-color: var(--orbit-stat-card-danger-bg); }
        .helios-filter-tile.is-active.helios-filter-tile-role-primary,
        .helios-filter-tile.is-active.helios-filter-tile-role-secondary { background-color: var(--orbit-stat-card-primary-bg); }

        /* ============================================================
           helios-pick-tile — compacte navigatie-tile voor picker-pagina's
           (vervangt het oude helios-pick-card-patroon met intro + URL).
           Tile = <a href>, geen aria-pressed; visueel: vierkant-ish met
           centered icon-tile boven, label eronder. Tweede regel (sublabel)
           optioneel voor disambiguatie. Hover lift + brand-blue border-tint
           (mirror van helios-pick-card hover-effect zodat de cultuur intact
           blijft). Gerendered door private/tpl/helios-pick-grid.php.
        ============================================================ */
        .helios-pick-tile {
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            gap: 0.5rem;
            width: 100%;
            min-height: 92px;
            padding: 0.75rem;
            text-align: center;
            text-decoration: none;
            color: var(--helios-text, var(--bs-body-color));
            background-color: var(--bs-card-bg, #fff);
            border: 1px solid var(--bs-border-color);
            border-radius: var(--orbit-radius, 10px);
            box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
            transition: border-color 0.15s ease-out,
                        box-shadow 0.15s ease-out,
                        transform 0.15s ease-out,
                        background-color 0.15s ease-out;
        }
        /* Hover/focus — mirror van .helios-filter-tile.is-active: brand-blue
           tint bg + 2px border, padding-1px compensate zodat de tile niet
           verschuift bij hover. Plus subtle lift voor affordance. */
        .helios-pick-tile:hover,
        .helios-pick-tile:focus-visible {
            color: var(--helios-text, var(--bs-body-color));
            background-color: rgba(var(--x-brand-blue-rgb, 13, 110, 253), 0.06);
            border-color: var(--x-brand-blue, var(--bs-primary));
            border-width: 2px;
            padding: calc(0.75rem - 1px);
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.08);
            transform: translateY(-1px);
            outline: none;
        }
        .helios-pick-tile:focus-visible {
            outline: 2px solid color-mix(in srgb, var(--bs-primary) 45%, transparent);
            outline-offset: 2px;
        }
        /* Icon-tile tint mee op hover voor visuele samenhang met de border. */
        .helios-pick-tile:hover .helios-pick-tile-icon,
        .helios-pick-tile:focus-visible .helios-pick-tile-icon {
            background-color: rgba(var(--x-brand-blue-rgb, 13, 110, 253), 0.12);
            color: var(--x-brand-blue-deep, var(--bs-primary));
        }
        .helios-pick-tile:hover .helios-pick-tile-icon i,
        .helios-pick-tile:focus-visible .helios-pick-tile-icon i {
            color: var(--x-brand-blue-deep, var(--bs-primary));
        }

        .helios-pick-tile-icon {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            width: 32px;
            height: 32px;
            border-radius: 6px;
            background-color: var(--helios-surface-hover, rgba(0, 0, 0, .05));
            color: var(--helios-text, var(--bs-body-color));
            overflow: hidden;
            flex-shrink: 0;
            transition: background-color 0.15s ease-out, color 0.15s ease-out;
        }
        .helios-pick-tile-icon img {
            width: 100%;
            height: 100%;
            object-fit: contain;
            padding: 3px;
        }
        .helios-pick-tile-icon i {
            width: 18px !important;
            height: 18px !important;
            color: var(--helios-text, var(--bs-body-color));
        }
        .helios-pick-tile-letter {
            font-size: 0.875rem;
            font-weight: 700;
            line-height: 1;
            color: var(--helios-text);
            text-transform: uppercase;
        }
        .helios-pick-tile-label {
            font-size: 0.875rem;
            font-weight: 600;
            line-height: 1.25;
            max-width: 100%;
            display: -webkit-box;
            -webkit-line-clamp: 2;
            -webkit-box-orient: vertical;
            overflow: hidden;
            word-break: break-word;
        }
        .helios-pick-tile-sublabel {
            font-size: 0.75rem;
            line-height: 1.2;
            color: var(--bs-secondary-color);
            max-width: 100%;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        /* ============================================================
           helios-filter-btn — segmented filter-knoppen in een filter-card
           (period/direction/type/etc.). Mobile krijgt iets ruimere
           verticale padding voor comfortabele tap-target (≥44px hoog
           samen met btn-group-sm). Gebruik op elke <button> binnen een
           filter-card btn-group: `class="btn helios-filter-btn ..."`.
           Eerder dupliceerde elke module dit als .sfq-period-opt /
           .sfq-type-opt — vervangen door deze utility class.
        ============================================================ */
        @media (max-width: 575.98px) {
            .helios-filter-btn {
                padding-top: 0.55rem;
                padding-bottom: 0.55rem;
            }
        }

        /* ============================================================
           helios-filter-offcanvas — bottom-sheet variant van een filter-
           dropdown voor mobile (<576px). Mirror van page-header offcanvas:
           header-loos, rounded-top, tap-tile items met brand-blue hover.
           Gebruik samen met `<ul class="helios-filter-oc-list">` als body
           wrapper. Eerder leefde dit als .sfq-offcanvas inline-style in
           quarantine-filter-card.php — vervangen door deze utility.
        ============================================================ */
        .helios-filter-offcanvas {
            height: auto !important;
            max-height: 75vh;
            border-top-left-radius: 1rem;
            border-top-right-radius: 1rem;
            border-top: 1px solid var(--bs-border-color);
            background-color: var(--bs-body-bg);
        }
        .helios-filter-offcanvas .offcanvas-body {
            padding: 0.5rem;
            padding-bottom: calc(0.5rem + env(safe-area-inset-bottom, 0px));
            overflow-y: auto;
        }
        .helios-filter-offcanvas .helios-filter-oc-list {
            list-style: none;
            margin: 0;
            padding: 0;
        }
        .helios-filter-offcanvas .dropdown-item {
            display: flex;
            align-items: center;
            width: 100%;
            padding: 0.875rem 0.75rem;
            margin: 2px 0;
            min-height: 3rem;
            border-radius: 0.375rem;
            font-size: 1rem;
            font-weight: 500;
            line-height: 1.4;
            white-space: normal;
        }
        .helios-filter-offcanvas .dropdown-item:hover,
        .helios-filter-offcanvas .dropdown-item:focus-visible {
            background-color: rgba(var(--x-brand-blue-rgb, 13,110,253), 0.08);
            color: var(--x-brand-blue-deep, var(--bs-primary));
            outline: none;
        }
        .helios-filter-offcanvas .dropdown-item.active {
            background-color: rgba(var(--x-brand-blue-rgb, 13,110,253), 0.12);
            color: var(--x-brand-blue-deep, var(--bs-primary));
        }
        .helios-filter-offcanvas .dropdown-divider {
            margin: 0.5rem -0.5rem;
        }
        /* Optional sticky search-row — opt-in via .helios-filter-oc-search wrapper. */
        .helios-filter-offcanvas .helios-filter-oc-search {
            padding: 0.5rem 0.75rem;
            position: sticky;
            top: 0;
            background-color: var(--bs-body-bg);
            z-index: 2;
        }

        /* ============================================================
           helios-filter-search — search-input met clear-button (×) binnen
           een filter-dropdown of -offcanvas. Gebruik:
             <li class="helios-filter-search position-sticky" style="top:0;
                 background:var(--bs-body-bg);z-index:1;">
               <input class="form-control form-control-sm helios-filter-search-input">
               <button class="btn btn-sm btn-link helios-filter-search-clear">×</button>
             </li>
           Clear-button toont alleen wanneer wrapper de `has-value` class
           krijgt (set door JS).
        ============================================================ */
        .helios-filter-search {
            position: relative;
        }
        .helios-filter-search .helios-filter-search-input {
            padding-right: 2rem;
        }
        .helios-filter-search .helios-filter-search-clear {
            position: absolute;
            top: 50%;
            right: 0.4rem;
            transform: translateY(-50%);
            display: none;
        }
        .helios-filter-search.has-value .helios-filter-search-clear {
            display: inline-flex;
        }
        /* Binnen offcanvas: clear-button extra rechts wegens grotere padding. */
        .helios-filter-offcanvas .helios-filter-search .helios-filter-search-clear {
            right: 1.1rem;
        }

        /* ============================================================
           Metrics-panel (servers/view monitoring-tab live metrics).
           Statuspage-style rij-layout: dot + label + value + viz + meta.
           Replaces de losse counter-cards + disk-progress per metric.
        ============================================================ */
        .metrics-panel-row {
            display: grid;
            grid-template-columns: 12px 96px minmax(80px, max-content) minmax(120px, 1.4fr) minmax(0, 2fr);
            column-gap: 1rem;
            align-items: center;
            padding: 0.875rem 1.25rem;
            border-bottom: 1px solid var(--bs-border-color, #e9ecef);
        }
        .metrics-panel .card-body > .metrics-panel-row:last-child {
            border-bottom: none;
        }

        /* Dots/progress-fills gebruiken `--orbit-chart-X` tokens — theme-aware
           softer than Bootstrap's vivid `--bs-X` (light: #96bd5e/#f0c36d/etc;
           dark: #b9da82/#f5b27a/etc). Past beter bij Orbit's overige UI-tinten
           in beide themes. Stat-card-tokens (--orbit-stat-card-X-value) blijven
           gereserveerd voor counter-card-VALUES. */
        .metrics-panel-dot {
            width: 10px;
            height: 10px;
            border-radius: 50%;
            display: inline-block;
            background-color: var(--orbit-chart-secondary, #6c757d);
        }
        .metrics-panel-dot-success { background-color: var(--orbit-chart-success, #96bd5e); }
        .metrics-panel-dot-warning { background-color: var(--orbit-chart-warning, #f0c36d); }
        .metrics-panel-dot-danger  { background-color: var(--orbit-chart-danger,  #dc3545); }
        .metrics-panel-dot-info    { background-color: var(--orbit-chart-info,    #8ab2d2); }
        .metrics-panel-dot-primary { background-color: var(--orbit-chart-primary, #2F6FB3); }
        .metrics-panel-dot-neutral { background-color: var(--orbit-chart-secondary, #6c757d); }

        .metrics-panel-label {
            font-weight: 600;
            font-size: 0.9375rem;
            /* --helios-text: theme-aware (light: #212529, dark: #e6eaf0).
               --bs-body-color is niet door Orbit dark-overridden → onleesbaar. */
            color: var(--helios-text, var(--bs-body-color));
        }
        .metrics-panel-value {
            font-family: var(--bs-font-monospace, monospace);
            font-weight: 600;
            font-size: 1.0625rem;
            text-align: right;
            font-variant-numeric: tabular-nums;
            color: var(--helios-text, var(--bs-body-color));
        }
        .metrics-panel-viz {
            display: flex;
            align-items: center;
            min-height: 28px;
        }
        .metrics-panel-viz .orbit-sparkline {
            min-height: 28px;
            margin: 0;
        }
        .metrics-panel-viz-empty {
            color: var(--bs-secondary-color, #6c757d);
            opacity: 0.4;
            font-size: 1.125rem;
        }
        .metrics-panel-progress {
            display: block;
            width: 100%;
            height: 6px;
            border-radius: 999px;
            background-color: var(--bs-tertiary-bg, #f1f3f5);
            overflow: hidden;
            position: relative;
        }
        .metrics-panel-progress-fill {
            display: block;
            height: 100%;
            border-radius: inherit;
            background-color: var(--orbit-chart-secondary, #6c757d);
            transition: width 0.3s ease;
        }
        /* Same `--orbit-chart-X` family als de dots — theme-aware soft tints.
           Daily-bars (uptime 30d cell) erven deze classes en zien er zachter uit
           dan met `--bs-X`. */
        .metrics-panel-progress-success { background-color: var(--orbit-chart-success, #96bd5e); }
        .metrics-panel-progress-warning { background-color: var(--orbit-chart-warning, #f0c36d); }
        .metrics-panel-progress-danger  { background-color: var(--orbit-chart-danger,  #dc3545); }
        .metrics-panel-progress-info    { background-color: var(--orbit-chart-info,    #8ab2d2); }
        .metrics-panel-progress-primary { background-color: var(--orbit-chart-primary, #2F6FB3); }

        .metrics-panel-meta {
            font-size: 0.8125rem;
            color: var(--bs-secondary-color, #6c757d);
            min-width: 0;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }

        /* Mobile: stack naar 2 rijen — header (dot + label + value) en
           footer (viz + meta) onder elkaar zodat er ruimte is voor sparkline. */
        @media (max-width: 767.98px) {
            .metrics-panel-row {
                grid-template-columns: 12px 1fr auto;
                grid-template-rows: auto auto auto;
                row-gap: 0.5rem;
                padding: 1rem 1rem;
            }
            .metrics-panel-viz,
            .metrics-panel-meta {
                grid-column: 2 / -1;
            }
            .metrics-panel-meta {
                white-space: normal;
            }
        }

        /* ============================================================
           Metrics-grid — 2x3 cellen voor monitoring-tab (Spec 4 Phase D).
           Vervangt de eenrijige metrics-panel: meer ruimte per metric,
           grotere value, dedicated visualisatie-slot, equal heights.
        ============================================================ */
        .metrics-grid-row {
            margin: 0;
        }
        /* Cell-dividers gebruiken --orbit-chart-grid (theme-aware: light #dfe6ef,
           dark #32465f) — past bij chart-grid-styling. --bs-border-color is in
           Orbit's dark theme niet override't en bleef #e9ecef = wit op donker. */
        .metrics-grid-cell {
            border-bottom: 1px solid var(--orbit-chart-grid, #dfe6ef);
        }
        .metrics-grid-cell:not(:last-child) {
            border-right: 1px solid var(--orbit-chart-grid, #dfe6ef);
        }
        @media (min-width: 768px) {
            /* Desktop 2x3: cellen op kolommen 1+2 hebben right-border, kolom 3 niet.
               Eerste rij (cellen 1-3) heeft bottom-border, tweede rij niet. */
            .metrics-grid-cell:nth-child(3n) {
                border-right: none;
            }
            .metrics-grid-cell:nth-last-child(-n+3) {
                border-bottom: none;
            }
        }
        .metrics-grid-value {
            font-size: 2rem;
            font-weight: 600;
            font-family: var(--bs-font-monospace, monospace);
            font-variant-numeric: tabular-nums;
            line-height: 1.1;
            letter-spacing: -0.02em;
            /* --helios-text is theme-aware; --bs-body-color staat ook in dark
               op de light-waarde (#2D3F5A) → onleesbaar tegen donkere card-bg. */
            color: var(--helios-text, var(--bs-body-color));
        }
        .metrics-grid-viz {
            min-height: 40px;
            display: flex;
            align-items: center;
        }
        .metrics-grid-viz .orbit-sparkline {
            min-height: 40px;
            margin: 0;
        }
        .metrics-grid-meta {
            font-size: 0.8125rem;
            line-height: 1.3;
        }
        /* Daily-bars (uptime 30d cell) — 30 verticale bars naast elkaar,
           hoogte volgt OK% per dag, kleur volgt severity-threshold. */
        .metrics-grid-daily-bars {
            height: 40px;
            width: 100%;
        }
        .metrics-grid-daily-bar {
            flex: 1 1 0;
            min-width: 4px;
            min-height: 4px;
            background-color: var(--orbit-stat-card-neutral-value, #6c757d);
            transition: opacity 0.15s ease;
        }
        .metrics-grid-daily-bar:hover {
            opacity: 0.75;
        }

        /* Status-strip (Card 2) — buttons hoever ipv span; verwijder
           default-button-styling zodat ze gelijk ogen aan de oude span-bars. */
        .metrics-status-bar {
            height: 100%;
            transition: opacity 0.15s ease, transform 0.15s ease;
        }
        .metrics-status-bar:hover,
        .metrics-status-bar:focus-visible {
            opacity: 0.8;
            transform: translateY(-1px);
        }
        .metrics-status-bar:focus-visible {
            outline: 2px solid var(--bs-primary, #0d6efd);
            outline-offset: 1px;
        }

        /* Header card (Card 1) — score-button ziet eruit als de score-circle
           (geen button-chrome); hover hint dat het clickable is. */
        .monitoring-header-score:hover span,
        .monitoring-header-score:focus-visible span {
            transform: scale(1.05);
            transition: transform 0.15s ease;
        }
        .monitoring-header-score:focus-visible {
            outline: none;
        }
        .monitoring-header-score:focus-visible span {
            box-shadow: 0 0 0 3px rgba(13, 110, 253, 0.25);
        }
        /* Verticale divider tussen header-segmenten (alleen desktop).
           --orbit-chart-grid: theme-aware (light #dfe6ef, dark #32465f). */
        .monitoring-header-divider {
            width: 1px;
            height: 48px;
            background-color: var(--orbit-chart-grid, #dfe6ef);
            flex-shrink: 0;
        }

        /* Lifetime-totals card op stats/view — 4-cellen-grid (col-lg-3) met
           subtle dividers tussen cellen. Aantal is altijd 4 (vast aantal
           tiles); CSS hoeft geen variabel-aantal te ondersteunen. */
        .lifetime-totals-row { margin: 0; }
        .lifetime-totals-cell {
            border-bottom: 1px solid var(--orbit-chart-grid, #dfe6ef);
        }
        .lifetime-totals-cell:last-child { border-bottom: 0; }
        @media (min-width: 576px) {
            /* sm: 2-koloms (col-sm-6). Right-border tussen cellen 1-2 en 3-4
               (nl. odd cells krijgen rechter rand); border-bottom alleen op
               eerste rij (cellen 1+2 = nth-child(-n+2)). */
            .lifetime-totals-cell:nth-child(odd) {
                border-right: 1px solid var(--orbit-chart-grid, #dfe6ef);
            }
            .lifetime-totals-cell { border-bottom: 0; }
            .lifetime-totals-cell:nth-child(-n+2) {
                border-bottom: 1px solid var(--orbit-chart-grid, #dfe6ef);
            }
        }
        @media (min-width: 992px) {
            /* lg: 4-koloms (col-lg-3). Right-border tussen alle cellen
               behalve laatste; geen border-bottom (1 rij). */
            .lifetime-totals-cell { border-bottom: 0; }
            .lifetime-totals-cell:not(:last-child) {
                border-right: 1px solid var(--orbit-chart-grid, #dfe6ef);
            }
        }
        .lifetime-totals-value {
            color: var(--helios-text, var(--bs-body-color));
            font-variant-numeric: tabular-nums;
            letter-spacing: -0.01em;
        }

        /* Specs-card op stats/view — definition-list met dt/dd op een grid;
           subtle dividers tussen rijen. Werkt 1-koloms op mobile (dt boven dd),
           2-koloms (label/value) vanaf sm. */
        .specs-grid dt,
        .specs-grid dd {
            border-bottom: 1px solid var(--orbit-chart-grid, #dfe6ef);
            margin: 0;
        }
        .specs-grid dd { color: var(--helios-text, var(--bs-body-color)); }
        @media (min-width: 576px) {
            .specs-grid dt { border-right: 1px solid var(--orbit-chart-grid, #dfe6ef); }
        }
        /* Laatste rij: removerow border. Aangezien dt+dd alterneren werkt
           :nth-last-of-type niet betrouwbaar; we mikken op de laatste 2 children. */
        .specs-grid > :nth-last-child(-n+2) { border-bottom: 0; }

        /* Attention-card (monitoring + stats overview) — vereist-aandacht
           lijst krijgt een orbit-stijl met severity-leftbar per rij + circle-
           icon. Severity bepaalt:
             - leftbar-color  (warning/danger/info; subtle voor info)
             - row-icon-color (matched aan bar)
             - hover-tint     (light role-tint bij mouseover)
         */
        .attention-card .card-header {
            border-bottom: 1px solid var(--orbit-chart-grid, #dfe6ef);
        }
        .attention-card-icon {
            width: 36px;
            height: 36px;
            border-radius: var(--orbit-radius, 10px);
            display: inline-flex;
            align-items: center;
            justify-content: center;
            color: var(--orbit-chart-warning, #d89b00);
            background-color: rgba(216, 155, 0, 0.10);
            flex-shrink: 0;
        }
        .attention-card-icon i { width: 18px !important; height: 18px !important; }

        .attention-row {
            position: relative;
            border-bottom: 1px solid var(--orbit-chart-grid, #dfe6ef);
            transition: background-color 0.12s ease;
        }
        .attention-row:last-child { border-bottom: 0; }
        /* Hele rij is klikbaar — anchor vult de rij. Padding zit op de link
           zodat het volledige oppervlak hover/click triggert. Geen visuele
           link-styling op de wrapper — kleur en decoratie inherited van de
           rij-content (badges, name, reason). */
        .attention-row-link {
            display: block;
            padding: 0.75rem 1rem 0.75rem 1.25rem;
            color: inherit;
            text-decoration: none;
        }
        .attention-row-link:hover,
        .attention-row-link:focus-visible {
            color: inherit;
            text-decoration: none;
        }
        .attention-row-link:focus-visible {
            outline: 2px solid color-mix(in srgb, var(--bs-primary) 45%, transparent);
            outline-offset: -2px;
        }
        .attention-row::before {
            content: '';
            position: absolute;
            top: 8px;
            bottom: 8px;
            left: 0;
            width: 3px;
            border-radius: 2px;
            background-color: var(--orbit-chart-info, #8ab2d2);
        }
        .attention-row-warning::before { background-color: var(--orbit-chart-warning, #d89b00); }
        .attention-row-danger::before  { background-color: var(--orbit-chart-danger,  #dc3545); }
        .attention-row:hover {
            background-color: rgba(138, 178, 210, 0.05);
        }
        .attention-row-warning:hover { background-color: rgba(216, 155, 0, 0.05); }
        .attention-row-danger:hover  { background-color: rgba(220, 53, 69, 0.05); }
        /* Status-dot in de aandachtspunten-rij — zelfde tinted-chip-systeem als
           `.alert-event-dot` / `.day-event-dot` (alerts-history timeline + day-
           events modal). Tint volgt de state via `.mon-state-chip--<tint>`-
           modifier op de icon zelf, niet op de row. Daardoor blijft het left-
           border-bar (severity-rank) onafhankelijk van de chip-kleur:
           offline-state met severity-rank=danger toont een grijze chip met een
           rode rij-bar — exact zoals de timeline het doet. */
        .attention-row-icon {
            width: 32px;
            height: 32px;
            border-radius: 50%;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            background-color: var(--mon-chip-bg, var(--bs-tertiary-bg));
            color: var(--mon-chip-fg, var(--bs-secondary-color));
            border: 1px solid var(--mon-chip-border, transparent);
            flex-shrink: 0;
        }
        .attention-row-icon i,
        .attention-row-icon svg { width: 14px !important; height: 14px !important; }
        /* Footer-link (… en N meer) — geen border-bar, niet als rij geteld. */
        .attention-row-more {
            padding: 0.5rem 1rem 0.5rem 1.25rem;
            border-bottom: 0;
        }
        .attention-row-more::before { display: none; }
        .attention-row-more:hover   { background-color: transparent; }

        /* Active-issues callout — top-issue krijgt een gekleurde icon-circle
           + linker accent-rand + zachte tint die past bij de severity. Severity-
           kleuren via --orbit-chart-{role} (theme-aware). */
        .active-issue-callout {
            border-left: 4px solid var(--orbit-chart-info, #8ab2d2);
            background-color: rgba(138, 178, 210, 0.06);
        }
        .active-issue-callout-warning {
            border-left-color: var(--orbit-chart-warning, #d89b00);
            background-color: rgba(216, 155, 0, 0.06);
        }
        .active-issue-callout-danger {
            border-left-color: var(--orbit-chart-danger, #dc3545);
            background-color: rgba(220, 53, 69, 0.06);
        }
        .active-issue-icon {
            width: 36px;
            height: 36px;
            border-radius: var(--orbit-radius, 10px);
            display: inline-flex;
            align-items: center;
            justify-content: center;
            background-color: var(--orbit-card-bg, #fff);
            color: var(--orbit-chart-info, #8ab2d2);
            border: 1px solid var(--orbit-chart-grid, #dfe6ef);
        }
        .active-issue-icon-warning { color: var(--orbit-chart-warning, #d89b00); }
        .active-issue-icon-danger  { color: var(--orbit-chart-danger,  #dc3545); }

        /* Alerts-list onder top-issue — verwijder dubbele border op laatste rij. */
        .active-issues-card .list-group-item:last-child { border-bottom: 0 !important; }
        .forecasts-card .list-group-item:last-child     { border-bottom: 0 !important; }

        /* Forecast-rij — grote days-remaining waarde rechts (visueel anchor),
           progress-bar links toont predicted-fill%. Severity volgt thresholds
           (<7d danger, <14d warning, anders neutral). */
        .forecast-days-block {
            min-width: 78px;
            padding-left: 0.5rem;
            border-left: 1px solid var(--orbit-chart-grid, #dfe6ef);
        }
        .forecast-days-value {
            font-size: 1.75rem;
            font-weight: 600;
            font-family: var(--bs-font-monospace, monospace);
            font-variant-numeric: tabular-nums;
            line-height: 1;
            letter-spacing: -0.02em;
            color: var(--helios-text, var(--bs-body-color));
        }
        .forecast-days-block-warning .forecast-days-value { color: var(--orbit-chart-warning, #d89b00); }
        .forecast-days-block-danger  .forecast-days-value { color: var(--orbit-chart-danger,  #dc3545); }

        /* Alert-history timeline op monitoring/view — verticale rail-lijn
           tussen opeenvolgende severity-dots. Time op linker kolom, dot+rail
           middel, content rechts. Hele rij is een <button> die de detail-modal
           opent (alert-event-row-clickable); bericht-preview is bewust weg
           zodat de timeline rustig blijft — klikken voor detail. */
        .alert-event-row {
            padding: 0;
            position: relative;
        }
        .alert-event-row + .alert-event-row {
            border-top: 1px solid var(--orbit-chart-grid, #dfe6ef);
        }
        /* Inner-element draagt het flex-layout. Button-reset zodat de
           native <button> chrome (border, focus-ring, kleurschema) niet
           botst met de timeline-look — eigen focus-style hieronder. */
        .alert-event-row-inner {
            width: 100%;
            background: transparent;
            border: 0;
            padding: 0.85rem 1rem;
            color: inherit;
            font: inherit;
            text-align: left;
            border-radius: 0;
            transition: background-color 120ms ease;
        }
        .alert-event-row-clickable {
            cursor: pointer;
        }
        .alert-event-row-clickable:hover {
            background-color: var(--bs-tertiary-bg, #f8f9fa);
        }
        .alert-event-row-clickable:focus-visible {
            outline: 2px solid var(--bs-primary, #2F6FB3);
            outline-offset: -2px;
            background-color: var(--bs-tertiary-bg, #f8f9fa);
        }
        .alert-event-time {
            /* width (niet min-width) zodat alle rijen precies dezelfde
               kolombreedte hebben, ongeacht stringlengte ("2 min" tot
               "3 maanden geleden"). Dot+rail+content lijnen zo onder elkaar. */
            width: 8rem;
            flex-shrink: 0;
            flex-grow: 0;
            text-align: right;
            padding-top: 6px;
        }
        .alert-event-rail {
            position: relative;
            width: 28px;
            display: flex;
            justify-content: center;
        }
        .alert-event-rail::before {
            content: '';
            position: absolute;
            top: 28px;     /* dot-hoogte (26) + 2px gap */
            bottom: -2rem; /* strekt door tot bovenkant van de volgende dot — row-padding (0.85rem×2) + extra zekerheid */
            left: 50%;
            transform: translateX(-50%);
            width: 2px;
            background-color: var(--helios-timeline-line, #dee2e6);
        }
        .alert-event-row:last-child .alert-event-rail::before {
            display: none;
        }
        /* alert-event-dot (alerts-history timeline) + day-event-dot (day-events
           modal) — beide gebruiken het chip-variabele patroon zodat de
           `.mon-state-chip--<tint>` modifier hetzelfde subtiele tinted-achtergrond
           +-foreground-paar oplevert als de status-chip. Eén regel zodat de twee
           niet uit elkaar groeien. */
        .alert-event-dot,
        .day-event-dot {
            width: 26px;
            height: 26px;
            border-radius: 50%;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            position: relative;
            z-index: 1;
            flex-shrink: 0;
            background-color: var(--mon-chip-bg, var(--bs-tertiary-bg));
            border: 1px solid var(--mon-chip-border, var(--bs-border-color));
            color: var(--mon-chip-fg, var(--bs-secondary-color));
        }
        /* Lucide vervangt <i data-lucide> met <svg> via outerHTML, dus we
           targeten de svg (post-render) én de i (pre-render fallback voor
           als createIcons nog niet gelopen heeft). 12px-icoon binnen 26px-tile
           geeft 7px witruimte rondom — duidelijke "rondje + icoon erin"-
           verhouding zonder dat het icoon plakt tegen de tile-rand. */
        .alert-event-dot i,
        .alert-event-dot svg,
        .day-event-dot i,
        .day-event-dot svg {
            width: 12px !important;
            height: 12px !important;
        }
        .alert-event-content {
            padding-top: 2px;
        }

        /* ---------------------------------------------------------------
           Progressbar track — alléén binnen tabellen donkerder. Bootstrap's
           default #e9ecef is bijna onzichtbaar tegen table-striped
           (--bs-tertiary-bg ≈ #f8f9fa); in een 6px-hoge tabelbalk gaat de
           gekleurde balk anders verloren. Buiten tabellen (counter-cards,
           dashboards, detail-pagina's) blijft de Bootstrap-default staan
           zodat progressbars daar niet onnodig zwaar ogen.
           Dark mode is al pikzwart (zie dark.css).
        --------------------------------------------------------------- */
        .table .progress {
            --bs-progress-bg: #adb5bd;
            background-color: #adb5bd;
        }

        /* ---------------------------------------------------------------
           Monitoring flag-icon + score-ring (monitoring/index.php tabel).
           Compact chip-patroon dat naast tabeltekst proportioneel oogt:
           18×18 ronde tile met 10px-icoon, zelfde tinted achtergrond als
           .alert-event-dot. De `.mon-state-chip--<tint>` tint-modifier
           leeft door op .alert-event-dot in monitoring/view.php (timeline);
           daar staan de rgb-tokens beneden onder dezelfde modifiers.
        --------------------------------------------------------------- */
        .mon-flag-icon {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            width: 18px;
            height: 18px;
            border-radius: 50%;
            background-color: var(--mon-chip-bg, var(--bs-tertiary-bg));
            color: var(--mon-chip-fg, var(--bs-secondary-color));
            border: 1px solid var(--mon-chip-border, var(--bs-border-color));
            line-height: 1;
            flex-shrink: 0;
        }
        .mon-flag-icon i,
        .mon-flag-icon svg {
            width: 10px !important;
            height: 10px !important;
        }
        /* Status-chip modifiers — gebruiken theme-aware --x-status-*-chip-*
           tokens (light-recipes in main.css :root, dark-mirror in dark.css).
           Bootstrap's `--bs-*-bg-subtle` zijn niet theme-aware in Orbit
           (Orbit gebruikt [data-theme] ipv [data-bs-theme], dus BS5 derived
           dark-tinten activeren niet) → chip bleef felgeel/lichtroze in
           dark-mode. De x-tokens zijn al de single source of truth voor
           overige status-badges, hier hergebruiken houdt de palette
           consistent. Critical/offline/neutral hebben geen x-token (geen
           BS5 hue-1-op-1 mapping) — losse dark-overrides hieronder. */
        .mon-state-chip--neutral {
            --mon-chip-bg: var(--bs-tertiary-bg);
            --mon-chip-fg: var(--helios-muted, var(--bs-secondary-color));
            --mon-chip-border: var(--bs-border-color);
        }
        .mon-state-chip--warning {
            --mon-chip-bg: var(--x-status-warning-chip-bg, var(--bs-warning-bg-subtle));
            --mon-chip-fg: var(--x-status-warning-chip-ink, var(--bs-warning-text-emphasis));
            --mon-chip-border: var(--x-status-warning-chip-border, var(--bs-warning-border-subtle));
        }
        .mon-state-chip--danger {
            --mon-chip-bg: var(--x-status-danger-chip-bg, var(--bs-danger-bg-subtle));
            --mon-chip-fg: var(--x-status-danger-chip-ink, var(--bs-danger-text-emphasis));
            --mon-chip-border: var(--x-status-danger-chip-border, var(--bs-danger-border-subtle));
        }
        .mon-state-chip--info {
            --mon-chip-bg: var(--x-status-info-chip-bg, var(--bs-info-bg-subtle));
            --mon-chip-fg: var(--x-status-info-chip-ink, var(--bs-info-text-emphasis));
            --mon-chip-border: var(--x-status-info-chip-border, var(--bs-info-border-subtle));
        }
        /* Critical = donkerste subtle chip (zwart-richting). Gebruikt Bootstrap's
           dark-subtle-tripel: licht-grijze bg + dark-emphasis fg + grijze border.
           Dark-mode override hieronder (BS5 derived subtles activeren niet
           in Orbit — zie comment hierboven). */
        .mon-state-chip--critical {
            --mon-chip-bg: var(--bs-dark-bg-subtle);
            --mon-chip-fg: var(--bs-dark-text-emphasis);
            --mon-chip-border: var(--bs-dark-border-subtle);
        }
        /* Offline = donkergrijs subtle chip — een tint lichter dan critical
           zodat de twee staten visueel uit elkaar te houden zijn. Secondary-
           palette ipv emphasis-color (= near-black, te dicht bij critical). */
        .mon-state-chip--offline {
            --mon-chip-bg: var(--bs-secondary-bg-subtle, var(--bs-tertiary-bg));
            --mon-chip-fg: var(--bs-secondary-color, var(--bs-body-color));
            --mon-chip-border: var(--bs-secondary-border-subtle, var(--bs-border-color));
        }
        /* Dark-mode overrides voor neutral/critical/offline (geen x-token mapping).
           Recipe-pattern matcht de --x-status-*-chip-* dark-recipes:
           color-mix(<hue> 18-24%, transparent) op een dark card-surface. */
        [data-theme="dark"] .mon-state-chip--neutral {
            --mon-chip-bg: color-mix(in srgb, #94a3b8 14%, transparent);
            --mon-chip-fg: #c8d2df;
            --mon-chip-border: color-mix(in srgb, #94a3b8 30%, transparent);
        }
        [data-theme="dark"] .mon-state-chip--critical {
            --mon-chip-bg: color-mix(in srgb, #0b1220 78%, transparent);
            --mon-chip-fg: #e6eaf0;
            --mon-chip-border: color-mix(in srgb, #ffffff 22%, transparent);
        }
        [data-theme="dark"] .mon-state-chip--offline {
            --mon-chip-bg: color-mix(in srgb, #64748b 22%, transparent);
            --mon-chip-fg: #cbd5e1;
            --mon-chip-border: color-mix(in srgb, #64748b 40%, transparent);
        }
        /* `.mon-flag-icon` (paused/suppressed indicators in monitoring/index)
           wordt zonder modifier gebruikt en valt terug op --bs-tertiary-bg —
           dat is in dark-mode #141d27, identiek aan de table-row surface
           waardoor het chip-randje wegvalt. Spiegel hetzelfde neutral-recipe
           als mon-state-chip--neutral. */
        [data-theme="dark"] .mon-flag-icon {
            --mon-chip-bg: color-mix(in srgb, #94a3b8 14%, transparent);
            --mon-chip-fg: #c8d2df;
            --mon-chip-border: color-mix(in srgb, #94a3b8 30%, transparent);
        }
        @media (prefers-color-scheme: dark) {
            [data-theme="auto"] .mon-state-chip--neutral {
                --mon-chip-bg: color-mix(in srgb, #94a3b8 14%, transparent);
                --mon-chip-fg: #c8d2df;
                --mon-chip-border: color-mix(in srgb, #94a3b8 30%, transparent);
            }
            [data-theme="auto"] .mon-state-chip--critical {
                --mon-chip-bg: color-mix(in srgb, #0b1220 78%, transparent);
                --mon-chip-fg: #e6eaf0;
                --mon-chip-border: color-mix(in srgb, #ffffff 22%, transparent);
            }
            [data-theme="auto"] .mon-state-chip--offline {
                --mon-chip-bg: color-mix(in srgb, #64748b 22%, transparent);
                --mon-chip-fg: #cbd5e1;
                --mon-chip-border: color-mix(in srgb, #64748b 40%, transparent);
            }
            [data-theme="auto"] .mon-flag-icon {
                --mon-chip-bg: color-mix(in srgb, #94a3b8 14%, transparent);
                --mon-chip-fg: #c8d2df;
                --mon-chip-border: color-mix(in srgb, #94a3b8 30%, transparent);
            }
        }
        /* Trigger-suffix tekst achter de status-badge — `text-body-secondary`
           viel terug op --bs-secondary-color (niet theme-aware in Orbit) →
           onleesbaar dim in dark mode. helios-muted is wel theme-aware
           (#6c757d light / #94a3b8 dark) en geeft beide modes voldoende
           contrast tegen de card-surface. */
        .alert-event-trigger {
            color: var(--helios-muted, var(--bs-secondary-color));
            font-size: 0.875rem;
        }

        /* Score-ring — kleine SVG-circle naast het score-getal. Track is licht,
           value-stroke volgt drempel: ≥90 success, ≥70 muted, <70 warning.
           CSS-vars zorgen dat dark mode automatisch correcte tinten kiest. */
        .mon-score-ring {
            display: inline-block;
            vertical-align: -3px;
        }
        .mon-score-ring .mon-score-ring-track {
            stroke: var(--bs-border-color);
            opacity: 0.6;
        }
        .mon-score-ring .mon-score-ring-value {
            stroke: var(--bs-secondary-color);
            transition: stroke-dasharray .2s linear;
        }
        .mon-score-ring.mon-ring-ok    .mon-score-ring-value { stroke: var(--bs-success); }
        .mon-score-ring.mon-ring-muted .mon-score-ring-value { stroke: var(--bs-secondary-color); }
        .mon-score-ring.mon-ring-warn  .mon-score-ring-value { stroke: var(--bs-warning-text-emphasis, #b97c0a); }
        /* HTML-message in modal — sane defaults voor Helios-output (paragrafen,
           lijsten, links, code-blocks). Geen aanname over class-namen aan kant
           van Helios; alleen tag-level styling. */
        .alert-message-html {
            font-size: 0.9375rem;
            line-height: 1.5;
        }
        .alert-message-html p:last-child  { margin-bottom: 0; }
        .alert-message-html ul, .alert-message-html ol { padding-left: 1.5rem; }
        .alert-message-html code {
            background-color: var(--orbit-card-bg-muted, #f8f9fa);
            padding: 0.1em 0.35em;
            border-radius: 4px;
            font-size: 0.875em;
        }
        .alert-message-html pre {
            background-color: var(--orbit-card-bg-muted, #f8f9fa);
            padding: 0.75rem;
            border-radius: var(--orbit-radius, 10px);
            overflow-x: auto;
        }

        /* Day-events modal — echte timeline met verticale rail-lijn tussen
           opeenvolgende dots. Light + dark mode beide via --helios-timeline-line. */
        .day-event-row {
            padding: 0.5rem 0 !important;
            border: none !important;
        }
        .day-event-time {
            min-width: 56px;
            text-align: right;
            padding-top: 4px;
            font-size: 0.875rem;
        }
        .day-event-rail {
            position: relative;
            width: 32px;
            display: flex;
            justify-content: center;
        }
        /* Verticale lijn tussen opeenvolgende dots — start onder de dot,
           strekt zich uit tot de bovenkant van de volgende rail. Dot is
           26px (zie shared .alert-event-dot/.day-event-dot regel hierboven),
           dus de lijn begint op 28px (dot-hoogte + 2px gap). */
        .day-event-rail::before {
            content: '';
            position: absolute;
            top: 28px;
            bottom: -1.5rem;
            left: 50%;
            transform: translateX(-50%);
            width: 2px;
            background-color: var(--helios-timeline-line, #dee2e6);
        }
        .day-event-row:last-child .day-event-rail::before {
            display: none;
        }
        /* .day-event-dot styling — zie shared regel met .alert-event-dot
           hierboven (chip-tint-vars + lucide i/svg sizing). */

        /* Score-explainer legenda (servers monitoring-tab dropdown):
           tweekoloms-grid met badge-tegels van vaste breedte links + label rechts. */
        .servers-mon-score-legend {
            grid-template-columns: 70px 1fr;
            align-items: center;
        }
        .servers-mon-score-legend .badge {
            min-width: 64px;
        }

        /* ============================================================
           Advanced variant — footer met Δ-indicator (trend).
           Gebruikt op dashboards met historische vergelijking
           (shortener/index: clicks 7d/30d, active resources).

           Visueel patroon (frontend-design skill: "dominant colors
           with sharp accents"):
             - Footer-bg = 14% role-mix tegen body-bg → gedempte
               extensie van card-body (geen grijze breuk)
             - Trend-pill = solid direction-kleur (success/danger/
               neutral) + wit text → sharp accent op gedempte footer
             - Context-label (bv. "vs vorige periode") = subtle naast
               text, niet competitief met badge

           Direction-based pill-kleuren (niet role-based) want een
           teken van groei/krimp is universeel groen/rood, ongeacht
           of de tile zelf info-blauw of secondary-grijs is.
           ============================================================ */
        .counter-card-footer {
            display: flex;
            align-items: center;
            flex-wrap: wrap;
            gap: 0.5rem;
            /* Continue surface: transparent bg = identiek aan card-inner
               eronder, geen role-tint shift. Border-top zeer subtle (0.04
               opacity) — genoeg voor visuele hiërarchie, niet genoeg voor
               sectie-breuk. Padding 1rem matcht card-body rhythm. */
            padding: 1rem;
            background-color: transparent;
            border-top: 1px solid rgba(var(--bs-body-color-rgb), 0.04);
            font-size: 0.8125rem;
            line-height: 1.3;
        }

        /* Trend = pill-badge met direction-kleur. */
        .counter-card-trend {
            display: inline-flex;
            align-items: center;
            gap: 0.3rem;
            padding: 0.2rem 0.55rem;
            border-radius: 999px;
            font-size: 0.75rem;
            font-weight: 600;
            line-height: 1;
            white-space: nowrap;
        }

        .counter-card-trend > i[data-lucide],
        .counter-card-trend > svg {
            width: 12px;
            height: 12px;
            stroke-width: 2.5;
            flex-shrink: 0;
        }

        .counter-card-trend-up {
            background-color: var(--bs-success);
            color: #ffffff;
        }

        .counter-card-trend-down {
            background-color: var(--bs-danger);
            color: #ffffff;
        }

        .counter-card-trend-flat {
            background-color: rgba(var(--bs-body-color-rgb), 0.12);
            color: rgba(var(--bs-body-color-rgb), 0.75);
        }

        .counter-card-trend-delta {
            font-weight: 600;
        }

        .counter-card-trend-pct {
            opacity: 0.9;
            font-weight: 500;
        }

        .counter-card-trend-label {
            color: rgba(var(--bs-body-color-rgb), 0.6);
            font-size: 0.75rem;
        }

        /* Per-role footer-bg rules verwijderd in V1+V2 redesign —
           continue surface betekent footer is transparent, role-tint
           komt enkel van card-inner eronder. .counter-card-footer-<role>
           classes blijven door de partial geëmitteerd voor backward-
           compat (en voor toekomstige per-role tweaks indien nodig). */

        /* ================================================================
           State-display — signal-stripe card (tpl/state-display.php).
           Unified component voor system-state (403/404, static pages),
           empty-state (deleted entity, no-data), en success/info feedback.

           Visueel principe (frontend-design skill): "Dominant colors with
           sharp accents outperform timid, evenly-distributed palettes".
           De left-border is de enige sharp accent; rest van card is
           neutraal `--helios-surface-raised`. Stripe-color hergebruikt de
           chip-token family (alerts/badges cyclus) voor cross-component
           consistency — one visual family voor alle state-signaling.
           ================================================================ */
        .state-display {
            position: relative;
            border: 1px solid var(--helios-border-subtle);
            border-left: 4px solid var(--state-stripe-color, var(--helios-muted));
            border-radius: var(--orbit-radius, 10px);
            background-color: var(--helios-surface-raised);
            color: var(--helios-text);
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
        }

        /* Standalone variant — system-state pages, prominent.
           Generous padding, larger typography, max-width voor readability.
           Margin-inline: auto centreert binnen parent container. */
        .state-display-standalone {
            padding: 2rem;
            max-width: 640px;
            margin-inline: auto;
        }
        .state-display-standalone .state-display-title {
            font-size: 1.5rem;
        }
        .state-display-standalone .state-display-icon {
            width: 24px;
            height: 24px;
        }

        /* Embedded variant — empty-state binnen detail-view of listing.
           Compacte padding, kleinere typography, volledige breedte van parent
           (geen margin-inline centering — volgt view-flow). */
        .state-display-embedded {
            padding: 1.25rem;
        }
        .state-display-embedded .state-display-title {
            font-size: 1.125rem;
        }
        .state-display-embedded .state-display-icon {
            width: 20px;
            height: 20px;
        }

        /* Role-color → stripe + icon via chip-token-ink (theme-aware,
           zelfde tokens als alerts/badges/counter-card-status). Neutral
           gebruikt --helios-muted (ook theme-aware). */
        .state-display-danger  { --state-stripe-color: var(--x-status-danger-chip-ink); }
        .state-display-warning { --state-stripe-color: var(--x-status-warning-chip-ink); }
        .state-display-success { --state-stripe-color: var(--x-status-success-chip-ink); }
        .state-display-info    { --state-stripe-color: var(--x-status-info-chip-ink); }
        .state-display-neutral { --state-stripe-color: var(--helios-muted); }

        /* Header — icon + title rij. Items-center lijnt icon visueel met
           title-baseline ondanks font-size verschil. */
        .state-display-header {
            display: flex;
            align-items: center;
            gap: 0.625rem;
            margin-bottom: 0.75rem;
        }
        .state-display-icon {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            color: var(--state-stripe-color);
            flex-shrink: 0;
        }
        .state-display-icon > i[data-lucide],
        .state-display-icon > svg {
            stroke: currentColor;
        }
        .state-display-title {
            font-family: 'Unbounded', sans-serif;
            font-weight: 600;
            letter-spacing: -0.015em;
            line-height: 1.2;
            margin: 0;
            color: var(--helios-text);
        }

        /* Body — uitleg-paragraphs. Line-height ruim voor error-contexts
           (users scan in stress — breathing helps). Max-width readability-cap
           geldt alleen op de standalone-variant: die staat op een gecentreerde
           640px card waar 52ch lekker leest. Op embedded (full-width binnen
           detail-views) zou dezelfde cap een loze rechterhelft creëren naast
           de full-bleed stripe + titel — daar laten we de body meebewegen
           met de card-padding. */
        .state-display-body {
            color: var(--helios-text);
            font-size: 0.9375rem;
            line-height: 1.6;
        }
        .state-display-standalone .state-display-body {
            max-width: 52ch;
        }
        .state-display-body p {
            margin: 0 0 0.75rem;
        }
        .state-display-body p:last-child {
            margin-bottom: 0;
        }

        /* Actions row — gap-based inline flex. Flex-wrap zodat buttons
           stacken bij smal viewport (mobile) zonder overflow. Primary en
           secondary gebruiken Bootstrap-native .btn klassen (rendered
           door de partial). */
        .state-display-actions {
            display: flex;
            flex-wrap: wrap;
            gap: 0.5rem;
            margin-top: 1.25rem;
        }
        .state-display-actions .btn {
            display: inline-flex;
            align-items: center;
            gap: 0.4rem;
        }
        .state-display-actions .btn > i[data-lucide],
        .state-display-actions .btn > svg {
            width: 16px;
            height: 16px;
            flex-shrink: 0;
        }

        /* Mobile responsive — compactere padding + title bij smal viewport.
           Standalone krijgt 1.5rem padding (was 2rem), title 1.25rem (was
           1.5rem). Embedded blijft zoals is (al compact). */
        @media (max-width: 575.98px) {
            .state-display-standalone {
                padding: 1.5rem;
            }
            .state-display-standalone .state-display-title {
                font-size: 1.25rem;
            }
        }

/* Monospace-familie + <code>/<pre>/<kbd>/<samp> rebranding.
   Bootstrap's default --bs-code-color is #d63384 (pink/purple) — past niet
   bij Orbit's token-palette. We mappen naar text-muted en geven code een
   subtiele chip-achtige achtergrond + rounded corners zodat inline code
   zichtbaar is zonder te schreeuwen. Font is Space Mono (via Google Fonts
   in header.php); fallback naar ui-monospace/system fonts.
   Zie design-system §2.2 "Typografie — Monospace". */
:root {
    --bs-font-monospace: "Space Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
    --bs-code-color: var(--bs-secondary-color, #6c757d);
}

/* .orbit-num — tabular-nums utility voor cijferkolommen die op één lijn moeten
   staan (CPU%, RAM, disk, score, uptime). Ipv font-monospace dat de body-font
   breekt; tabular-nums lined up de cijfers maar laat de body-font intact. */
.orbit-num {
    font-variant-numeric: tabular-nums;
}
code,
.font-monospace,
pre,
kbd,
samp {
    font-family: var(--bs-font-monospace);
    font-weight: 400;
}
/* Inline <code> krijgt chip-achtige treatment; .bg-dark <code> / <pre> blijft
   onaangeroerd (daar sturen Bootstrap utilities al de kleur). */
code {
    background-color: rgba(0, 0, 0, 0.04);
    padding: 0.1em 0.35em;
    border-radius: 3px;
    font-size: 0.92em;
}
/* Binnen donkere surfaces (pre.bg-dark, tooltips etc.) geen extra achtergrond
   op child-<code> — anders krijgt de snippet een dubbele laag. */
pre.bg-dark code,
.bg-dark code,
.bg-dark > code {
    background-color: transparent;
    padding: 0;
    border-radius: 0;
    color: inherit;
    font-size: inherit;
}

/* Analytics live-pulse dot — subtiele pulse-ring voor "Live op dit moment"
   in de TLDR summary card (views/backend/tools/analytics/site.php). De dot
   zelf is een 8px cirkel; de animatie is een expanderende ring via
   box-shadow die uitfadet. 1.5s cyclus, ease-out zodat de puls niet
   afleidt bij langere leestijd.

   Kleur komt uit --orbit-chart-success (brand-green, dark-mode aware);
   --orbit-live-pulse-color is een lokaal alias zodat de pulse-ring in één
   plek bindt aan hetzelfde token als de dot. */
@keyframes orbit-live-pulse {
    0%   { box-shadow: 0 0 0 0   var(--orbit-live-pulse-ring-from, rgba(150, 189, 94, 0.5)); }
    100% { box-shadow: 0 0 0 8px var(--orbit-live-pulse-ring-to,   rgba(150, 189, 94, 0));   }
}
.live-pulse-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex-shrink: 0;
    /* Optische uitlijning met de x-hoogte van de begeleidende tekst — de
       parent moet .d-inline-flex.align-items-center zijn om drift door
       verschillende line-heights te vermijden. */
    background: var(--orbit-live-pulse-color, var(--orbit-chart-success, #96bd5e)) !important;
    animation: orbit-live-pulse 1.5s ease-out infinite;
}
/* Gray-state bij 0 live bezoekers: geen pulse, neutrale kleur die ook
   leesbaar blijft in dark-mode (gebruikt Bootstrap's --bs-secondary token). */
.live-pulse-dot.is-zero {
    background: var(--bs-secondary, #6c757d) !important;
    animation: none !important;
    box-shadow: none !important;
    opacity: .5;
}
@media (prefers-reduced-motion: reduce) {
    .live-pulse-dot { animation: none; }
}

/* ---------------------------------------------------------------
   Analytics period-filter — segmented button-group styling.
   Desktop: active period krijgt brand-color achtergrond. Mobile:
   de buttons behouden normale tap-height (40px+) i.p.v. de btn-sm
   compact-styling die moeilijk aan te tikken was.
   --------------------------------------------------------------- */
[data-analytics-period-group] .btn.active,
[data-analytics-period-group] .btn:active {
    background: var(--orbit-primary, var(--bs-primary));
    border-color: var(--orbit-primary, var(--bs-primary));
    color: #fff;
}
[data-analytics-period-group] .btn {
    min-height: 38px;
}

/* Analytics summary-card "Overig"-rij micro-metrics — mid-dot separators
   tussen nowrap-paren, met spacing-gap zodat de rij netjes kan wrappen
   op mobiel i.p.v. overflow/truncate. Het eerste kind heeft geen leading
   dot; bij wrap valt de dot weg voor het kind dat de nieuwe regel opent
   (via ::before op .text-nowrap dat vanaf het tweede child een · toont). */
.analytics-tldr-extras {
    column-gap: .45rem;
    row-gap: .1rem;
}
.analytics-tldr-extras > .text-nowrap + .text-nowrap::before {
    content: "·";
    color: var(--bs-secondary-color, #6c757d);
    margin-right: .45rem;
    opacity: .7;
}
.analytics-tldr-extras > .text-nowrap > .fw-semibold + .text-muted {
    margin-left: .25rem;
}

/* Analytics summary-card screenshot — padding rond het frame, afgeronde
   hoeken die meebuigen met de card-radius, hover-overlay, en een vaste
   aspect-ratio. Voorheen nam het frame de row-hoogte aan, waardoor op
   brede viewports een smalle, sterk getrimde variant ontstond (de
   TLDR-content rechts bepaalt de row-hoogte). Aspect-ratio 16:10 matcht
   Microlink's native capture (1280×800) zodat de cover-crop minimaal is
   en het beeld consistent oogt op elk scherm. */
.analytics-screenshot-wrap {
    /* min-height weggehaald — aspect-ratio op het frame regelt nu de hoogte. */
}
.analytics-screenshot-frame {
    border-radius: calc(var(--orbit-radius, 10px) * 0.8);
    overflow: hidden;
    background-color: var(--bs-body-tertiary-bg);
    aspect-ratio: 16 / 10;
    width: 100%;
    /* Subtiele border — zelfde kleur als Bootstrap's card-border-color token
       zodat het frame visueel aansluit bij omliggende cards in dark + light. */
    border: 1px solid var(--bs-border-color-translucent, rgba(0, 0, 0, .12));
    transition: box-shadow .2s ease, transform .2s ease, border-color .2s ease;
}
.analytics-screenshot-frame:hover,
.analytics-screenshot-frame:focus-visible {
    box-shadow: 0 4px 16px rgba(0, 0, 0, .12);
    border-color: var(--bs-border-color, rgba(0, 0, 0, .18));
    outline: none;
}
.analytics-screenshot-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: top center;
    position: absolute;
    inset: 0;
}
.analytics-screenshot-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    background: rgba(18, 33, 53, 0); /* brand-dark tint op hover */
    opacity: 0;
    transition: background-color .2s ease, opacity .2s ease;
    pointer-events: none;
}
/* Hover-overlay pas actief zodra de image daadwerkelijk geladen is (voorkomt
   een lege donkere waas tijdens het spinner-stadium). */
.analytics-screenshot-frame.is-loaded:hover .analytics-screenshot-overlay,
.analytics-screenshot-frame.is-loaded:focus-visible .analytics-screenshot-overlay {
    background: rgba(18, 33, 53, 0.55);
    opacity: 1;
}
[data-theme="dark"] .analytics-screenshot-frame.is-loaded:hover .analytics-screenshot-overlay,
[data-theme="dark"] .analytics-screenshot-frame.is-loaded:focus-visible .analytics-screenshot-overlay {
    background: rgba(0, 0, 0, 0.6);
}

/* ═══════════════════════════════════════════════════════════════════
   ANALYTICS INTEGRATION MODAL — "Field Manual" editorial wizard
   Numbered sections (01-04), station-tags, dark console-panels voor
   alle code/text, radar-metaphor op de verify-stap.
   ═══════════════════════════════════════════════════════════════════ */

#integrationModal .modal-content {
    border: 0;
    box-shadow: 0 24px 80px -16px rgba(15, 23, 32, .35);
}
#integrationModal .modal-body {
    padding: 2rem 2.25rem;
}

/* ── Stepper rail ─────────────────────────────────────────────────── */
.int-stepper {
    position: relative;
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    padding: .25rem 0 1.75rem;
    margin-bottom: 2.25rem;
    border-bottom: 1px solid color-mix(in srgb, var(--orbit-primary, #254672) 10%, transparent);
}
.int-stepper-rail,
.int-stepper-progress {
    position: absolute;
    top: 15px;
    left: 0;
    right: 0;
    height: 2px;
    border-radius: 2px;
}
.int-stepper-rail {
    background: color-mix(in srgb, var(--orbit-primary, #254672) 12%, transparent);
}
.int-stepper-progress {
    width: var(--progress, 0%);
    background: linear-gradient(90deg,
        color-mix(in srgb, var(--orbit-primary, #254672) 70%, transparent) 0%,
        var(--orbit-primary, #254672) 100%);
    transition: width .35s cubic-bezier(.2, .8, .3, 1);
}
.int-stepper-station {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .55rem;
    flex: 1;
    z-index: 1;
}
.int-stepper-bead {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--bs-body-bg, #fff);
    color: var(--bs-secondary-color);
    border: 2px solid color-mix(in srgb, var(--orbit-primary, #254672) 18%, transparent);
    font-weight: 600;
    font-size: .82rem;
    font-variant-numeric: tabular-nums;
    transition: all .25s ease;
}
.int-stepper-check {
    width: 14px;
    height: 14px;
    display: none;
    color: #fff;
}
.int-stepper-label {
    font-size: .72rem;
    font-weight: 500;
    letter-spacing: .02em;
    color: var(--bs-secondary-color);
    text-align: center;
    transition: color .2s;
    white-space: nowrap;
}
.int-stepper-station.is-active .int-stepper-bead {
    background: var(--orbit-primary, #254672);
    color: #fff;
    border-color: var(--orbit-primary, #254672);
    transform: scale(1.1);
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--orbit-primary, #254672) 18%, transparent);
}
.int-stepper-station.is-active .int-stepper-label {
    color: var(--bs-body-color);
    font-weight: 600;
}
.int-stepper-station.is-complete .int-stepper-bead {
    background: var(--orbit-primary, #254672);
    border-color: var(--orbit-primary, #254672);
}
.int-stepper-station.is-complete .int-stepper-num { display: none; }
.int-stepper-station.is-complete .int-stepper-check { display: inline-block; }

/* ── Section header — editorial numbering ─────────────────────────── */
.int-section + .int-section { margin-top: 2.5rem; }
.int-section-head {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 1.25rem;
    margin-bottom: 1.25rem;
    align-items: start;
}
.int-section-index {
    font-family: 'Unbounded', ui-sans-serif, system-ui, sans-serif;
    font-weight: 500;
    font-size: 2.4rem;
    line-height: .85;
    color: color-mix(in srgb, var(--orbit-primary, #254672) 35%, transparent);
    letter-spacing: -.04em;
    font-variant-numeric: tabular-nums;
    padding-top: .15rem;
    min-width: 3.25rem;
}
.int-station-tag {
    display: inline-block;
    font-size: .64rem;
    font-weight: 600;
    letter-spacing: .18em;
    text-transform: uppercase;
    color: var(--orbit-primary, #254672);
    background: color-mix(in srgb, var(--orbit-primary, #254672) 10%, transparent);
    padding: .18rem .5rem;
    border-radius: 3px;
    margin-bottom: .55rem;
}
.int-section-title {
    font-weight: 600;
    font-size: 1.1rem;
    letter-spacing: -.01em;
    color: var(--bs-body-color);
    margin: 0 0 .5rem;
}
.int-section-lede {
    font-size: .92rem;
    line-height: 1.55;
    color: var(--bs-secondary-color);
    margin: 0;
    max-width: 56ch;
}
.int-section-lede code {
    font-size: .85em;
    padding: .05rem .3rem;
    background: color-mix(in srgb, var(--orbit-primary, #254672) 7%, transparent);
    color: color-mix(in srgb, var(--orbit-primary, #254672) 85%, var(--bs-body-color));
    border-radius: 3px;
}

/* ── Console (dark code/text panels) ──────────────────────────────── */
.int-console {
    background: linear-gradient(180deg, #101a28 0%, #0a1220 100%);
    border-radius: calc(var(--orbit-radius, 10px) * 1.2);
    overflow: hidden;
    box-shadow:
        0 8px 24px -12px rgba(0, 0, 0, .4),
        inset 0 1px 0 rgba(255, 255, 255, .04);
    border: 1px solid rgba(255, 255, 255, .05);
}
.int-console-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: .7rem 1rem .7rem 1.15rem;
    border-bottom: 1px solid rgba(255, 255, 255, .05);
    background: linear-gradient(180deg, rgba(255, 255, 255, .03) 0%, transparent 100%);
}
.int-console-tag {
    font-family: ui-monospace, 'SF Mono', monospace;
    font-size: .68rem;
    letter-spacing: .08em;
    color: rgba(255, 255, 255, .55);
    display: inline-flex;
    align-items: center;
    gap: .4rem;
}
.int-console-tag svg,
.int-console-tag i {
    width: 13px;
    height: 13px;
    color: color-mix(in srgb, var(--orbit-chart-info, #6E9EC2) 90%, white);
}
.int-console-body {
    padding: 1rem 1.15rem;
    margin: 0;
}
.int-console-input,
.int-console-textarea {
    width: 100%;
    background: transparent !important;
    border: 0;
    color: #e8f0fa;
    font-family: ui-monospace, 'SF Mono', monospace;
    font-size: .85rem;
    line-height: 1.5;
    padding: 0;
}
.int-console-input { resize: none; }
.int-console-input:focus,
.int-console-textarea:focus {
    outline: none;
    box-shadow: none;
}
.int-console-body--privacy {
    padding: 1rem 1.15rem;
}
.int-console-textarea {
    color: rgba(232, 240, 250, .92);
    line-height: 1.6;
    resize: none;
    overflow: hidden;
    display: block;
}
pre.int-console-code {
    white-space: pre-wrap;
    word-break: break-all;
    padding: 1rem 1.15rem;
}
pre.int-console-code code {
    color: #e8f0fa;
    background: transparent;
    padding: 0;
    font-size: .85rem;
}

/* ── Copy-button ──────────────────────────────────────────────────── */
.int-copy-btn {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .35rem .7rem;
    border-radius: 6px;
    background: rgba(255, 255, 255, .06);
    color: rgba(232, 240, 250, .85);
    border: 1px solid rgba(255, 255, 255, .08);
    font-size: .75rem;
    font-weight: 500;
    transition: all .15s ease;
    cursor: pointer;
}
.int-copy-btn:hover {
    background: rgba(255, 255, 255, .12);
    color: #fff;
    border-color: rgba(255, 255, 255, .15);
}
.int-copy-btn:active { transform: scale(.97); }
.int-copy-btn .int-copy-icon,
.int-copy-btn .int-copy-check {
    width: 13px;
    height: 13px;
}
.int-copy-btn .int-copy-check { display: none; }
.int-copy-btn.is-copied {
    background: color-mix(in srgb, var(--orbit-chart-success) 22%, transparent);
    border-color: color-mix(in srgb, var(--orbit-chart-success) 40%, transparent);
    color: color-mix(in srgb, var(--orbit-chart-success) 30%, white);
}
.int-copy-btn.is-copied .int-copy-icon { display: none; }
.int-copy-btn.is-copied .int-copy-check { display: inline-block; }

/* ── Platform tabs (chips) ────────────────────────────────────────── */
.int-tabs {
    display: flex;
    gap: .4rem;
    padding: .3rem;
    background: color-mix(in srgb, var(--orbit-primary, #254672) 6%, transparent);
    border-radius: calc(var(--orbit-radius, 10px) * 0.9);
    margin-bottom: 1.5rem;
    overflow-x: auto;
    scrollbar-width: none;
}
.int-tabs::-webkit-scrollbar { display: none; }
.int-tab {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .45rem .85rem;
    background: transparent;
    border: 0;
    border-radius: calc(var(--orbit-radius, 10px) * 0.7);
    color: var(--bs-secondary-color);
    font-size: .82rem;
    font-weight: 500;
    white-space: nowrap;
    cursor: pointer;
    transition: all .15s;
    flex-shrink: 0;
}
.int-tab:hover {
    color: var(--bs-body-color);
    background: rgba(255, 255, 255, .5);
}
.int-tab.active {
    background: var(--bs-body-bg, #fff);
    color: var(--bs-body-color);
    font-weight: 600;
    box-shadow: 0 2px 6px -1px rgba(0, 0, 0, .08),
                0 0 0 1px color-mix(in srgb, var(--orbit-primary, #254672) 12%, transparent);
}
.int-tab-name { font-family: 'Public Sans', ui-sans-serif, system-ui, sans-serif; }

/* ── Numbered steps in platform panels ────────────────────────────── */
.int-platform-panel { margin-bottom: 0; }
.int-steps-numbered {
    list-style: none;
    padding: 0;
    margin: 0 0 1.25rem;
    counter-reset: step;
}
.int-steps-numbered li {
    counter-increment: step;
    padding: .55rem 0 .55rem 2.4rem;
    position: relative;
    color: var(--bs-body-color);
    font-size: .92rem;
    line-height: 1.55;
    border-bottom: 1px dashed color-mix(in srgb, var(--orbit-primary, #254672) 8%, transparent);
}
.int-steps-numbered li:last-child { border-bottom: 0; padding-bottom: 0; }
.int-steps-numbered li::before {
    content: counter(step);
    position: absolute;
    left: 0;
    top: .5rem;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: color-mix(in srgb, var(--orbit-primary, #254672) 10%, transparent);
    color: var(--orbit-primary, #254672);
    font-weight: 600;
    font-size: .72rem;
    font-variant-numeric: tabular-nums;
    display: flex;
    align-items: center;
    justify-content: center;
}
.int-steps-numbered code {
    font-size: .85em;
    padding: .05rem .32rem;
    background: color-mix(in srgb, var(--orbit-primary, #254672) 8%, transparent);
    color: color-mix(in srgb, var(--orbit-primary, #254672) 85%, var(--bs-body-color));
    border-radius: 3px;
}

/* ── Verify card — radar station ──────────────────────────────────── */
.int-verify {
    display: flex;
    align-items: center;
    gap: 1.25rem;
    padding: 1.35rem 1.5rem;
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--orbit-chart-success) 6%, var(--bs-body-bg)) 0%,
        var(--bs-body-bg) 70%);
    border: 1px solid color-mix(in srgb, var(--orbit-chart-success) 25%, transparent);
    border-radius: var(--orbit-radius, 10px);
    position: relative;
    overflow: hidden;
}
.int-verify[data-state="success"] {
    border-color: color-mix(in srgb, var(--orbit-chart-success) 50%, transparent);
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--orbit-chart-success) 12%, var(--bs-body-bg)) 0%,
        var(--bs-body-bg) 70%);
}
.int-verify[data-state="error"] {
    border-color: color-mix(in srgb, var(--orbit-chart-warning) 45%, transparent);
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--orbit-chart-warning) 10%, var(--bs-body-bg)) 0%,
        var(--bs-body-bg) 70%);
}
.int-verify-radar {
    position: relative;
    width: 46px;
    height: 46px;
    border-radius: 50%;
    background: color-mix(in srgb, var(--orbit-chart-success) 14%, transparent);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
.int-verify-radar svg,
.int-verify-radar i {
    width: 22px;
    height: 22px;
    color: var(--orbit-chart-success);
    z-index: 2;
}
.int-verify-radar-ping {
    position: absolute;
    inset: 0;
    border-radius: 50%;
    border: 2px solid color-mix(in srgb, var(--orbit-chart-success) 50%, transparent);
    opacity: 0;
}
.int-verify[data-state="loading"] .int-verify-radar-ping {
    animation: int-verify-ping 1.6s ease-out infinite;
}
.int-verify[data-state="loading"] .int-verify-radar-ping--delay {
    animation-delay: .8s;
}
@keyframes int-verify-ping {
    0%   { transform: scale(.8); opacity: .8; }
    80%  { transform: scale(1.8); opacity: 0; }
    100% { transform: scale(1.8); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
    .int-verify-radar-ping { animation: none !important; }
}
.int-verify-body { flex-grow: 1; min-width: 0; }
.int-verify-title {
    font-weight: 600;
    font-size: .95rem;
    letter-spacing: -.005em;
    color: var(--bs-body-color);
    margin-bottom: .15rem;
}
.int-verify-hint {
    font-size: .82rem;
    color: var(--bs-secondary-color);
    line-height: 1.45;
}
.int-verify-btn {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    padding: .55rem 1rem;
    background: var(--orbit-primary, #254672);
    color: #fff;
    border: 0;
    border-radius: 6px;
    font-weight: 500;
    font-size: .85rem;
    cursor: pointer;
    flex-shrink: 0;
    transition: all .2s;
    box-shadow: 0 2px 10px -2px color-mix(in srgb, var(--orbit-primary, #254672) 35%, transparent);
}
.int-verify-btn:hover {
    transform: translateY(-1px);
    box-shadow: 0 6px 16px -4px color-mix(in srgb, var(--orbit-primary, #254672) 45%, transparent);
}
.int-verify-btn svg,
.int-verify-btn i { width: 14px; height: 14px; }
.int-verify-loading-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #fff;
    animation: int-verify-btn-pulse 1s ease-in-out infinite;
}
@keyframes int-verify-btn-pulse {
    0%, 100% { opacity: .4; transform: scale(.9); }
    50%      { opacity: 1;  transform: scale(1.1); }
}
/* Result slot — verborgen tot JS .is-visible toevoegt (geen witruimte vooraf). */
.int-verify-result {
    display: none;
    margin-top: .9rem;
    animation: int-slide-in .3s cubic-bezier(.2, .8, .3, 1);
}
.int-verify-result.is-visible { display: block; }
@keyframes int-slide-in {
    from { opacity: 0; transform: translateY(-6px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* ── Dark-mode ────────────────────────────────────────────────────── */
[data-theme="dark"] #integrationModal .int-section-title,
[data-theme="dark"] #integrationModal .int-verify-title,
[data-theme="dark"] #integrationModal .int-steps-numbered li {
    color: var(--helios-text);
}
[data-theme="dark"] #integrationModal .int-section-lede,
[data-theme="dark"] #integrationModal .int-verify-hint,
[data-theme="dark"] #integrationModal .int-stepper-label {
    color: color-mix(in srgb, var(--helios-text) 68%, transparent);
}
[data-theme="dark"] .int-stepper {
    border-bottom-color: rgba(255, 255, 255, .08);
}
[data-theme="dark"] .int-stepper-rail {
    background: rgba(255, 255, 255, .08);
}
[data-theme="dark"] .int-stepper-progress {
    background: linear-gradient(90deg,
        color-mix(in srgb, var(--orbit-chart-primary) 60%, transparent) 0%,
        var(--orbit-chart-primary) 100%);
}
[data-theme="dark"] .int-stepper-bead {
    background: var(--helios-surface-raised, #1b222d);
    color: color-mix(in srgb, var(--helios-text) 65%, transparent);
    border-color: color-mix(in srgb, var(--orbit-chart-primary) 25%, transparent);
}
[data-theme="dark"] .int-stepper-station.is-active .int-stepper-bead,
[data-theme="dark"] .int-stepper-station.is-complete .int-stepper-bead {
    background: var(--orbit-chart-primary);
    color: #fff;
    border-color: var(--orbit-chart-primary);
}
[data-theme="dark"] .int-stepper-station.is-active .int-stepper-bead {
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--orbit-chart-primary) 22%, transparent);
}
[data-theme="dark"] .int-stepper-station.is-active .int-stepper-label {
    color: var(--helios-text);
}
[data-theme="dark"] .int-section-index {
    color: color-mix(in srgb, var(--orbit-chart-primary) 55%, transparent);
}
[data-theme="dark"] .int-section-lede code,
[data-theme="dark"] .int-steps-numbered code {
    background: rgba(255, 255, 255, .06);
    color: var(--orbit-chart-info);
}
[data-theme="dark"] .int-tabs { background: rgba(255, 255, 255, .04); }
[data-theme="dark"] .int-tab { color: color-mix(in srgb, var(--helios-text) 65%, transparent); }
[data-theme="dark"] .int-tab:hover {
    background: rgba(255, 255, 255, .07);
    color: var(--helios-text);
}
[data-theme="dark"] .int-tab.active {
    background: var(--helios-surface-raised, #141d27);
    color: var(--helios-text);
    box-shadow: 0 2px 6px -1px rgba(0, 0, 0, .4),
                0 0 0 1px color-mix(in srgb, var(--orbit-chart-primary) 25%, transparent);
}
[data-theme="dark"] .int-station-tag {
    color: var(--orbit-chart-info);
    background: color-mix(in srgb, var(--orbit-chart-info) 14%, transparent);
}
[data-theme="dark"] .int-steps-numbered li::before {
    background: color-mix(in srgb, var(--orbit-chart-primary) 14%, transparent);
    color: var(--orbit-chart-info);
}
[data-theme="dark"] .int-steps-numbered li {
    border-bottom-color: rgba(255, 255, 255, .06);
}
[data-theme="dark"] .int-verify {
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--orbit-chart-success) 10%, var(--helios-surface-raised)) 0%,
        var(--helios-surface-raised) 70%);
    border-color: color-mix(in srgb, var(--orbit-chart-success) 35%, transparent);
}
[data-theme="dark"] .int-verify[data-state="success"] {
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--orbit-chart-success) 18%, var(--helios-surface-raised)) 0%,
        var(--helios-surface-raised) 70%);
    border-color: color-mix(in srgb, var(--orbit-chart-success) 55%, transparent);
}
[data-theme="dark"] .int-verify[data-state="error"] {
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--orbit-chart-warning) 16%, var(--helios-surface-raised)) 0%,
        var(--helios-surface-raised) 70%);
    border-color: color-mix(in srgb, var(--orbit-chart-warning) 50%, transparent);
}
[data-theme="dark"] .int-verify-btn {
    background: var(--orbit-chart-primary);
    box-shadow: 0 2px 10px -2px color-mix(in srgb, var(--orbit-chart-primary) 40%, transparent);
}
[data-theme="dark"] .int-verify-btn:hover {
    box-shadow: 0 6px 16px -4px color-mix(in srgb, var(--orbit-chart-primary) 50%, transparent);
}

/* ── Responsive ───────────────────────────────────────────────────── */
@media (max-width: 575.98px) {
    #integrationModal .modal-body { padding: 1.25rem; }
    .int-section-head {
        grid-template-columns: 1fr;
        gap: .25rem;
    }
    .int-section-index {
        font-size: 1.5rem;
        min-width: auto;
    }
    .int-stepper-label { font-size: .65rem; }
    .int-verify {
        flex-wrap: wrap;
        gap: 1rem;
    }
    .int-verify-btn { width: 100%; justify-content: center; }
}

/* ═══════════════════════════════════════════════════════════════════
   CONTEXT-SWITCHER "The Meridian" — globale navigator
   Leest als coordinaat-marker: scope → hairline → current-entity → kbd.
   Gebouwd op Bootstrap 5 dropdown — BS regelt open/close, keyboard-nav,
   positionering, z-index en a11y. Alleen het visuele "rail"-ontwerp en
   de dropdown-item row-styling leven in deze sectie.
   ═══════════════════════════════════════════════════════════════════ */

.orbit-picker {
    --nav-rail: var(--orbit-primary, #254672);
    --nav-ink:  var(--bs-body-color);
    --nav-muted: var(--bs-secondary-color);
}

/* Filter-variant — deelt wrapper-classes met navigator maar visueel
   "naked": geen rail-bg/border, geen margin. Wrapper vult de
   beschikbare ruimte in z'n parent (label + picker pattern), zodat de
   trigger als full-width input-element oogt. */
.orbit-picker--filter {
    flex: 1 1 auto;
    min-width: 0;
    max-width: 100%;
}

/* Navigator-variant = volle kaart-rail (Meridian).
   Filter-variant deelt slechts de wrapper-classes; een "naked"
   .dropdown is voldoende — geen rail-bg/border, geen 100% width
   (de compacte btn-light-trigger bepaalt zelf z'n breedte). */
.orbit-picker--navigator {
    display: flex;
    align-items: stretch;
    width: 100%;
    min-width: 0;
    max-width: 100%;
    margin-bottom: 1.25rem;
    border-radius: calc(var(--orbit-radius, 10px) * 1.2);
    background: color-mix(in srgb, var(--nav-rail) 8%, transparent);
    border: 1px solid color-mix(in srgb, var(--nav-rail) 14%, transparent);
    transition: border-color .2s, background .2s;
}
.orbit-picker--navigator:hover {
    border-color: color-mix(in srgb, var(--nav-rail) 24%, transparent);
    background: color-mix(in srgb, var(--nav-rail) 11%, transparent);
}

.orbit-picker-scope {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    padding: 0 .9rem 0 1rem;
    border-right: 1px solid color-mix(in srgb, var(--nav-rail) 16%, transparent);
    color: var(--nav-muted);
    flex-shrink: 0;
}
.orbit-picker-scope-label {
    font-family: 'Unbounded', ui-sans-serif, system-ui, sans-serif;
    font-weight: 500;
    font-size: .6875rem;
    letter-spacing: .18em;
    text-transform: uppercase;
    line-height: 1;
    opacity: .75;
    white-space: nowrap;
}
.orbit-picker-scope-chevron {
    width: 12px; height: 12px;
    color: color-mix(in srgb, var(--nav-rail) 48%, transparent);
    flex-shrink: 0;
}

.orbit-picker-trigger {
    display: inline-flex;
    align-items: center;
    gap: .75rem;
    padding: .55rem 1rem;
    background: transparent;
    border: 0;
    color: var(--nav-ink);
    cursor: pointer;
    text-align: left;
    min-width: 0;   /* zodat binnen-content kan ellipsen */
    flex: 1 1 auto;
    transition: background .15s;
    border-top-right-radius: inherit;
    border-bottom-right-radius: inherit;
}
.orbit-picker-trigger:hover,
.orbit-picker-trigger:focus-visible {
    background: color-mix(in srgb, var(--nav-rail) 6%, transparent);
    outline: none;
}
.orbit-picker-trigger[aria-expanded="true"] {
    background: color-mix(in srgb, var(--nav-rail) 10%, transparent);
}

.orbit-picker-current {
    display: inline-flex;
    flex-direction: column;
    align-items: flex-start;
    gap: .08rem;
    min-width: 0;
    flex: 1 1 auto;
    line-height: 1.15;
}
.orbit-picker-current-name {
    font-weight: 600;
    font-size: .9375rem;
    letter-spacing: -.005em;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    line-height: 1.2;
}
.orbit-picker-current-domain {
    font-size: .75rem;
    color: var(--nav-muted);
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    line-height: 1.25;
}
.orbit-picker-kbd {
    font-family: ui-monospace, 'SF Mono', monospace;
    font-size: .6875rem;
    font-weight: 600;
    color: var(--nav-muted);
    padding: .1rem .4rem;
    border-radius: .3rem;
    background: color-mix(in srgb, var(--nav-rail) 10%, transparent);
    border: 1px solid color-mix(in srgb, var(--nav-rail) 18%, transparent);
    line-height: 1.25;
    flex-shrink: 0;
}
.orbit-picker-chevron {
    width: 14px; height: 14px;
    color: var(--nav-muted);
    flex-shrink: 0;
    transition: transform .2s;
}
.orbit-picker-trigger[aria-expanded="true"] .orbit-picker-chevron {
    transform: rotate(180deg);
}

/* ── btn-helios-on-dark — Bootstrap btn-variant voor secundaire actie-
      knoppen op donkere oppervlakken (terminal-card-headers, dark
      hero-banners, dark-context dropdown-triggers). Gebruikt het Bootstrap
      5.3 --bs-btn-* CSS-var pattern zodat :hover, :active, :focus en
      :disabled automatisch via de framework-laag werken — geen extra
      selectors nodig. Combineert met .btn-sm voor compact-size.

      Padding-y overruled op 0.1875rem (3px) in plaats van btn-sm default
      0.25rem (4px) zodat de knop in een card-header niet de header-hoogte
      opdrijft. Project-globaal herbruikbaar. */
.btn-helios-on-dark {
    --bs-btn-color: rgba(255, 255, 255, 0.85);
    --bs-btn-bg: transparent;
    --bs-btn-border-color: rgba(255, 255, 255, 0.20);
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: rgba(255, 255, 255, 0.08);
    --bs-btn-hover-border-color: rgba(255, 255, 255, 0.35);
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: rgba(255, 255, 255, 0.15);
    --bs-btn-active-border-color: rgba(255, 255, 255, 0.45);
    --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.20);
    --bs-btn-focus-shadow-rgb: 255, 255, 255;
    --bs-btn-disabled-color: rgba(255, 255, 255, 0.40);
    --bs-btn-disabled-bg: transparent;
    --bs-btn-disabled-border-color: rgba(255, 255, 255, 0.10);
    --bs-btn-padding-y: 0.1875rem;
}

/* ── Generic helios collapse-toggle — chevron rotation tied to aria-expanded.
      Werkt op zowel <button>-elementen als op niet-button containers (bv.
      .card-header) waar de hele container als collapse-trigger fungeert.
      Voor de niet-button-variant: ook cursor + hover-affordance + a11y-hint
      via [role=button] + [tabindex=0]. */
.helios-collapse-chevron {
    transition: transform .2s;
}
.helios-collapse-toggle[aria-expanded="false"] .helios-collapse-chevron {
    transform: rotate(0deg);
}
.helios-collapse-toggle[aria-expanded="true"] .helios-collapse-chevron {
    transform: rotate(180deg);
}
.helios-collapse-toggle[role="button"] {
    cursor: pointer;
    user-select: none;
    transition: background-color .15s;
}
.helios-collapse-toggle[role="button"]:hover {
    background-color: rgba(0, 0, 0, 0.03);
}
.helios-collapse-toggle[role="button"]:focus-visible {
    outline: 2px solid var(--bs-primary, #0d6efd);
    outline-offset: -2px;
}
/* Donkere headers (bv. terminal bg-dark) krijgen een lichte hover-tint. */
.helios-collapse-toggle[role="button"].bg-dark:hover {
    background-color: #2a2a2a !important;
}

/* ── .helios-info-tooltip — inline info-icoon naast een form-label of
      heading, dat met `data-bs-toggle="tooltip"` extra context geeft.
      Vervangt 6+ instances van inline `style="width:14px;height:14px;
      cursor:help;vertical-align:-2px"` op <i data-lucide="info"> elementen.
      Toepassing: <i data-lucide="info" class="helios-info-tooltip text-muted
      ms-1" data-bs-toggle="tooltip" title="…"></i>. */
.helios-info-tooltip {
    width: 14px;
    height: 14px;
    cursor: help;
    vertical-align: -2px;
}

/* ── orbit-terminal — VS-Code-style donkere code-block met regelnummers
      en subtiele color-tokens. Gebruikt op rapportage-commando's;
      herbruikbaar voor andere modules die uitgevoerde shell-commando's
      tonen. */
.orbit-terminal {
    color: #e6e6e6;
    background: #1e1e1e;
}
.orbit-terminal-lineno {
    color: rgba(255, 255, 255, 0.35);
    font-variant-numeric: tabular-nums;
    background: rgba(255, 255, 255, 0.03);
}
.orbit-terminal-line {
    color: #e6e6e6;
}

/* ── helios-file-picker drag-state — visual feedback wanneer een file
      over de container wordt gedragd. Class wordt door helios-file-picker.js
      gezet/verwijderd. Subtle border + bg-tint, geen scale of shadow-shift
      (focus blijft op de inhoud, geen flash). */
[data-helios-file-picker] {
    transition: border-color .15s, background-color .15s;
}
[data-helios-file-picker].is-drag-over {
    border-color: var(--bs-primary, #0d6efd) !important;
    background-color: rgba(13, 110, 253, 0.05) !important;
}

/* ── Contextueel: action-buttons binnen een warm-getinte list-item
      (.bg-warning-subtle) blenden in met de item-bg. Geen PHP-conditional
      nodig; de scope-selector regelt dit per context. Werkt zowel voor
      edit (btn-light border) als delete (btn-light border text-danger). */
.list-group-item.bg-warning-subtle .btn-light.border {
    background-color: rgba(255, 193, 7, 0.10);
    border-color: rgba(255, 193, 7, 0.30);
}
.list-group-item.bg-warning-subtle .btn-light.border:hover,
.list-group-item.bg-warning-subtle .btn-light.border:focus {
    background-color: rgba(255, 193, 7, 0.20);
    border-color: rgba(255, 193, 7, 0.45);
}

/* ── orbit-copy — class-state lifecycle voor orbit-copy.js
      (.is-copied wordt 1500ms toegevoegd na een succesvolle clipboard-write).
      Markup heeft .orbit-copy-default + .orbit-copy-success spans/icons:
      idle toont default, .is-copied toont success. */
.orbit-copy-btn .orbit-copy-success { display: none; }
.orbit-copy-btn.is-copied .orbit-copy-default { display: none; }
.orbit-copy-btn.is-copied .orbit-copy-success { display: inline-block; }

/* ── helios-badge-strong — donkerder, meer-grounded badge-variant voor
      gebruik op donkere oppervlakken (terminal-headers, dark cards) waar
      de standaard Bootstrap-badge te vivid/popping aanvoelt.
      Pair met .bg-{warning,info,success,danger} om de basiskleur te
      bepalen; deze regels overrulen alleen background + text-color.
      Project-globaal herbruikbaar. */
.badge.helios-badge-strong.bg-warning {
    background-color: #6c4a00 !important;
    color: #fff !important;
}
.badge.helios-badge-strong.bg-info {
    background-color: #1c4a5a !important;
    color: #fff !important;
}
.badge.helios-badge-strong.bg-success {
    background-color: #1e5b30 !important;
    color: #fff !important;
}
.badge.helios-badge-strong.bg-danger {
    background-color: #6e2828 !important;
    color: #fff !important;
}

/* ── Dropdown-menu (Bootstrap dropdown) — alleen visueel afgestemd,
      BS regelt positionering + z-index; custom keyboard-nav zit in
      orbit-picker.js omdat een search-input de native ↑↓ opeet. */
.orbit-picker-menu {
    min-width: min(360px, 100%);
    max-width: min(480px, calc(100vw - 1.5rem));
    padding: .35rem;
    max-height: 380px;
    overflow-y: auto;
}
.orbit-picker-search {
    padding: .35rem .4rem .25rem;
    /* Sticky binnen scrollende .orbit-picker-menu — top compenseert de
       menu-padding (.35rem) zodat de search-bar niet "boven" de menu-rand
       blijft hangen. Background dekt onderliggende option-rows die onder
       de bar door scrollen. z-index 2 zit boven dropdown-divider (1). */
    position: sticky;
    top: -.35rem;
    background: var(--bs-body-bg);
    z-index: 2;
}

/* Clear-knop (×) binnen .orbit-picker-search-bar — toont alleen wanneer
   .has-value class op de bar staat (gezet door orbit-picker.js bij elke
   filterItems-pass). Mirror van .helios-filter-search-clear pattern, maar
   intra-bar (binnen dezelfde label) i.p.v. absoluut gepositioneerd. */
.orbit-picker-search-clear {
    display: none;
    flex-shrink: 0;
    width: 18px;
    height: 18px;
    padding: 0;
    margin-left: .15rem;
    border: 0;
    border-radius: 50%;
    background: color-mix(in srgb, var(--orbit-primary, #254672) 14%, transparent);
    color: color-mix(in srgb, var(--orbit-primary, #254672) 65%, transparent);
    cursor: pointer;
    align-items: center;
    justify-content: center;
    transition: background-color .12s ease, color .12s ease;
}
.orbit-picker-search-bar.has-value .orbit-picker-search-clear {
    display: inline-flex;
}
.orbit-picker-search-clear:hover,
.orbit-picker-search-clear:focus-visible {
    background: color-mix(in srgb, var(--orbit-primary, #254672) 22%, transparent);
    color: var(--orbit-primary, #254672);
    outline: none;
}
.orbit-picker-search-clear i[data-lucide] {
    width: 11px;
    height: 11px;
}
/* Dark-mode mirror */
[data-theme="dark"] .orbit-picker-search-clear {
    background: rgba(255, 255, 255, .07);
    color: color-mix(in srgb, var(--helios-text) 55%, transparent);
}
[data-theme="dark"] .orbit-picker-search-clear:hover,
[data-theme="dark"] .orbit-picker-search-clear:focus-visible {
    background: rgba(255, 255, 255, .12);
    color: var(--helios-text);
}

/* Shared search-bar pattern (desktop dropdown + mobile modal). De ─lg
   modifier voor de mobile modal vergroot padding/font, zelfde core. */
.orbit-picker-search-bar {
    display: flex;
    align-items: center;
    gap: .55rem;
    padding: 0 .65rem;
    margin: 0;
    border: 1px solid color-mix(in srgb, var(--orbit-primary, #254672) 14%, transparent);
    border-radius: 7px;
    background: color-mix(in srgb, var(--orbit-primary, #254672) 4%, transparent);
    transition: border-color .15s ease, background .15s ease;
    cursor: text;
}
.orbit-picker-search-bar:focus-within {
    border-color: color-mix(in srgb, var(--orbit-primary, #254672) 36%, transparent);
    background: color-mix(in srgb, var(--orbit-primary, #254672) 7%, transparent);
}
.orbit-picker-search-icon {
    width: 13px;
    height: 13px;
    color: color-mix(in srgb, var(--orbit-primary, #254672) 55%, transparent);
    flex-shrink: 0;
    transition: color .15s ease;
}
.orbit-picker-search-bar:focus-within .orbit-picker-search-icon {
    color: color-mix(in srgb, var(--orbit-primary, #254672) 80%, transparent);
}
.orbit-picker-search-bar .form-control,
.orbit-picker-search-bar .form-control:focus {
    flex: 1;
    min-width: 0;
    border: 0;
    /* appearance:none strip de UA-styling van type="search" — anders krijgt
       het input een eigen dark-mode achtergrond via color-scheme + browser-
       default. background-color expliciet (niet shorthand) zodat we BS's
       --bs-form-control-bg variable overschrijven, niet alleen 'background'. */
    appearance: none;
    -webkit-appearance: none;
    background-color: transparent;
    box-shadow: none;
    padding: .4rem 0;
    font-size: .8125rem;
    color: var(--bs-body-color);
    outline: none;
}
/* Verberg de WebKit-clear-button (X icoontje) van type="search" — past niet
   bij ons design en zou rechts in de bar verschijnen. */
.orbit-picker-search-bar .form-control::-webkit-search-cancel-button,
.orbit-picker-search-bar .form-control::-webkit-search-decoration {
    -webkit-appearance: none;
    appearance: none;
}
/* ─lg variant — mobile modal: groter tap-target + leesbaarder font. */
.orbit-picker-search-bar--lg {
    padding: 0 .9rem;
    border-radius: 10px;
    margin-bottom: 1rem;
}
.orbit-picker-search-bar--lg .orbit-picker-search-icon {
    width: 16px;
    height: 16px;
}
.orbit-picker-search-bar--lg .form-control,
.orbit-picker-search-bar--lg .form-control:focus {
    padding: .7rem 0;
    font-size: 1rem;
}

/* Dropdown-items — name + identifier + live-dot. Zelfde ritme als de
   trigger (name/domain font-sizes matchen). */
.orbit-picker-opt {
    display: flex;
    align-items: center;
    gap: .65rem;
    padding: .55rem .7rem;
    border-radius: 6px;
    transition: background-color .12s ease, box-shadow .12s ease;
}
.orbit-picker-opt:hover {
    background-color: color-mix(in srgb, var(--orbit-primary, #254672) 7%, transparent);
    color: var(--bs-body-color);
}
/* Keyboard focus — subtiele left-accent bar i.p.v. rommelige outline-ring.
   Gebruik focus-visible zodat muis-focus geen visuele ruis geeft. */
.orbit-picker-opt:focus { outline: 0; }
.orbit-picker-opt:focus-visible {
    outline: 0;
    background-color: color-mix(in srgb, var(--orbit-primary, #254672) 10%, transparent);
    box-shadow: inset 3px 0 0 var(--orbit-primary, #254672);
    color: var(--bs-body-color);
}
.orbit-picker-opt.active {
    background-color: color-mix(in srgb, var(--orbit-primary, #254672) 10%, transparent);
    color: var(--bs-body-color);
    font-weight: 600;
}
.orbit-picker-opt-body {
    display: flex;
    flex-direction: column;
    gap: .1rem;
    min-width: 0;
    flex: 1;
    line-height: 1.2;
}
.orbit-picker-opt-name {
    font-weight: 600;
    font-size: .9375rem;
    letter-spacing: -.005em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.orbit-picker-opt-domain {
    font-size: .75rem;
    color: var(--bs-secondary-color);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    line-height: 1.25;
}
/* Status-dot per option (context-switcher).
   Default = success (groen, met pulse-glow). Modifier-classes overrulen kleur:
   .is-idle (grijs, no glow), .is-warning (oranje), .is-danger (rood),
   .is-info (blauw). Mapping via $opt['status'] in orbit-picker.php; legacy
   $opt['has_live']=true blijft success geven (no-status = is-idle). */
.orbit-picker-opt-live-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--orbit-chart-success);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--orbit-chart-success) 22%, transparent);
    flex-shrink: 0;
}
.orbit-picker-opt-live-dot.is-idle {
    background: var(--bs-secondary-color);
    box-shadow: none;
    opacity: .3;
}
.orbit-picker-opt-live-dot.is-warning {
    background: var(--bs-warning, #ffc107);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--bs-warning, #ffc107) 22%, transparent);
}
.orbit-picker-opt-live-dot.is-danger {
    background: var(--bs-danger, #dc3545);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--bs-danger, #dc3545) 22%, transparent);
}
.orbit-picker-opt-live-dot.is-info {
    background: var(--bs-info, #6e9ec2);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--bs-info, #6e9ec2) 22%, transparent);
}
/* Optionele icon-tile per option — visueel mirror van helios-entity-tile-sm,
   maar scoped aan de navigator. Wordt alleen gerenderd als de partial een
   icon_image of icon_lucide krijgt; oude callers zonder icon zijn ongewijzigd. */
.orbit-picker-opt-icon {
    flex: 0 0 24px;
    width: 24px;
    height: 24px;
    border-radius: 6px;
    background-color: var(--helios-surface-hover, rgba(0, 0, 0, .05));
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--helios-text, var(--bs-body-color));
    overflow: hidden;
}
.orbit-picker-opt-icon img {
    width: 100%;
    height: 100%;
    object-fit: contain;
}
.orbit-picker-opt-icon i[data-lucide] {
    width: 14px;
    height: 14px;
}
/* Trigger-variant — iets compacter zodat de header-rij niet uitrekt. */
.orbit-picker-current-icon {
    flex: 0 0 22px;
    width: 22px;
    height: 22px;
    border-radius: 5px;
    background-color: color-mix(in srgb, var(--nav-rail, #254672) 8%, transparent);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    margin-right: .1rem;
}
.orbit-picker-current-icon img {
    width: 100%;
    height: 100%;
    object-fit: contain;
}
.orbit-picker-current-icon i[data-lucide] {
    width: 13px;
    height: 13px;
    color: var(--nav-ink);
}
/* Naam-suffix — muted "· extra" achter de hoofd-naam (bv. group-label).
   Inherit lijnhoogte/typografie van de parent .orbit-picker-opt-name /
   .orbit-picker-current-name zodat het visueel één regel is. */
.orbit-picker-opt-name-suffix,
.orbit-picker-current-name-suffix {
    font-weight: 400;
    margin-left: .15rem;
}

/* Modal-list — grotere icon (tap-target) */
.orbit-picker-modal-list .orbit-picker-opt-icon {
    flex: 0 0 28px;
    width: 28px;
    height: 28px;
    border-radius: 7px;
}
.orbit-picker-modal-list .orbit-picker-opt-icon i[data-lucide] {
    width: 16px;
    height: 16px;
}

/* Dark-mode — chart-primary (lichter op dark surface) */
[data-theme="dark"] .orbit-picker {
    --nav-rail: var(--orbit-chart-primary, #5f8fb3);
    --nav-ink:  var(--helios-text, #e6eaf0);
    /* --nav-muted overrulen — anders inherit'd hij --bs-secondary-color
       die in Orbit's dark mode niet flipt (data-theme i.p.v.
       data-bs-theme). Zonder deze regel is .orbit-picker-chevron
       donker-grijs op een donkere surface = onzichtbaar. */
    --nav-muted: color-mix(in srgb, var(--helios-text, #e6eaf0) 60%, transparent);
}
[data-theme="dark"] .orbit-picker--navigator {
    background: color-mix(in srgb, var(--nav-rail) 12%, transparent);
    border-color: color-mix(in srgb, var(--nav-rail) 28%, transparent);
}
[data-theme="dark"] .orbit-picker--navigator:hover {
    background: color-mix(in srgb, var(--nav-rail) 18%, transparent);
    border-color: color-mix(in srgb, var(--nav-rail) 38%, transparent);
}
[data-theme="dark"] .orbit-picker-menu {
    background: var(--helios-surface-raised, #1b222d);
    border: 1px solid color-mix(in srgb, var(--nav-rail) 22%, transparent);
    color: var(--helios-text);
}
[data-theme="dark"] .orbit-picker-opt {
    color: var(--helios-text);
}
[data-theme="dark"] .orbit-picker-opt:hover {
    background: color-mix(in srgb, var(--nav-rail) 14%, transparent);
    color: var(--helios-text);
}
[data-theme="dark"] .orbit-picker-opt:focus-visible {
    background: color-mix(in srgb, var(--nav-rail) 18%, transparent);
    color: var(--helios-text);
    box-shadow: inset 3px 0 0 var(--nav-rail);
}
[data-theme="dark"] .orbit-picker-opt.active {
    background: color-mix(in srgb, var(--nav-rail) 22%, transparent);
    color: var(--helios-text);
}
[data-theme="dark"] .orbit-picker-opt-domain,
[data-theme="dark"] .orbit-picker-scope,
[data-theme="dark"] .orbit-picker-current-domain {
    color: color-mix(in srgb, var(--helios-text) 68%, transparent);
}
[data-theme="dark"] .orbit-picker-kbd {
    color: var(--helios-text);
    background: color-mix(in srgb, var(--nav-rail) 18%, transparent);
    border-color: color-mix(in srgb, var(--nav-rail) 34%, transparent);
}

/* Mobile — scope-label compacter, subtiele margin aan de zijkanten zodat
   hij niet rand-tot-rand in de container plakt. Trigger opent een
   fullscreen modal (zie .orbit-picker-modal hieronder); de desktop
   dropdown-menu wordt verborgen via `display: none !important` in de
   media query zelf (niet via d-* utilities — die breken BS's .show-
   toggle op de dropdown). */
@media (max-width: 575.98px) {
    .orbit-picker--navigator {
        margin-left: .25rem;
        margin-right: .25rem;
        width: auto;
    }
    .orbit-picker-scope { padding: 0 .75rem 0 .85rem; }
    .orbit-picker-scope-label { font-size: .625rem; }
    .orbit-picker-current-name { font-size: .9rem; }
    /* Mobile: desktop-dropdown volledig uit beeld — mobile gebruikt de modal. */
    .orbit-picker-menu { display: none !important; }
}

/* ── Mobile fullscreen modal variant ─────────────────────────────────
   Op mobile wordt de dropdown vervangen door een fullscreen modal zodat
   het toetsenbord voorspelbaar de content omhoog pusht i.p.v. het menu
   af te snijden. Styling spiegelt de Meridian-typografie zodat het één
   component voelt, niet twee. */
.orbit-picker-modal .modal-header {
    align-items: flex-start;
    padding: 1rem 1.25rem .85rem;
    border-bottom: 1px solid color-mix(in srgb, var(--orbit-primary, #254672) 10%, transparent);
}
.orbit-picker-modal-head-text {
    min-width: 0;
    flex: 1;
}
.orbit-picker-modal-head-text .orbit-picker-scope-label {
    display: block;
    margin-bottom: .35rem;
    color: color-mix(in srgb, var(--orbit-primary, #254672) 60%, var(--bs-body-color));
    opacity: 1;
}
.orbit-picker-modal-title {
    font-size: 1.125rem;
    font-weight: 600;
    letter-spacing: -.01em;
    margin: 0;
    color: var(--bs-body-color);
    line-height: 1.25;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.orbit-picker-modal-body {
    padding: .5rem 1.25rem 1.25rem;
}
/* Sticky search-blok tussen modal-header en modal-body. Leeft buiten
   .modal-body zodat hij niet meescrollt — modal-dialog-scrollable scrollt
   alleen de body. Border-bottom geeft visueel onderscheid tussen het
   "vaste" zoek-deel en de scrollende lijst. */
 .orbit-picker-modal-search {
    padding: .5rem 1.25rem .5rem;
    background: var(--bs-body-bg);
    border-bottom: 1px solid var(--bs-border-color);
}
/* Modal: zoekbalk geen extra margin onder sticky search */
.orbit-picker-modal-search .orbit-picker-search-bar--lg {
    margin-bottom: 0;
}
.orbit-picker-modal-list {
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: .15rem;
}
.orbit-picker-modal-list .orbit-picker-opt {
    padding: .85rem .75rem;
    gap: .75rem;
    border-radius: 8px;
    min-height: 54px;   /* 44px tap-target + breathing */
}
.orbit-picker-modal-list .orbit-picker-opt-name {
    font-size: 1rem;
}
.orbit-picker-modal-list .orbit-picker-opt-domain {
    font-size: .8125rem;
}

/* Dark-mode — modal */
[data-theme="dark"] .orbit-picker-modal .modal-header {
    border-bottom-color: rgba(255, 255, 255, .08);
}
[data-theme="dark"] .orbit-picker-modal-search {
    background: var(--bs-body-bg);
    border-bottom-color: rgba(255, 255, 255, .08);
}
[data-theme="dark"] .orbit-picker-modal-head-text .orbit-picker-scope-label {
    color: var(--orbit-chart-info);
}
[data-theme="dark"] .orbit-picker-modal-title {
    color: var(--helios-text);
}
/* Dark-mode search-bar — neutrale tinten (geen orbit-primary tint die als
   navy halo om het veld zou hangen). */
[data-theme="dark"] .orbit-picker-search-bar {
    background: rgba(255, 255, 255, .04);
    border-color: rgba(255, 255, 255, .08);
}
[data-theme="dark"] .orbit-picker-search-bar:focus-within {
    background: rgba(255, 255, 255, .07);
    border-color: rgba(255, 255, 255, .18);
}
[data-theme="dark"] .orbit-picker-search-icon {
    color: color-mix(in srgb, var(--helios-text) 50%, transparent);
}
[data-theme="dark"] .orbit-picker-search-bar:focus-within .orbit-picker-search-icon {
    color: color-mix(in srgb, var(--helios-text) 75%, transparent);
}
/* Override de globale html[data-theme="dark"] .form-control regel uit
   dark.css:1152 — die zet background-color: var(--helios-bg-main) op alle
   form-controls, wat hier zichtbaar wordt als hard-donker blok binnen de
   wrapper. Specificity (0,3,0) wint van dark.css's (0,2,1). */
[data-theme="dark"] .orbit-picker-search-bar .form-control,
[data-theme="dark"] .orbit-picker-search-bar .form-control:focus {
    background-color: transparent;
    border-color: transparent;
    color: var(--helios-text);
}
[data-theme="dark"] .orbit-picker-search-bar .form-control::placeholder {
    color: color-mix(in srgb, var(--helios-text) 45%, transparent);
}

/* ─── Filter-variant trigger ────────────────────────────────────────
   Compacte BS btn-light met leading-icon-tile + label + chevron.
   Bewust subtiel: blijft visueel "een knop", niet een hele kaart zoals
   de navigator-trigger. Tile = 24px afgeronde square met soft tint
   die past bij brand-primary. Toont op desktop én mobile (alleen
   wrapper d-none/d-sm-* logic verschilt). */
.orbit-picker-trigger--filter {
    /* Reset wat .btn-light doet zodat tile + chevron netjes uitlijnen. */
    padding-block: .3rem;
    padding-inline: .55rem .55rem;
    line-height: 1.2;
    max-width: 100%;
}
.orbit-picker-trigger--filter:focus-visible {
    box-shadow: 0 0 0 .2rem color-mix(in srgb, var(--orbit-primary, #254672) 22%, transparent);
}
.orbit-picker-trigger-tile {
    flex-shrink: 0;
    width: 24px;
    height: 24px;
    border-radius: 6px;
    background: color-mix(in srgb, var(--orbit-primary, #254672) 12%, transparent);
    color: var(--orbit-primary, #254672);
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.orbit-picker-trigger-tile i[data-lucide] {
    width: 14px;
    height: 14px;
}
.orbit-picker-trigger-label {
    font-weight: 500;
    color: var(--helios-text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}
.orbit-picker-trigger-chevron {
    flex-shrink: 0;
    width: 14px;
    height: 14px;
    color: color-mix(in srgb, var(--helios-text) 55%, transparent);
    transition: transform .15s ease;
}
.orbit-picker-trigger--filter[aria-expanded="true"] .orbit-picker-trigger-chevron {
    transform: rotate(180deg);
}
[data-theme="dark"] .orbit-picker-trigger-tile {
    background: rgba(255, 255, 255, .08);
    color: color-mix(in srgb, var(--helios-text) 80%, transparent);
}

/* ─── Offcanvas-bottom shell (filter-variant mobile) ────────────────
   Sheet-stijl alternatief voor de fullscreen modal. Sluit makkelijker
   (backdrop + swipe), past bij filter-context (geen volledige
   pagina-overname nodig). Sticky search bovenin de body via een
   apart .orbit-picker-offcanvas-search blok. */
.orbit-picker-offcanvas {
    border-top-left-radius: var(--orbit-radius, 10px);
    border-top-right-radius: var(--orbit-radius, 10px);
    max-height: 85vh;
    height: auto !important; /* override BS default 30vh */
}
.orbit-picker-offcanvas-head {
    padding: .75rem 1.25rem;
    border-bottom: 1px solid var(--bs-border-color);
}
.orbit-picker-offcanvas-search {
    padding: .75rem 1.25rem 1rem;
    background: var(--bs-body-bg);
    border-bottom: 1px solid var(--bs-border-color);
    position: sticky;
    top: 0;
    z-index: 5;
}
.orbit-picker-offcanvas-body {
    padding: .5rem .75rem 1rem;
    overflow-y: auto;
}
.orbit-picker-offcanvas-list {
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: .15rem;
}
.orbit-picker-offcanvas-list .orbit-picker-opt {
    padding: .75rem .75rem;
    gap: .75rem;
    border-radius: 8px;
    min-height: 48px;
}
.orbit-picker-offcanvas-list .orbit-picker-opt-name {
    font-size: .95rem;
}
.orbit-picker-offcanvas-list .orbit-picker-opt-domain {
    font-size: .8125rem;
}
[data-theme="dark"] .orbit-picker-offcanvas-head,
[data-theme="dark"] .orbit-picker-offcanvas-search {
    background: var(--bs-body-bg);
    border-bottom-color: rgba(255, 255, 255, .08);
}

/* ═══════════════════════════════════════════════════════════════════
   ANALYTICS FILTER-BAR — Plausible-style single-dimension filter
   Pill links + Filter-dropdown rechts. Bootstrap dropdown + modal
   onder de motorkap; eigen typografie en kleuren erover.
   ═══════════════════════════════════════════════════════════════════ */

.orbit-filter-pill {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    padding: .35rem .25rem .35rem .75rem;
    background: color-mix(in srgb, var(--orbit-primary, #254672) 8%, transparent);
    border: 1px solid color-mix(in srgb, var(--orbit-primary, #254672) 22%, transparent);
    border-radius: 999px;
    font-size: .8125rem;
    color: var(--bs-body-color);
    max-width: 80vw;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* v2 pill sub-elements */
.orbit-filter-pill-dim {
  font-weight: 600;
  color: var(--orbit-primary);
}

.orbit-filter-pill-op {
  color: var(--orbit-text-muted, var(--bs-secondary-color, #6c757d));
  font-style: italic;
  margin: 0 0.35rem;
}

.orbit-filter-pill-val {
  font-weight: 500;
}

.orbit-filter-pill-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 1.25rem;
  height: 1.25rem;
  margin-left: 0.5rem;
  border-radius: 50%;
  cursor: pointer;
  transition: background 120ms ease;
  /* color inherits from pill; icon SVG scales via width/height below */
  color: inherit;
  opacity: 0.55;
}

.orbit-filter-pill-remove i[data-lucide],
.orbit-filter-pill-remove svg {
  width: 12px;
  height: 12px;
  /* SVG is position-independent of line-height, so × baseline drift is gone */
  display: block;
}

.orbit-filter-pill-remove:hover {
  background: var(--orbit-danger-soft, rgba(220, 53, 69, 0.12));
  opacity: 1;
}

/* Bootstrap 5 mist .min-w-0 utility (alleen .min-vw-100/.min-vh-100).
   Nodig voor flex-children met text-truncate: zonder min-width:0 kan een
   flex-item niet kleiner dan zijn intrinsieke content (overflow gebeurt). */
.min-w-0 { min-width: 0 !important; }

/* Stats icon utilities — pure sizing voor inline-styled lucide icons +
   country-flag images. Marges/spacing via Bootstrap utilities (me-2, ms-1)
   op de call-site zodat dezelfde class in verschillende layout-contexten
   herbruikbaar is. */
.orbit-icon-sm {
    width: 14px;
    height: 14px;
    vertical-align: middle;
}
.orbit-flag-img {
    width: 20px;
    height: 15px;
    border-radius: 2px;
}

/* ApexCharts custom-tooltip wrapper — gebruikt door pieTooltipBuilder()
   in orbit-shortener-ui.js. Apex past z'n eigen theme-classes
   (.apexcharts-theme-light) niet betrouwbaar toe op tooltip.custom output;
   we leveren self-contained styling. */
.orbit-pie-tooltip {
    background: #fff;
    border: 1px solid #d6d8dc;
    border-radius: 6px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
    font-size: .8125rem;
    color: #212529;
    overflow: hidden;
    min-width: 140px;
}
.orbit-pie-tooltip__header {
    font-weight: 600;
    padding: .4rem .6rem;
    border-bottom: 1px solid #eee;
    background: #f8f9fa;
}
.orbit-pie-tooltip__body {
    padding: .4rem .6rem;
}

/* ========================================================================
   List-group admin pattern — voor listing-content (recent items, top items,
   admin entity-rijen) waar tabel-stijl te statistisch voelt. Gebruikt
   Bootstrap list-group-flush + list-group-item-action; deze regels voegen
   alleen orbit-token-aware hover-state + ranking-badge toe.
   ======================================================================== */
.orbit-rank-badge {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: color-mix(in srgb, var(--orbit-primary, #254672) 12%, transparent);
    color: var(--orbit-primary, #254672);
    font-weight: 600;
    font-size: .8125rem;
    line-height: 1;
}

.list-group-flush .list-group-item-action:hover,
.list-group-flush .list-group-item-action:focus {
    background-color: color-mix(in srgb, var(--orbit-primary, #254672) 4%, transparent);
}

/* topN-row + value-picker active highlight */
tbody[data-analytics-topn] tr.is-active,
.orbit-filter-picker-list .is-active {
  background: var(--orbit-primary-soft, rgba(37, 70, 114, 0.08));
}

/* Per-card window-capped notice (v2 — Task 15) */
.orbit-card-notice {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.75rem;
  margin-bottom: 0.75rem;
  font-size: 0.8125rem;
  color: var(--orbit-text-muted, var(--bs-secondary-color, #6c757d));
  background: var(--orbit-warning-soft, rgba(255, 193, 7, 0.1));
  border-left: 3px solid var(--orbit-warning, #ffc107);
  border-radius: var(--orbit-radius, 10px);
}

.orbit-card-notice i[data-lucide] {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}

.orbit-filter-dropdown {
    min-width: 280px;
    max-width: min(420px, 90vw);
}
.orbit-filter-dim-group + .orbit-filter-dim-group {
    margin-top: .8rem;
}
.orbit-filter-dim-group-label {
    font-size: .65rem;
    font-weight: 600;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: color-mix(in srgb, var(--orbit-primary, #254672) 70%, transparent);
    margin-bottom: .35rem;
}
.orbit-filter-dim-btn {
    display: block;
    width: 100%;
    text-align: left;
    padding: .45rem .6rem;
    border: 0;
    background: transparent;
    border-radius: 6px;
    font-size: .9rem;
    color: var(--bs-body-color);
    cursor: pointer;
    transition: background .12s;
}
.orbit-filter-dim-btn:hover,
.orbit-filter-dim-btn:focus-visible {
    background: color-mix(in srgb, var(--orbit-primary, #254672) 8%, transparent);
    outline: 0;
}

/* Scroll-gedrag wordt afgehandeld door .modal-dialog-scrollable op het
   parent .modal-dialog (Bootstrap-conform). Eigen max-height+overflow-y
   hier zou een scroll-binnen-scroll context maken: op mobile-fullscreen
   strekt de modal-body uit over het hele scherm maar de inner list bleef
   gecapped op 60vh, waardoor onderkant content onbereikbaar werd.
   Ref: https://getbootstrap.com/docs/5.3/components/modal/#scrolling-long-content */
.orbit-filter-picker-list {
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: .15rem;
}
.orbit-filter-picker-list li button {
    display: block;
    width: 100%;
    text-align: left;
    padding: .75rem 1rem;
    min-height: 48px;
    border: 0;
    background: transparent;
    border-radius: 8px;
    font-size: .95rem;
    color: var(--bs-body-color);
    cursor: pointer;
    transition: background .12s;
}
.orbit-filter-picker-list li button:hover,
.orbit-filter-picker-list li button:focus-visible {
    background: color-mix(in srgb, var(--orbit-primary, #254672) 8%, transparent);
    outline: 0;
}

/* Disabled-card bij actieve filter — alleen visuele dim + cursor-help.
   De toelichting komt uit een Bootstrap-tooltip (data-bs-toggle="tooltip"
   + title-attr gewired in JS) zodat hij niet over de KPI-cijfers heen
   rendert. Pointer-events blijven aan zodat de tooltip kan triggeren. */
.orbit-filter-disabled-card {
    opacity: .55;
    cursor: help;
    position: relative;
}
.orbit-filter-disabled-card * {
    pointer-events: none;
}

.orbit-filter-window-notice {
    font-size: .72rem;
    color: var(--bs-secondary-color);
    padding: .35rem .75rem;
    text-align: center;
    border-top: 1px solid color-mix(in srgb, var(--orbit-primary, #254672) 8%, transparent);
}

/* ── Dark-mode ────────────────────────────────────────────────────── */
[data-theme="dark"] .orbit-filter-pill {
    background: color-mix(in srgb, var(--orbit-chart-primary) 14%, transparent);
    border-color: color-mix(in srgb, var(--orbit-chart-primary) 30%, transparent);
    color: var(--helios-text);
}
[data-theme="dark"] .orbit-filter-dim-group-label {
    color: var(--orbit-chart-info);
}
[data-theme="dark"] .orbit-filter-dim-btn {
    color: var(--helios-text);
}
[data-theme="dark"] .orbit-filter-dim-btn:hover,
[data-theme="dark"] .orbit-filter-dim-btn:focus-visible {
    background: rgba(255, 255, 255, .06);
}
[data-theme="dark"] .orbit-filter-picker-list li button {
    color: var(--helios-text);
}
[data-theme="dark"] .orbit-filter-picker-list li button:hover,
[data-theme="dark"] .orbit-filter-picker-list li button:focus-visible {
    background: rgba(255, 255, 255, .06);
}
[data-theme="dark"] .orbit-filter-window-notice {
    color: color-mix(in srgb, var(--helios-text) 60%, transparent);
    border-top-color: rgba(255, 255, 255, .08);
}
/* v2 pill sub-elements — dark-mode contrast fixes.
   Light: --orbit-primary = #254672 (navy, readable on white).
   Dark:  --orbit-primary is still navy → illegible on dark bg.
   Use --orbit-chart-primary (#5f8fb3, light-blue) for dim label;
   use --helios-muted (#94a3b8) for the muted op text. */
[data-theme="dark"] .orbit-filter-pill-dim {
    color: var(--orbit-chart-primary);
}
[data-theme="dark"] .orbit-filter-pill-op {
    color: var(--helios-muted, #94a3b8);
}
/* 30d card notice — dark-mode: muted text on warning-soft bg is unreadable.
   Use --orbit-chart-warning (#f5b27a, amber) which is dark-mode-aware and
   carries enough contrast on the dark card surface. */
[data-theme="dark"] .orbit-card-notice {
    color: var(--orbit-chart-warning, #f5b27a);
    background: color-mix(in srgb, var(--orbit-chart-warning, #f5b27a) 10%, transparent);
    border-left-color: var(--orbit-chart-warning, #f5b27a);
}

/* Mobile — pill mag wrappen, dropdown is verborgen (d-sm-none op de
   markup), offcanvas neemt over (zie .orbit-filter-offcanvas hieronder). */
@media (max-width: 575.98px) {
    .orbit-filter-bar {
        flex-wrap: wrap;
        gap: .5rem;
    }
    .orbit-filter-pill {
        max-width: 100%;
        width: fit-content;
    }
}

/* Offcanvas-bottom variant voor mobile filter — zelfde patroon als
   page-header.php's offcanvas. Dim-groups krijgen wat extra ademruimte
   vergeleken met de dropdown-variant omdat tap-targets groter mogen. */
.orbit-filter-offcanvas {
    --bs-offcanvas-height: auto;
    max-height: 70vh;
    border-top-left-radius: 14px;
    border-top-right-radius: 14px;
}
.orbit-filter-offcanvas .offcanvas-body {
    padding: 1.25rem 1rem 1.5rem;
}
.orbit-filter-offcanvas .orbit-filter-dim-group + .orbit-filter-dim-group {
    margin-top: 1rem;
}
.orbit-filter-offcanvas .orbit-filter-dim-btn {
    padding: .85rem .75rem;
    font-size: 1rem;
    min-height: 48px;  /* tap-target */
}
[data-theme="dark"] .orbit-filter-offcanvas {
    background-color: var(--helios-bg-panel, #1b222d);
    color: var(--helios-text);
}
[data-theme="dark"] .orbit-filter-offcanvas .orbit-filter-dim-group-label {
    color: var(--orbit-chart-info);
}
[data-theme="dark"] .orbit-filter-offcanvas .orbit-filter-dim-btn {
    color: var(--helios-text);
}
[data-theme="dark"] .orbit-filter-offcanvas .orbit-filter-dim-btn:hover,
[data-theme="dark"] .orbit-filter-offcanvas .orbit-filter-dim-btn:focus-visible {
    background: rgba(255, 255, 255, .06);
}

/* Mobile filter active-list (in offcanvas) */
/* border-bottom → BS `border-bottom` util on <li> (JS-built); flex-shrink-0 → BS util on btn-close */
.orbit-filter-active-item:last-child {
    border-bottom: none !important;
}
.orbit-filter-active-edit {
    color: var(--bs-body-color);
    min-height: 44px; /* touch-friendly */
}
.orbit-filter-active-edit:hover {
    color: var(--orbit-primary);
}

/* ── Site-card "weather-aura" — tier-driven radial gradient achtergrond ───
   Het oppervlak van elke kaart draagt een hue-aura die het actuele traffic-
   niveau communiceert als omgevingssignaal: grijs (idle) → blauw (low) →
   groen (healthy) → geel/oranje (busy) → rood (fire). De aura is een radial
   gradient vanuit de rechteronderhoek (waar de 24u-sparkline leeft) en fadet
   naar transparant voordat hij de tekst raakt. Tier 4 (fire) krijgt een
   tweede warme gradient-bron linksboven voor asymmetrische intensiteit —
   zo voel je het verschil tussen "druk" en "alles staat in brand" voordat
   je de cijfers leest.

   Tokens: hergebruik --orbit-chart-* tokens die al dark-mode-aware zijn;
   geen aparte dark-mode hue-definities nodig. Opacities worden in dark-mode
   iets verhoogd omdat een donkere base meer licht absorbeert.

   Stack (z-index):
     ::before                       = aura-layer (0)
     .analytics-card-bg-spark        = 24u sparkline (1)
     .card-body / .card-footer       = content (2) */

.site-card > .d-none.d-md-block > .card {
    --card-aura-hue: var(--orbit-chart-secondary);
    --card-aura-opacity: 0.04;
    --card-aura-accent-hue: transparent;
    --card-aura-accent-opacity: 0;

    position: relative;
    isolation: isolate;
    overflow: hidden;
    transition: transform .25s cubic-bezier(.2, .8, .3, 1),
                box-shadow .25s ease;
    will-change: transform;
}
/* Hover: 1.5px lift + zachte navy-getinte shadow + iets helderder aura.
   Alleen wanneer de kaart echt klikbaar is (stretched-link aanwezig),
   maar simpel te houden: we passen overal toe zodat het voelt als
   "de kaart reageert op u". */
.site-card > .d-none.d-md-block > .card:hover {
    transform: translateY(-1.5px);
    box-shadow: 0 6px 24px -8px color-mix(in srgb, var(--orbit-primary, #254672) 18%, transparent),
                0 1px 2px rgba(0, 0, 0, .05);
}
.site-card > .d-none.d-md-block > .card:hover::before {
    filter: brightness(1.15) saturate(1.05);
}
[data-theme="dark"] .site-card > .d-none.d-md-block > .card:hover {
    box-shadow: 0 6px 24px -8px rgba(0, 0, 0, .55),
                0 0 0 1px color-mix(in srgb, var(--orbit-chart-primary) 25%, transparent);
}
@media (prefers-reduced-motion: reduce) {
    .site-card > .d-none.d-md-block > .card,
    .site-card > .d-none.d-md-block > .card:hover {
        transform: none;
        transition: none;
    }
}

/* Live-heartbeat dot naast het live-aantal. Grijs+rustig bij 0, groen+
   pulserend bij actief verkeer. data-has-live wordt server-side gezet en
   (bij AJAX-refresh) door JS bijgewerkt (zie orbit-analytics-ui.js
   sitesOverview poll). */
.site-card-live {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
}
.site-card-live-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--bs-secondary-color, #6c757d);
    opacity: .35;
    flex-shrink: 0;
    transition: opacity .3s, background .3s, box-shadow .3s;
}
.site-card-live[data-has-live="1"] .site-card-live-dot {
    background: var(--orbit-chart-success);
    opacity: 1;
    animation: site-card-heartbeat 2s ease-out infinite;
}
@keyframes site-card-heartbeat {
    0%   { box-shadow: 0 0 0 0   color-mix(in srgb, var(--orbit-chart-success) 55%, transparent); }
    70%  { box-shadow: 0 0 0 6px color-mix(in srgb, var(--orbit-chart-success)  0%, transparent); }
    100% { box-shadow: 0 0 0 0   color-mix(in srgb, var(--orbit-chart-success)  0%, transparent); }
}
@media (prefers-reduced-motion: reduce) {
    .site-card-live-dot { animation: none !important; }
}

/* Trend-pills — vervangt inline ↑5% tekst. Tabular-nums voorkomt column-
   shift bij verschillende percentage-breedtes. Kleur via color-mix tegen
   body-tint zodat light- en dark-mode natuurlijk goed contrasteren. */
.helios-trend-pill {
    display: inline-flex;
    align-items: center;
    gap: .25rem;
    padding: .08rem .4rem;
    border-radius: 999px;
    font-size: .72rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    line-height: 1.3;
    letter-spacing: .01em;
    margin-left: .25rem;
    transition: transform .2s ease;
    vertical-align: middle;
}
.helios-trend-pill-up {
    color: color-mix(in srgb, var(--orbit-chart-success) 85%, #000);
    background: color-mix(in srgb, var(--orbit-chart-success) 14%, transparent);
}
.helios-trend-pill-down {
    color: color-mix(in srgb, var(--orbit-chart-danger) 85%, #000);
    background: color-mix(in srgb, var(--orbit-chart-danger) 14%, transparent);
}
[data-theme="dark"] .helios-trend-pill-up {
    color: color-mix(in srgb, var(--orbit-chart-success) 55%, white);
    background: color-mix(in srgb, var(--orbit-chart-success) 22%, transparent);
}
[data-theme="dark"] .helios-trend-pill-down {
    color: color-mix(in srgb, var(--orbit-chart-danger) 55%, white);
    background: color-mix(in srgb, var(--orbit-chart-danger) 22%, transparent);
}
.site-card .card:hover .helios-trend-pill {
    transform: translateY(-1px);
}

.site-card > .d-none.d-md-block > .card::before {
    content: "";
    position: absolute;
    inset: 0;
    background:
        radial-gradient(
            ellipse 110% 85% at 88% 100%,
            color-mix(in srgb, var(--card-aura-hue) calc(var(--card-aura-opacity) * 100%), transparent) 0%,
            color-mix(in srgb, var(--card-aura-hue) calc(var(--card-aura-opacity) * 60%),  transparent) 35%,
            transparent 72%
        ),
        radial-gradient(
            circle at 12% 8%,
            color-mix(in srgb, var(--card-aura-accent-hue) calc(var(--card-aura-accent-opacity) * 100%), transparent) 0%,
            transparent 55%
        );
    pointer-events: none;
    z-index: 0;
    transition: background 400ms ease;
}

/* Tier-niveaus — idle tot fire */
.site-card[data-traffic-tier="0"] > .d-none.d-md-block > .card {
    --card-aura-hue: var(--orbit-chart-secondary);
    --card-aura-opacity: 0.04;
}
.site-card[data-traffic-tier="1"] > .d-none.d-md-block > .card {
    --card-aura-hue: var(--orbit-chart-info);
    --card-aura-opacity: 0.09;
}
.site-card[data-traffic-tier="2"] > .d-none.d-md-block > .card {
    --card-aura-hue: var(--orbit-chart-success);
    --card-aura-opacity: 0.12;
}
.site-card[data-traffic-tier="3"] > .d-none.d-md-block > .card {
    --card-aura-hue: var(--orbit-chart-warning);
    --card-aura-opacity: 0.15;
}
.site-card[data-traffic-tier="4"] > .d-none.d-md-block > .card {
    --card-aura-hue: var(--orbit-chart-danger);
    --card-aura-opacity: 0.18;
    --card-aura-accent-hue: var(--orbit-chart-warning);
    --card-aura-accent-opacity: 0.10;
}

/* Dark-mode surface-hiërarchie fix: globale .bg-white → --helios-bg-main
   override (dark.css) zorgt dat site-cards BLENDEN met de pagina-achtergrond
   zonder distinction. Hier geven we de site-cards specifiek de raised
   surface zodat ze één stap oplichten — net als andere card-listings. */
[data-theme="dark"] .site-card > .d-none.d-md-block > .card.bg-white {
    background-color: var(--helios-surface-raised) !important;
}

/* Tekst-leesbaarheid in dark mode: Bootstrap's --bs-body-color is in Orbit's
   dark mode niet apart gezet (BS-5.3 gebruikt 'm binnen component-scopes,
   :root-override zou no-op zijn), dus .text-body class rendert als donker-
   blauw op donker oppervlak → onleesbaar. Forceer BS text-emphasis utilities
   naar helios-text zodat ze in beide thema's als "primary text" werken. */
[data-theme="dark"] .text-body,
[data-theme="dark"] .text-body-emphasis {
    color: var(--helios-text) !important;
}

/* Dark-mode opacity bump (donkere base absorbeert meer licht). */
[data-theme="dark"] .site-card[data-traffic-tier="0"] > .d-none.d-md-block > .card { --card-aura-opacity: 0.07; }
[data-theme="dark"] .site-card[data-traffic-tier="1"] > .d-none.d-md-block > .card { --card-aura-opacity: 0.14; }
[data-theme="dark"] .site-card[data-traffic-tier="2"] > .d-none.d-md-block > .card { --card-aura-opacity: 0.18; }
[data-theme="dark"] .site-card[data-traffic-tier="3"] > .d-none.d-md-block > .card { --card-aura-opacity: 0.22; }
[data-theme="dark"] .site-card[data-traffic-tier="4"] > .d-none.d-md-block > .card {
    --card-aura-opacity: 0.26;
    --card-aura-accent-opacity: 0.15;
}

/* Content-lagen boven de aura. Sparkline zit al op z-index:1 uit de
   bestaande inline-style; dit zorgt alleen dat card-body/footer hoger komen. */
.site-card > .d-none.d-md-block > .card > .card-body,
.site-card > .d-none.d-md-block > .card > .card-footer {
    position: relative;
    z-index: 2;
}
.analytics-card-bg-spark {
    z-index: 1 !important;
}

/* Analytics topN "toon alle" expand-row — full-width clickable tr.
   .orbit-table-expand-row = generieke server-rendered variant (backup stats
   tabellen via data-orbit-table-expand, zie tpl/backup/_stats-body.php). */
.analytics-topn-expand-row,
.orbit-table-expand-row {
    cursor: pointer;
    transition: background-color .15s ease;
}
.analytics-topn-expand-row:hover td,
.orbit-table-expand-row:hover td {
    background-color: var(--bs-tertiary-bg, rgba(0,0,0,.03));
}

/* Analytics topN key-cell — truncate lange URLs/domeinen binnen cardbreedte.
   Alleen op md+ (≥768px): table-layout:fixed + 60/40 kolom-verdeling zodat
   de bar-row altijd netjes in de value-kolom past en de key-kolom lange URLs
   knipt met ellipsis.

   Onder md: .orbit-table-mobile gebruikt display:block op tr/td (zie §8 voor
   het stacked label-waarde patroon). table-layout:fixed interfereert dan met
   de blok-layout → value-cel raakt leeg of met verkeerde breedte. Media-query
   isoleert de desktop-regels zodat mobile naar natural-width teruggaat. */
@media (min-width: 768px) {
    .orbit-stat-table-card .table {
        table-layout: fixed;
        width: 100%;
    }
    .orbit-stat-table-card .table > :not(caption) > * > *:first-child {
        width: 60%;
    }
    .orbit-stat-table-card .table > :not(caption) > * > *:last-child {
        width: 40%;
    }
    /* .table-responsive voegt standaard overflow-x:auto toe — voor topN-cards
       is dat niet nodig (content is begrensd) en veroorzaakt op sommige
       viewports scroll/overflow buiten de card. */
    .orbit-stat-table-card .table-responsive {
        overflow-x: visible;
    }
}
.orbit-stat-table-card .analytics-topn-key {
    min-width: 0;
    max-width: 100%;
    gap: .4rem;
}
.orbit-stat-table-card .analytics-topn-key-text {
    min-width: 0;
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.orbit-stat-table-card .analytics-topn-external {
    display: inline-flex;
    align-items: center;
    opacity: .55;
    transition: opacity .15s ease, color .15s ease;
}
.orbit-stat-table-card .analytics-topn-external:hover,
.orbit-stat-table-card .analytics-topn-external:focus-visible {
    opacity: 1;
    color: var(--orbit-brand-primary, #0d6efd);
}

/* ===== helios-icon-picker ===== */
.helios-icon-picker [data-icon-preview] {
    min-width: 38px;
    justify-content: center;
    background: var(--helios-surface-sunken);
    color: var(--helios-text);
}
.helios-icon-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
    gap: 6px;
}
.helios-icon-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    padding: 10px 6px;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--orbit-radius);
    background: var(--helios-surface-raised);
    color: var(--helios-text);
    cursor: pointer;
    transition: background-color .12s ease, border-color .12s ease, color .12s ease;
    min-height: 70px;
}
.helios-icon-tile:hover {
    background: var(--helios-surface-hover);
    border-color: var(--bs-primary);
    color: var(--helios-text);
}
.helios-icon-tile i { width: 20px; height: 20px; }
.helios-icon-tile-label {
    font-size: 11px;
    color: var(--helios-text);
    opacity: .6;
    text-align: center;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 100%;
}
[data-theme="dark"] .helios-icon-tile,
[data-theme="auto"] .helios-icon-tile {
    border-color: rgba(255, 255, 255, 0.10);
}

/* ===== helios-image-upload ===== */
.helios-image-upload-preview {
    width: 64px;
    aspect-ratio: 1 / 1;
    background: var(--helios-surface-sunken);
}
.helios-image-upload-preview.is-wide {
    width: 128px;
    aspect-ratio: 16 / 9;
}
@media (min-width: 576px) {
    .helios-image-upload-preview { width: 80px; }
    .helios-image-upload-preview.is-wide { width: 160px; }
}

/* ─── Helios License toggle-cards ─────────────────────────────────────
   Mini-cards voor de auto-detected licenties op /backend/servers/add.
   Klikbaar met btn-check sibling-input pattern. Active-state werkt in
   light en dark via --bs-primary-rgb (alpha-blend op de active bg) en
   theme-aware --helios-* fallbacks voor neutrale kleuren.

   Layout: square icon-box links + twee tekstregels rechts (text-truncate
   houdt het op één regel met ellipsis). Grid via Bootstrap col-6
   (mobiel) / col-md-3 (desktop). */
.helios-license-card {
    display: flex;
    align-items: center;
    gap: .625rem;
    padding: .5rem .75rem;
    width: 100%;
    min-height: 56px;
    cursor: pointer;
    text-align: left;
    background-color: var(--helios-surface-raised, var(--bs-body-bg));
    border: 1px solid var(--helios-border-subtle, var(--bs-border-color));
    border-radius: var(--orbit-radius, 10px);
    color: var(--helios-text, var(--bs-body-color));
    transition: border-color .15s ease, background-color .15s ease;
    user-select: none;
}
.helios-license-card:hover {
    border-color: rgba(var(--bs-primary-rgb), .35);
}
.btn-check:checked + .helios-license-card {
    background-color: rgba(var(--bs-primary-rgb), .12);
    border-color: rgba(var(--bs-primary-rgb), .45);
    color: var(--helios-text, var(--bs-body-color));
}
.btn-check:focus-visible + .helios-license-card {
    box-shadow: 0 0 0 .2rem rgba(var(--bs-primary-rgb), .25);
}
/* Generic entity-tile — 36px icon-square used in detail-view L1 tiles
   (person/contact, software/license, …). Cross-module canonical. Use the
   helios/entity-tile.php partial for new call-sites; existing inline
   usage in licenses/index.php + servers/_form.php was migrated in the
   2026-05 rename from .helios-license-icon → .helios-entity-tile. */
.helios-entity-tile {
    flex: 0 0 36px;
    width: 36px;
    height: 36px;
    border-radius: var(--orbit-radius, 10px);
    background-color: var(--helios-surface-hover, rgba(0, 0, 0, .05));
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--helios-text, var(--bs-body-color));
    overflow: hidden;          /* clip image-fill aan border-radius */
}

/* Compact variant voor in tabel-rijen — sluit aan bij body-line-height
   zonder de regel verticaal op te rekken. Smaller corners passen bij
   de kleinere oppervlakte. */
.helios-entity-tile-sm {
    flex: 0 0 22px;
    width: 22px;
    height: 22px;
    border-radius: 5px;
}
.btn-check:checked + .helios-license-card .helios-entity-tile {
    background-color: var(--bs-primary);
    color: #fff;
}
.helios-license-card-text {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-width: 0;          /* zonder dit overflowt text-truncate niet binnen flex */
}
.helios-license-card-text .text-truncate {
    line-height: 1.25;
}

/* ===== helios-badge-strip ==================================================
   Wrap-container voor icon/text-badges met auto-clamp op N regels. De
   helper-JS (helios-badge-strip.js) meet na render hoeveel badges in
   `data-clamp` rijen passen en collapsed de overflow in een
   ".helios-badge-strip-more" badge ("+N") met tooltip die de verborgen
   labels lijst.

   Layout (flex/wrap/gap) staat als Bootstrap-utility-classes op de
   markup zelf (zie tpl/helios/badge-strip.php), zodat de strip ook
   zonder JS een nette default heeft. Deze sectie is daarom dun — alleen
   de "+N"-badge en flex-alignment.
============================================================================*/
.helios-badge-strip {
    align-items: flex-start;
}
.helios-badge-strip-more {
    cursor: help;
}
.helios-badge-strip-more.helios-badge-strip-more-clickable {
    /* Modal-modus — pointer + lichte hover-state om de klikbaarheid
       visueel te onderscheiden van de tooltip-only variant. */
    cursor: pointer;
    transition: background-color .12s ease, border-color .12s ease;
}
.helios-badge-strip-more.helios-badge-strip-more-clickable:hover,
.helios-badge-strip-more.helios-badge-strip-more-clickable:focus-visible {
    background-color: var(--helios-surface-hover, rgba(0, 0, 0, .06)) !important;
    border-color: var(--helios-border-strong, rgba(0, 0, 0, .25)) !important;
}

/* helios-badge-strip modal — lijst-weergave van álle items (zichtbaar +
   verborgen, incl. niet-inbegrepen). Niet-inbegrepen items krijgen
   opacity + line-through op het label (icoon blijft leesbaar zodat
   herkenning per row consistent blijft). */
.helios-badge-strip-modal-item {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: .5rem .25rem;
    /* Theme-aware tokens — --bs-body-color / --bs-secondary-color /
       --bs-border-color zijn in Orbit niet dark-overridden (statische
       light-waarden). --helios-text / --helios-muted / --helios-border-
       subtle wel; zie main.css :root + dark.css token-block. */
    border-bottom: 1px solid var(--helios-border-subtle);
    color: var(--helios-text);
}
.helios-badge-strip-modal-item:last-child {
    border-bottom: 0;
}
.helios-badge-strip-modal-item > i,
.helios-badge-strip-modal-item > svg {
    flex-shrink: 0;
    color: var(--helios-muted);
}
.helios-badge-strip-modal-item.is-not-included {
    opacity: .45;
}
.helios-badge-strip-modal-item.is-not-included .helios-badge-strip-modal-label {
    text-decoration: line-through;
}

/* Multi-koloms variant — `display: grid` op md+ zodat items row-major
   over N kolommen verdeeld worden. Op smalle viewports valt de lijst
   terug op 1 kolom (default block-flow). md = 768px. */
@media (min-width: 768px) {
    .helios-feature-list-cols {
        display: grid;
        column-gap: 1.25rem;
    }
    .helios-feature-list-cols-2 { grid-template-columns: 1fr 1fr; }
    .helios-feature-list-cols-3 { grid-template-columns: 1fr 1fr 1fr; }
    .helios-feature-list-cols-4 { grid-template-columns: 1fr 1fr 1fr 1fr; }
}

/* ============================================================================
   Orbit fragment-loader — refresh-button feedback.
   ----------------------------------------------------------------------------
   Tijdens een handmatige refresh markeert orbit-fragment-loader.js de knop met
   `data-orbit-refreshing="1"` + `disabled`. We laten dan het lucide icoontje
   binnen de knop ronddraaien zodat de gebruiker visuele bevestiging heeft dat
   z'n klik is geregistreerd. Andere helios-spin-animaties (intelligence) zijn
   eigen keyframes; deze blijft strak begrensd op de fragment-refresh-knop.
============================================================================ */
@keyframes orbit-fragment-spin {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}
[data-orbit-refreshing="1"] .orbit-fragment-refresh-icon {
    animation: orbit-fragment-spin 0.9s linear infinite;
    transform-origin: 50% 50%;
}
[data-orbit-refreshing="1"] {
    /* `disabled` zorgt al voor pointer-events:none + lichtere opacity in BS,
       maar opacity overschrijven we naar iets minder hard zodat de knop ook
       tijdens refresh nog goed leesbaar blijft. */
    opacity: .85;
    cursor: progress;
}

/* ===== helios-radio-card ===================================================
   Generic card-styled radio-tile, globaal inzetbaar in form-flows waar je
   een keuze uit één of meer "kandidaten" met een visuele kaart wil aanbieden
   in plaats van een dropdown. Werkt op het Bootstrap `btn-check + label`
   pattern: de radio-input is visually-hidden, de label is de kaart en
   `:checked` levert de primary-accent. Alle visuele states gebruiken
   theme-aware tokens (`--helios-surface-*`, `--helios-text`,
   `--helios-border-subtle`) zodat dark-mode automatisch werkt.

   Eerste use-case: server-picker op /dashboard/servers/ips/request.
   Volgende use-cases (denkbaar): pakket-keuze, license-tier, address-picker.

   Mark-up:
   <input type="radio" class="btn-check" id="…" [disabled]>
   <label class="helios-radio-card [.is-disabled]" for="…">
       <div class="helios-radio-card__head">
           <i class="helios-radio-card__icon"></i>
           <div class="helios-radio-card__body">
               <div class="helios-radio-card__title">…</div>
               <div class="helios-radio-card__subtitle">…</div>
           </div>
       </div>
       <div class="helios-radio-card__meta">…badges/counters…</div>
   </label>
   ============================================================================ */
.helios-radio-card {
    display: flex;
    flex-direction: column;
    gap: .65rem;
    height: 100%;
    padding: .9rem 1rem;
    background: var(--helios-surface-raised, #fff);
    color: var(--helios-text, #212529);
    border: 1px solid var(--helios-border-subtle, var(--bs-border-color));
    border-radius: var(--orbit-radius, 10px);
    cursor: pointer;
    transition: border-color .12s ease, box-shadow .12s ease, background-color .12s ease;
    margin: 0;
}
.helios-radio-card:hover {
    border-color: rgba(var(--bs-primary-rgb), .45);
    box-shadow: 0 1px 4px rgba(0, 0, 0, .06);
}
.btn-check:focus-visible + .helios-radio-card {
    box-shadow: 0 0 0 .2rem rgba(var(--bs-primary-rgb), .25);
    border-color: rgba(var(--bs-primary-rgb), .55);
}
.btn-check:checked + .helios-radio-card {
    border-color: var(--orbit-primary, var(--bs-primary));
    background-color: color-mix(in srgb, var(--orbit-primary, var(--bs-primary)) 7%, var(--helios-surface-raised, #fff));
    box-shadow: 0 0 0 1px var(--orbit-primary, var(--bs-primary)) inset;
}
.helios-radio-card.is-disabled,
.btn-check:disabled + .helios-radio-card {
    cursor: not-allowed;
    opacity: .55;
    background-color: var(--helios-surface-sunken, #f8f9fa);
}
.btn-check:disabled + .helios-radio-card:hover {
    border-color: var(--helios-border-subtle, var(--bs-border-color));
    box-shadow: none;
}

.helios-radio-card__head {
    display: flex;
    align-items: flex-start;
    gap: .55rem;
    min-width: 0;
}
.helios-radio-card__icon {
    width: 18px;
    height: 18px;
    flex-shrink: 0;
    color: var(--helios-muted, #6c757d);
    margin-top: 2px;
}
.btn-check:checked + .helios-radio-card .helios-radio-card__icon {
    color: var(--orbit-primary, var(--bs-primary));
}
.helios-radio-card__body {
    min-width: 0;
    flex-grow: 1;
}
.helios-radio-card__title {
    font-weight: 600;
    color: var(--helios-text, inherit);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.helios-radio-card__subtitle {
    font-size: .8125rem;
    color: var(--helios-muted, #6c757d);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: var(--bs-font-monospace, ui-monospace, SFMono-Regular, Menlo, Monaco, "Courier New", monospace);
}
/* Hint-variant — voor prose-tekst (mode-keuze, optie-hint) waar mono +
   nowrap+ellipsis ongewenst zijn. Gebruik wanneer de subtitle een korte
   uitleg is i.p.v. een ID/hostname/code. */
.helios-radio-card__hint {
    font-size: .8125rem;
    color: var(--helios-muted, #6c757d);
    line-height: 1.35;
}
.helios-radio-card__meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: .25rem .5rem;
    font-size: .8125rem;
}

/* Invalid-group: wrapper rood-tinted wanneer required radio-set leeg blijft. */
.is-invalid-group .helios-radio-card {
    border-color: rgba(var(--bs-danger-rgb), .55);
}

/* Dark-mode fine-tuning — bevatte voorheen `background: #fff` hard-coded.
   Tokens regelen nu de meeste states; alleen de checked-tint heeft een
   subtiele bump nodig zodat hij ook op de dark surface kleur bekent. */
[data-theme="dark"] .btn-check:checked + .helios-radio-card {
    background-color: color-mix(in srgb, var(--orbit-primary, var(--bs-primary)) 14%, var(--helios-surface-raised, #151e28));
}
@media (prefers-color-scheme: dark) {
    [data-theme="auto"] .btn-check:checked + .helios-radio-card {
        background-color: color-mix(in srgb, var(--orbit-primary, var(--bs-primary)) 14%, var(--helios-surface-raised, #151e28));
    }
}

/* ----------------------------------------------------------------
   Select2 multi-select choice pills — globale Orbit-styling.

   Overruled de orbit-blauwe blokken die uit het bootstrap-5 theme
   defaults komen. Compact (font .8em), subtiele border, leesbaar
   kruisje. Wordt gebruikt door élke <select multiple data-helios-…>
   of select2.init({theme:'bootstrap-5', multiple: …}).

   Light- en dark-mode tokens komen uit de Helios-palette zodat ze
   meegaan met theme-toggle. Bestaande dark.css-rules (raw
   `.select2-selection__choice` zonder bootstrap-5-prefix) blijven
   de --default theme dekken; deze rules zijn specifieker.
---------------------------------------------------------------- */
.select2-container--bootstrap-5 .select2-selection--multiple .select2-selection__choice {
    background-color: var(--helios-surface-raised, #f3f5f7);
    border: 1px solid var(--helios-border-subtle, rgba(0, 0, 0, .12));
    color: var(--helios-text, #1a3150);
    font-size: .8125rem;
    line-height: 1.2;
    padding: .15rem .45rem .15rem .55rem;
    border-radius: .375rem;
    margin: .15rem .25rem .15rem 0;
    display: inline-flex;
    align-items: center;
    gap: .35rem;
}
.select2-container--bootstrap-5 .select2-selection--multiple .select2-selection__choice__display {
    padding: 0;
}
.select2-container--bootstrap-5 .select2-selection--multiple .select2-selection__choice__remove {
    color: var(--helios-text, #1a3150);
    opacity: .55;
    border: 0;
    background: transparent;
    padding: 0 .2rem;
    line-height: 1;
    font-size: 1.05em;
    font-weight: 600;
    transition: opacity .12s ease;
    cursor: pointer;
}
.select2-container--bootstrap-5 .select2-selection--multiple .select2-selection__choice__remove:hover,
.select2-container--bootstrap-5 .select2-selection--multiple .select2-selection__choice__remove:focus {
    opacity: 1;
    color: var(--bs-danger, #b8324a);
    background: transparent;
}

/* Dark-mode override — donker oppervlak + lichte tekst. Dark.css had
   alleen rules voor de --default theme; deze rule dekt het
   --bootstrap-5 theme dat Orbit standaard gebruikt. */
html[data-theme="dark"] .select2-container--bootstrap-5 .select2-selection--multiple .select2-selection__choice {
    background-color: var(--helios-surface-raised, #1c2733);
    border-color: rgba(255, 255, 255, .14);
    color: var(--helios-text, #e6eaf0);
}
html[data-theme="dark"] .select2-container--bootstrap-5 .select2-selection--multiple .select2-selection__choice__remove {
    color: var(--helios-text, #e6eaf0);
}
@media (prefers-color-scheme: dark) {
    html[data-theme="auto"] .select2-container--bootstrap-5 .select2-selection--multiple .select2-selection__choice {
        background-color: var(--helios-surface-raised, #1c2733);
        border-color: rgba(255, 255, 255, .14);
        color: var(--helios-text, #e6eaf0);
    }
    html[data-theme="auto"] .select2-container--bootstrap-5 .select2-selection--multiple .select2-selection__choice__remove {
        color: var(--helios-text, #e6eaf0);
    }
}

/* ==========================================================================
   helios-bulk-actions — card-grid multi-select UX
   ========================================================================== */

/* Checkbox slot: top-right corner of card-body, z-index above stretched-link */
.bulk-checkbox-slot {
    position: absolute;
    top: 8px;
    right: 8px;
    z-index: 3;
    display: none; /* hidden by default; JS toggles visibility in bulk-mode */
}

/* Selected card: primary border + subtle glow */
.bulk-selected > .d-none.d-md-block .card,
.bulk-selected > .card {
    border: 2px solid var(--bs-primary) !important;
    box-shadow: 0 0 0 3px var(--bs-primary-bg-subtle) !important;
}

/* Cursor pointer on card in bulk-mode so users know it's clickable */
.bulk-mode-active .card {
    cursor: pointer;
}

/* helios-bulk-actions — disable card-link nav in bulk-mode so card-click can toggle selection */
.bulk-mode-active .card a.stretched-link,
.bulk-mode-active .card a.card-link,
.bulk-mode-active .card .row-link,
.bulk-mode-active .package-assignment-card a,
.bulk-mode-active .sf-assignment-card a {
    pointer-events: none;
}
/* Re-enable interactive controls so checkbox/delete/dropdown still work in bulk-mode */
.bulk-mode-active .card input,
.bulk-mode-active .card button,
.bulk-mode-active .card .dropdown,
.bulk-mode-active .card [data-bulk-ignore] {
    pointer-events: auto;
}

/* Bulk-disabled items: in bulk-mode toon ze gedimd zodat duidelijk is dat ze
   niet selecteerbaar zijn. Buiten bulk-mode geen styling — de cards moeten
   normaal werken (stretched-link blijft actief). De helios-bulk-actions.js
   skipt deze items voor checkbox-injectie + card-click toggle. */
.bulk-mode-active .bulk-disabled > .d-none.d-md-block .card,
.bulk-mode-active .bulk-disabled > .card {
    opacity: .55;
    cursor: not-allowed;
}
.bulk-mode-active .bulk-disabled .card a.stretched-link,
.bulk-mode-active .bulk-disabled .card a.card-link {
    pointer-events: none;
}

/* ================================================================
   Spamfilter — compare-table (packages/compare)
   ================================================================ */

/* Highlighted column: most-used package gets a primary-subtle tint */
.spamfilter-compare .package-highlighted {
    background-color: var(--bs-primary-bg-subtle);
}

/* Section-header rows: visual separator between feature categories */
.spamfilter-compare .table-section-header td {
    padding-top: 10px;
    padding-bottom: 10px;
}

/* Sticky thead: ensure solid background so rows don't bleed through */
.spamfilter-compare thead.position-sticky th {
    background-clip: padding-box;
    background-color: var(--helios-surface-raised, #fff);
}

[data-theme="dark"] .spamfilter-compare thead.position-sticky th {
    background-color: var(--helios-surface-raised, #1e1e2e);
}


/* Spamfilter admin assignment-view — filter-reset toggle hidden states.
   Used by JS to hide reset-buttons when the filter state is in its default. */
.sfal-reset-hidden,
.sfas-reset-hidden {
    display: none !important;
}

/* ===========================================================================
   Orbit-list partial (Phase 2)
   Spec: docs/superpowers/specs/2026-05-17-helios-list-v2-design.md §3.2
   =========================================================================== */

.orbit-list { position: relative; }

/* View toggle: pure CSS swap, no JS style mutation */
.orbit-list[data-orbit-list-view="card"] [data-orbit-list-view-mode="list"] { display: none; }
.orbit-list[data-orbit-list-view="list"] [data-orbit-list-view-mode="card"] { display: none; }

/* Bulk-mode visual state */
.orbit-list .orbit-list-bulk-checkbox-slot { display: none; }
.orbit-list.orbit-list-bulk-mode .orbit-list-bulk-checkbox-slot { display: block !important; }
.orbit-list.orbit-list-bulk-mode .orbit-list-card-wrap .card-footer,
.orbit-list.orbit-list-bulk-mode .orbit-list-card-wrap .dropdown {
    display: none !important;
}
.orbit-list .orbit-list-bulk-selected {
    box-shadow: inset 0 0 0 2px var(--bs-primary), 0 0 0 1px var(--bs-primary);
    transition: box-shadow 120ms ease-out;
}

/* Loading shimmer — applied to rows-container while XHR in flight */
.orbit-list-rows[aria-busy="true"] .orbit-list-card-wrap,
.orbit-list-rows[aria-busy="true"] .orbit-list-table-wrap tbody tr {
    opacity: 0.35;
    pointer-events: none;
    transition: opacity 80ms linear;
}

/* Active-filters chip-row */
.orbit-list-active-filters .orbit-list-filter-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.125rem 0.5rem;
    border-radius: var(--orbit-radius);
    background: var(--helios-surface-sunken, var(--bs-light));
    border: 1px solid var(--helios-border-subtle, var(--bs-border-color));
    font-size: 0.8125rem;
    margin-right: 0.25rem;
}
.orbit-list-active-filters .orbit-list-filter-chip button {
    background: none;
    border: none;
    padding: 0;
    line-height: 1;
    color: var(--helios-text-muted, var(--bs-secondary-color));
}
.orbit-list-active-filters .orbit-list-filter-chip button:hover {
    color: var(--bs-danger);
}

/* Card bulk-mode position anchor — required for absolute checkbox slot */
.orbit-list .orbit-list-bulk-position { position: relative; }

/* "Load more" button — full-width on mobile */
@media (max-width: 767px) {
    .orbit-list-load-more .btn { width: 100%; }
}

/* ============================================================
   Orbit Toolbar — globale floating tool-strip (admin-only).
   Slot-pattern: huidige tool is notification-bell, future-proof
   voor extra tools zonder layout-changes.
   ============================================================ */

.orbit-toolbar {
    position: fixed;
    top: 12px;
    right: 12px;
    z-index: 1075;
    display: flex;
    align-items: center;
    gap: 8px;
    pointer-events: none;
}
.orbit-toolbar > * {
    pointer-events: auto;
}

/* Mobile-slot variant zit IN #mobileHeader, geen fixed positioning */
.orbit-toolbar--mobile {
    position: static;
    margin-left: auto;
    margin-right: 8px;
    gap: 6px;
}

.orbit-toolbar-tool {
    width: 36px;
    height: 36px;
    border-radius: var(--orbit-radius, 10px);
    background: var(--helios-surface-raised);
    border: 1px solid var(--helios-border-subtle);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
    color: var(--helios-text);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    position: relative;
    transition: background-color .15s ease, transform .12s ease;
    cursor: pointer;
}
.orbit-toolbar--mobile .orbit-toolbar-tool {
    /* Match mobile-nav hamburger (header.php line ~167): 44×44, semi-transparent
       black borders + shadow-sm — werkt op zowel light- als dark-styled mobileHeader. */
    width: 44px;
    height: 44px;
    border-radius: var(--bs-border-radius, 0.375rem);
    border: 1px solid rgba(0, 0, 0, 0.15);
    border-bottom: 2px solid rgba(0, 0, 0, 0.15);
    box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
    background: var(--helios-surface-raised);
}
.orbit-toolbar-tool:hover {
    background: var(--helios-surface-sunken);
}
.orbit-toolbar-tool:focus-visible {
    outline: 2px solid var(--bs-primary);
    outline-offset: 2px;
}
.orbit-toolbar-tool[aria-expanded="true"] {
    background: var(--helios-surface-sunken);
}

[data-toolbar-bell-icon].is-ringing {
    animation: orbit-bell-ring 1.0s ease-in-out 2;
    transform-origin: top center;
}

@keyframes orbit-bell-ring {                                                                    /* lint-ok */
    0%, 100% { transform: rotate(0); }
    20%      { transform: rotate(12deg); }
    40%      { transform: rotate(-10deg); }
    60%      { transform: rotate(7deg); }
    80%      { transform: rotate(-5deg); }
}

.orbit-toolbar-badge {
    position: absolute;
    top: -4px;
    right: -4px;
    min-width: 18px;
    height: 18px;
    background: var(--bs-danger);
    color: #fff;
    border-radius: 9px;
    font-size: 11px;
    font-weight: 600;
    padding: 0 5px;
    line-height: 18px;
    text-align: center;
    box-shadow: 0 0 0 2px var(--helios-surface-raised);
}
.orbit-toolbar-badge[data-pulse="1"] {
    animation: orbit-toolbar-badge-pulse 1.6s ease-out 2;
}
@keyframes orbit-toolbar-badge-pulse {                                                          /* lint-ok */
    0%   { transform: scale(1);   box-shadow: 0 0 0 2px var(--helios-surface-raised), 0 0 0 0 rgba(220, 53, 69, 0.5); }
    50%  { transform: scale(1.1); box-shadow: 0 0 0 2px var(--helios-surface-raised), 0 0 0 8px rgba(220, 53, 69, 0); }
    100% { transform: scale(1);   box-shadow: 0 0 0 2px var(--helios-surface-raised), 0 0 0 0 rgba(220, 53, 69, 0); }
}

/* has-critical: continue subtiele halo-pulse zolang er ≥1 critical-notification
   ongelezen is. Stopt vanzelf zodra de poll meldt dat has_critical=false.
   Mutually exclusive met data-pulse (one-off insert-pulse heeft voorrang). */
.orbit-toolbar-badge[data-has-critical="1"]:not([data-pulse="1"]) {
    animation: orbit-toolbar-badge-critical 2.2s ease-in-out infinite;
}
@keyframes orbit-toolbar-badge-critical {                                                       /* lint-ok */
    0%, 100% { box-shadow: 0 0 0 2px var(--helios-surface-raised), 0 0 0 0   rgba(220, 53, 69, 0.55); }
    50%      { box-shadow: 0 0 0 2px var(--helios-surface-raised), 0 0 0 7px rgba(220, 53, 69, 0); }
}

.orbit-toolbar-panel {
    width: 380px;
    max-width: calc(100vw - 24px);
    max-height: 70vh;
    overflow-y: auto;
    padding: 0;
    border-radius: var(--orbit-radius, 10px);
}

.orbit-toolbar-panel-skeleton,
.orbit-toolbar-panel-empty,
.orbit-toolbar-panel-error {
    pointer-events: none;
}

.orbit-toolbar-panel-item {
    position: relative;
    border-bottom: 1px solid var(--helios-border-subtle);
}
.orbit-toolbar-panel-item:last-child {
    border-bottom: none;
}
.orbit-toolbar-panel-item-stripe {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 3px;
}
.orbit-toolbar-panel-item-btn {
    width: 100%;
    text-align: left;
    background: transparent;
    border: 0;
    padding: 10px 12px 10px 16px;
    color: var(--helios-text);
    cursor: pointer;
}
.orbit-toolbar-panel-item-btn:hover {
    background: var(--helios-surface-sunken);
}
.orbit-toolbar-panel-item-icon {
    flex-shrink: 0;
    color: var(--helios-text-muted);
}
.orbit-toolbar-panel-footer a {
    color: var(--helios-text);
}
.orbit-toolbar-panel-footer a:hover {
    background: var(--helios-surface-sunken);
}

@keyframes orbit-spin {                                                                          /* lint-ok */
    to { transform: rotate(360deg); }
}

/* ============================================================
   Admin Notification Card — notification list-item op de
   /backend/system/notifications pagina (card-list, NIET DataTable).
   ============================================================ */

.admin-notification {
    position: relative;
    overflow: hidden;
    border: 1px solid var(--helios-border-subtle);
    background: var(--helios-surface-raised);
    transition: background-color .15s ease;
}
.admin-notification[data-notification-state="unread"] {
    background: var(--helios-surface-sunken);
}
.admin-notification[data-notification-state="dismissed"] {
    opacity: .65;
}
.admin-notification-stripe {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 4px;
    background: var(--helios-border-subtle);
}
.admin-notification[data-notification-severity="warning"]  .admin-notification-stripe { background: var(--bs-warning); }
.admin-notification[data-notification-severity="danger"]   .admin-notification-stripe { background: var(--bs-danger); }
.admin-notification[data-notification-severity="critical"] .admin-notification-stripe { background: var(--bs-danger); }

.admin-notification-icon {
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    border-radius: var(--orbit-radius, 10px);
    background: var(--helios-surface-sunken);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--icon-color, var(--helios-text-muted));
}
.admin-notification[data-notification-state="unread"] .admin-notification-icon {
    background: var(--helios-surface-raised);
}
.admin-notification-unread-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--bs-primary);
    margin-right: 6px;
    vertical-align: middle;
}
.admin-notification-actions .btn {
    font-size: 12px;
}

/* ============================================================
   Orbit Toolbar — mobile offcanvas-end (vervangt de desktop-dropdown
   op <xxl). Slide-in van rechts mirrort de sidebar (slide-start van
   links) — vertrouwd mobile pattern. Op <sm: viewport-fill voor
   native notification-feed feel. Op ≥sm: zijbalk-overlay (~420px).
   ============================================================ */

.orbit-toolbar-mobile-panel {
    /* Laat ~8% backdrop-strip links zichtbaar op phones, zodat tap-buiten-
       sluit altijd mogelijk is (Bootstrap's standaard sidebar-pattern).
       min(420px, 92vw): op smalle phones wint 92vw, op bredere caps 420px. */
    --bs-offcanvas-width: min(420px, 92vw);
    background: var(--helios-surface-raised);
    color: var(--helios-text);
}
.orbit-toolbar-mobile-panel .offcanvas-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
}

/* Op viewports waar #mobileHeader zichtbaar is (<xxl): offcanvas start
   onder de 64px-header. mobileHeader's `shadow-sm` cast ~6px shadow naar
   beneden — top:72px geeft 2px ademruimte zodat panel-content niet visueel
   onder de header-shadow valt. Backdrop blijft viewport-vol (z-1040),
   mobileHeader (z-1200) staat erboven zodat de bell-button bereikbaar blijft
   (toggle-close).

   Selector `.offcanvas.orbit-toolbar-mobile-panel` is (0,2,0) — wint over
   Bootstrap's `.offcanvas-end` (0,1,0) `top:0` default ongeacht load-order.

   Bootstrap offcanvas-end heeft default top:0 bottom:0; we override top:72
   en laten bottom:0 staan — hoogte rekt automatisch tot onderkant viewport. */
@media (max-width: 1399.98px) {                                                 /* lint-ok */
    .offcanvas.orbit-toolbar-mobile-panel,
    .offcanvas.helios-search-offcanvas {
        top: 64px;
        border-top: 1px solid var(--helios-border-subtle);
        /* Expliciete hoogte met dvh-fallback: Bootstrap's default `bottom:0` +
           `position:fixed` werkt met top:64px op desktop, maar op iOS Safari
           rekent `100vh` de URL-bar mee óók als die ingeklapt is — daardoor
           valt de onderkant van de offcanvas onder het viewport en is de
           laatste notificatie niet meer bereikbaar. `100dvh` (dynamic viewport
           height) shrinks/grows met de URL-bar; `100vh` blijft als fallback
           voor browsers zonder dvh-support (~5% mid-2024). */
        height: calc(100vh - 64px);
        /* GEEN `will-change: transform` hier — dat plaatste de offcanvas op zijn
           eigen GPU compositing-laag, wat op iOS Safari de visual-viewport
           tijdens DOM-mutatie kortstondig liet desynchroniseren van de
           layout-viewport. Visueel: offcanvas verspringt ~80px naar beneden
           met whitespace bovenaan tijdens AJAX-return (video bug-frame f19).
           De oorspronkelijke reden (loading-bar GPU-thrash) was een hypothese
           die nooit bevestigd werd; reverten lost het concrete jump-probleem
           op zonder dat we de loading-bar issue zien terugkomen. */
    }
    @supports (height: 100dvh) {
        .offcanvas.orbit-toolbar-mobile-panel,
        .offcanvas.helios-search-offcanvas {
            height: calc(100dvh - 64px);
        }
    }
}

/* ────────────────────────────────────────────────────────────────────
   Helios — Spinning icon (manual refresh-knop in history filter-bar).
   ──────────────────────────────────────────────────────────────────── */
.helios-spinning [data-lucide] {
    animation: helios-spin .8s linear infinite;
}
@keyframes helios-spin {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}

/* ────────────────────────────────────────────────────────────────────
   Helios — Activity-skeleton (laad-placeholder bij filter-submit + load-more).
   Hoogte + spacing 1:1 met .helios-activity-row zodat de overgang naadloos
   voelt (geen "spring" wanneer skeleton naar echte card swapt). De
   icon-placeholder matcht het 20x20 lucide-icoon + margin-top 2px.
   ──────────────────────────────────────────────────────────────────── */
.helios-activity-skeleton .helios-activity-skeleton-icon {
    width: 20px;
    height: 20px;
    margin-top: 2px;
    flex-shrink: 0;
}

/* ────────────────────────────────────────────────────────────────────
   Helios — Activity-row in domain-history timeline (consistent spacing,
   geneste wijzigingen-card met eigen border voor hierarchie).
   ──────────────────────────────────────────────────────────────────── */
.helios-activity-row .alert {
    /* Inline alert binnen card-body — strakker dan default alert om
       de visuele dichtheid van het timeline-blok te bewaren. */
    border-radius: 6px;
}
.helios-activity-row .helios-activity-changes {
    background: transparent;
    border-color: var(--helios-border-subtle, #e9ecef) !important;
    box-shadow: none;
}
.helios-activity-row .helios-activity-changes > .card-header {
    cursor: pointer;
    transition: background-color .15s ease-in-out;
}
.helios-activity-row .helios-activity-changes > .card-header:hover {
    background-color: rgba(0, 0, 0, .03) !important;
}

/* ────────────────────────────────────────────────────────────────────
   Helios — Diff-renderer (wijzigingen-inhoud binnen activity-row).
   Consistent sectie-model: header + content, sub-sections met dezelfde
   structuur. Subtle border-top scheidt secties — geen mb-3 bottom op
   laatste sectie om dubbele whitespace tegen card-body py-3 te voorkomen.

   Alle body-text binnen .helios-diff-content op .875rem (== Bootstrap small).
   Header-tekstkleuren via --helios-* tokens (theme-aware light + dark).
   --bs-secondary-color / --bs-body-color zijn NIET theme-aware in Orbit.
   ──────────────────────────────────────────────────────────────────── */
.helios-diff-content {
    font-size: .875rem;
}
.helios-diff-content > section.helios-diff-section + section.helios-diff-section {
    margin-top: 1rem;
    padding-top: 1rem;
    border-top: 1px solid var(--helios-border-subtle, #e9ecef);
}
.helios-diff-content > section.helios-diff-section:last-child {
    margin-bottom: 0;
}
.helios-diff-section-header {
    font-size: .75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--helios-muted, #6c757d);
    margin-bottom: .5rem;
}

/* Sub-section binnen een section (bv. per-rol contact-diff, per-DNS-section).
   Visueel onderscheid via subtiel inset-blok ipv eigen card. Collapsible
   variant gebruikt zelfde header maar met chevron-rotatie. */
.helios-diff-subsection {
    margin-top: .75rem;
}
.helios-diff-subsection:first-child {
    margin-top: 0;
}
.helios-diff-subsection-header {
    font-size: .8125rem;
    font-weight: 600;
    color: var(--helios-text, #212529);
    padding: .375rem 0;
    display: flex;
    align-items: center;
    gap: .375rem;
    border-bottom: 1px solid var(--helios-border-subtle, #e9ecef);
    margin-bottom: .5rem;
}
.helios-diff-subsection--collapsible .helios-diff-subsection-header {
    cursor: pointer;
    transition: color .15s ease-in-out;
}
.helios-diff-subsection--collapsible .helios-diff-subsection-header:hover {
    color: var(--bs-primary, #6e9ec2);
}

/* Compacte diff-tabel — inline-tabel canon: subtiele border + radius zodat
   hij visueel aansluit op de grotere card-wrapped tabellen in Orbit.
   Uniforme padding rondom in ALLE cellen (header + body), edges krijgen
   iets extra horizontale ruimte voor visuele rust binnen de border. */
.helios-diff-table {
    border: 1px solid var(--helios-border-subtle, #e9ecef);
    border-radius: 6px;
    border-collapse: separate;
    border-spacing: 0;
    overflow: hidden; /* clipt cell-corners zodat border-radius op de tabel werkt */
    background-color: transparent;
}
.helios-diff-table > thead > tr > th,
.helios-diff-table > tbody > tr > td {
    padding: .375rem .5rem;       /* 6px 8px — close to user's 4px-rondom request, readable */
    border-top: none;
    border-bottom: 0;             /* override Bootstrap's .table cell border-bottom — anders
                                     krijg je een dubbele border onderaan (cell-bottom + table-border) */
    vertical-align: top;
}
.helios-diff-table > thead > tr > th:first-child,
.helios-diff-table > tbody > tr > td:first-child {
    padding-left: .625rem;        /* 10px — iets extra zodat tekst niet tegen de border drukt */
}
.helios-diff-table > thead > tr > th:last-child,
.helios-diff-table > tbody > tr > td:last-child {
    padding-right: .625rem;
}
.helios-diff-table > thead > tr > th {
    background-color: color-mix(in srgb, var(--helios-border-subtle, #e9ecef) 35%, transparent);
    border-bottom: 1px solid var(--helios-border-subtle, #e9ecef);
}
.helios-diff-table > tbody > tr + tr > td {
    border-top: 1px solid color-mix(in srgb, var(--helios-border-subtle, #e9ecef) 60%, transparent);
}
/* Lange waardes (URLs, identifiers, sentences) breken binnen de cel-breedte
   ipv te overflowen of de tabel uit te zetten. Op alle viewports — niet alleen
   mobile — anders kan een lange string het hele wijzigingen-card uit z'n
   container drukken. */
.helios-diff-table > tbody > tr > td {
    overflow-wrap: anywhere;
    word-break: break-word;
}

/* <pre>-blokken binnen wijzigingen: word-wrap aan zodat lange JSON / provider-
   responses binnen de cel-breedte blijven. overflow-y blijft staan voor de
   max-height-cap. */
.helios-diff-content pre,
.helios-activity-row pre.helios-pre-wrap {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    word-break: break-word;
}

/* ────────────────────────────────────────────────────────────────────
   Helios — History-tab mobiele optimalisaties (<md = 767.98px).
   Sluiten aan op de globale mobile-rules: .form-control/.form-select
   krijgen 44px min-height op mobile, .btn krijgt extra vertical padding.
   ──────────────────────────────────────────────────────────────────── */

/* Desktop default: filter-body altijd zichtbaar (geen collapse-toggle nodig). */
@media (min-width: 768px) {
    .helios-history-filter-body {
        display: block !important;
        height: auto !important;
    }
    .helios-history-filter-mobile-toggle {
        display: none !important;
    }
}

@media (max-width: 767.98px) {
    /* Mobile filter-toggle: tap-target voldoende, chevron-rotatie via
       helios-collapse-toggle, achtergrond match bij card-body (geen card-header tint). */
    .helios-history-filter-mobile-toggle {
        min-height: 44px;
        background-color: var(--bs-body-bg);
    }
    /* Filter-action knoppen full-width op mobiel (Reset + Refresh). */
    .helios-history-filter-actions {
        width: 100%;
    }
    .helios-history-filter-actions .btn {
        flex: 1 1 0;
    }
}

/* Activity-row primary line: stack relative-time onder title-group op smal scherm.
   align-items-baseline blijft op desktop voor perfecte tekst-uitlijning. */
@media (max-width: 575.98px) {
    .helios-activity-primary {
        flex-direction: column;
        align-items: flex-start !important;
        gap: .25rem !important;
    }
    .helios-activity-primary .text-nowrap {
        white-space: normal !important;
    }
    /* Lange event-titels (bv. "Domein testdomein4.nl gesynchroniseerd met
       provider") nemen op smalle viewports hun eigen rij in. flex-basis:100%
       op de titel-span forceert dat de badge + actor + bulk altijd samen op
       de NA-rij vallen — niet halverwege de titel gepusht zoals default
       flex-wrap. Resultaat: predictable layout, badge en actor blijven
       visueel bij elkaar als één meta-blok. */
    .helios-activity-primary .helios-activity-title {
        flex-basis: 100%;
        line-height: 1.4;
    }
    /* Action-knoppen full-width stack op smal scherm — beter tappen + duidelijke
       hierarchie dan inline-wrap gedrag. */
    .helios-activity-actions {
        flex-direction: column !important;
        align-items: stretch !important;
    }
    .helios-activity-actions .btn {
        justify-content: center;
        width: 100%;
    }
    /* Card-body horizontale padding inkrimpen voor meer content-breedte. */
    .helios-activity-row > .card-body {
        padding-left: .75rem;
        padding-right: .75rem;
    }
    /* Diff-tabel cellen iets compacter op smal scherm zodat 3 kolommen
       passen zonder horizontale scroll. */
    .helios-diff-table > thead > tr > th,
    .helios-diff-table > tbody > tr > td {
        padding: .3125rem .375rem;
    }
    .helios-diff-table > thead > tr > th:first-child,
    .helios-diff-table > tbody > tr > td:first-child {
        padding-left: .5rem;
    }
    .helios-diff-table > thead > tr > th:last-child,
    .helios-diff-table > tbody > tr > td:last-child {
        padding-right: .5rem;
    }
    /* Wijzigingen-collapse header: WCAG tap-target ≥44px. py-2 (16px+content)
       bumpen naar py-3-equivalent zodat tap-target consistent voldoet. */
    .helios-activity-row .helios-activity-changes > .card-header {
        min-height: 44px;
    }
    /* Diff-subsection headers ook iets ruimer voor collapse-variant taps. */
    .helios-diff-subsection--collapsible .helios-diff-subsection-header {
        min-height: 40px;
        padding-top: .5rem;
        padding-bottom: .5rem;
    }
}

/* ────────────────────────────────────────────────────────────────────
   Helios — Notitie-body clickable (opent edit-modal).
   ──────────────────────────────────────────────────────────────────── */
.helios-note-body-clickable {
    cursor: pointer;
    transition: background-color .15s ease-in-out;
}
.helios-note-body-clickable:hover {
    background-color: rgba(255, 193, 7, 0.18) !important;
}
.helios-note-body-clickable:focus-visible {
    outline: 2px solid var(--bs-warning);
    outline-offset: -2px;
}

/* ────────────────────────────────────────────────────────────────────
   Helios — Contacten-tab grid (2 picker-secties naast elkaar op lg+).
   Neutraliseert de mb-3 die de partial standalone gebruikt — de row-
   gutter (g-3) levert de verticale spacing al.
   ──────────────────────────────────────────────────────────────────── */
/* mb-0 vervangt het mb-3 van de partial (g-3 op de row regelt de vertical gap).
   Géén height: 100% — anders rekken admin/tech zich uit tot owner-hoogte (die
   de extra "kopieer naar admin/tech" knop heeft) waardoor er loze witruimte
   onder de preview ontstaat. Asymmetrie (owner net iets hoger) is visueel
   minder storend dan ongebalanceerde top/bottom padding binnen één card. */
.helios-contacts-grid .helios-contact-picker {
    margin-bottom: 0;
}

/* ────────────────────────────────────────────────────────────────────
   Helios — Contact-preview status-block
   Status-tinted inline-card binnen contact-picker preview-area
   (tpl/domains/contact-picker-card.php + bulk-contacts-modal.php).

   Gebruikt de canonical Orbit `--x-status-*-chip-*` tokens (xynta-
   aligned, main.css L193+ light + dark.css L81+ dark) zodat:
     - block-bg = chip-bg  (zachte olijfgroen / oker / bordeaux,
                            semi-transparent overlay in dark — werkt
                            op de outer `bg-light` grijze backdrop én
                            op pure card-bg)
     - block-border = chip-border (subtiele role-rand)
     - block-color  = chip-ink (donkere variant van de role —
                                cascadert naar alle children zodat
                                naam/adres/contact subtle gestemd
                                zijn met de bg, niet dissonant body-color)
     - .text-body-secondary binnen het block inheritert chip-ink met
       opacity .78 — adres/contact-regel blijft visueel ondergeschikt
       aan naam, maar binnen dezelfde tonale familie.

   Badge wordt `.badge.bg-{role}-subtle` (Bootstrap-class) — Orbit
   override't die automatisch via dezelfde chip-tokens (main.css
   L1128-1159). Géén dedicated `.helios-contact-preview-badge` rule
   meer; canon-domain-badge styling (text-uppercase small px-2 py-1)
   matched de rest van /backend/domains.
   ──────────────────────────────────────────────────────────────────── */
.helios-contact-preview {
    margin-top: 1rem;
    border: 1px solid;
    border-radius: var(--orbit-radius, 10px);
    padding: 0.75rem;
}
/* Empty + neutral = neutrale card (witte/card-bg + grijze rand, geen
   role-tint). Visueel consistent met de tinted states — alle 5 states
   renderen als card, alleen kleur verschilt. --bs-card-bg cascadert
   automatisch in dark mode. */
.helios-contact-preview-state-empty,
.helios-contact-preview-state-neutral {
    background-color: var(--bs-card-bg);
    border-color:     var(--bs-border-color);
}
.helios-contact-preview-state-verified {
    background-color: var(--x-status-success-chip-bg);
    border-color:     var(--x-status-success-chip-border);
    color:            var(--x-status-success-chip-ink);
}
.helios-contact-preview-state-pending {
    background-color: var(--x-status-warning-chip-bg);
    border-color:     var(--x-status-warning-chip-border);
    color:            var(--x-status-warning-chip-ink);
}
.helios-contact-preview-state-error {
    background-color: var(--x-status-danger-chip-bg);
    border-color:     var(--x-status-danger-chip-border);
    color:            var(--x-status-danger-chip-ink);
}
/* Secondary regels (adres/contact) binnen tinted block — inherit chip-ink
   met opacity-trick voor subtle tonale demping. text-body-secondary's
   eigen `color` heeft een specifieke utility-override; `!important` is
   nodig om die te neutraliseren. */
.helios-contact-preview-state-verified .text-body-secondary,
.helios-contact-preview-state-pending  .text-body-secondary,
.helios-contact-preview-state-error    .text-body-secondary {
    color: inherit !important;
    opacity: 0.78;
}

/* ────────────────────────────────────────────────────────────────────
   Helios — Contacten card (clickable → contacts tab)
   ──────────────────────────────────────────────────────────────────── */
.helios-contacts-card {
    cursor: pointer;
    transition: box-shadow .15s ease-in-out, transform .15s ease-in-out;
}
.helios-contacts-card:hover {
    box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .08);
}
.helios-contacts-card:focus-visible {
    outline: 2px solid var(--bs-primary);
    outline-offset: 2px;
}
.helios-contacts-card .btn,
.helios-contacts-card .helios-contact-row {
    cursor: pointer;
}
/* Bredere tooltip voor rich contact-info (adres + email + telefoon).
   Tooltip-background is donker (BS default #000), dus labels krijgen een lichte
   semi-transparante kleur i.p.v. text-muted (dat was donkergrijs op zwart = onleesbaar).
   Layout: links-uitgelijnde label/value rijen met een vaste labelkolom voor rust. */
.tooltip.helios-contact-tooltip .tooltip-inner {
    max-width: 340px;
    padding: 0.55rem 0.7rem;
    text-align: left;
    line-height: 1.45;
}
.tooltip.helios-contact-tooltip .helios-contact-tt-row {
    display: flex;
    gap: 0.5rem;
    align-items: baseline;
    margin-bottom: 0.2rem;
}
.tooltip.helios-contact-tooltip .helios-contact-tt-row:last-child {
    margin-bottom: 0;
}
.tooltip.helios-contact-tooltip .helios-contact-tt-label {
    flex: 0 0 4.5rem;
    max-width: 4.5rem;
    color: rgba(255, 255, 255, 0.6);
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.tooltip.helios-contact-tooltip .helios-contact-tt-value {
    flex: 1 1 auto;
    color: #fff;
    word-break: break-word;
}
.tooltip.helios-contact-tooltip .helios-contact-tt-value.font-monospace {
    font-size: 0.85em;
}

/* ============================================================
   Queue-dashboard (pending_operations-bucket op /backend/domains/actions)
   - .helios-queue-health        : top-strip met cron-heartbeat + throughput
   - .helios-queue-stuck         : per-card markering voor stuck items
   - .helios-queue-bulkbar       : action-bar bij bulk-selectie
   ============================================================ */

.helios-queue-health {
    border-left: 3px solid var(--bs-border-color);
}
.helios-queue-health-success {
    border-left-color: var(--bs-success);
    background-color: rgba(var(--bs-success-rgb), 0.04);
}
.helios-queue-health-warning {
    border-left-color: var(--bs-warning);
    background-color: rgba(var(--bs-warning-rgb), 0.06);
}
.helios-queue-health-danger {
    border-left-color: var(--bs-danger);
    background-color: rgba(var(--bs-danger-rgb), 0.06);
}
.helios-queue-health-secondary {
    border-left-color: var(--bs-secondary);
}

/* Stuck-markering: subtiele pulserende gradient achter de stripe. */
.helios-queue-stuck {
    position: relative;
    background-image: linear-gradient(
        to right,
        rgba(var(--bs-danger-rgb), 0.05) 0%,
        rgba(var(--bs-danger-rgb), 0) 40%
    );
}
.helios-queue-stuck::before {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    border-radius: inherit;
    box-shadow: 0 0 0 0 rgba(var(--bs-danger-rgb), 0.35);
    animation: helios-queue-stuck-pulse 2.4s ease-out infinite;
}
@keyframes helios-queue-stuck-pulse {
    0%   { box-shadow: 0 0 0 0    rgba(var(--bs-danger-rgb), 0.35); }
    70%  { box-shadow: 0 0 0 6px  rgba(var(--bs-danger-rgb), 0);    }
    100% { box-shadow: 0 0 0 0    rgba(var(--bs-danger-rgb), 0);    }
}

/* Bulk-bar: lichte zelfde achtergrond als counter-cards, zichtbaar separator. */
.helios-queue-bulkbar {
    border-left: 3px solid var(--bs-primary);
    background-color: rgba(var(--bs-primary-rgb), 0.04);
}

/* Manual-refresh-knop: spin het refresh-icoon tijdens een fragment-fetch.
   OrbitFragments zet data-orbit-refreshing="1" op de trigger tijdens de
   in-flight call (zie orbit-fragment-loader.js refreshExternally). */
button[data-orbit-refreshing="1"] .helios-queue-refresh-icon {
    animation: helios-spin 0.8s linear infinite;
}

/* ─── Helios Search Pill — orbit-toolbar trigger ─────────────────────── */
.helios-search-pill-wrap { display: inline-block; }

.helios-search-pill {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    min-width: 240px;
    padding: .375rem .75rem;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--orbit-radius, 10px);
    background: var(--bs-body-bg);
    color: var(--bs-secondary-color);
    font-size: .875rem;
    cursor: pointer;
    transition: border-color .15s ease, box-shadow .15s ease;
}
.helios-search-pill:hover {
    border-color: var(--bs-primary);
    box-shadow: 0 0 0 .15rem rgba(var(--bs-primary-rgb), .12);
}
.helios-search-pill-label { color: var(--bs-secondary-color); }
.helios-search-pill-kbd {
    font-size: .7rem;
    padding: .1rem .35rem;
    border-radius: 4px;
    background: var(--bs-tertiary-bg);
    color: var(--bs-secondary-color);
    border: 1px solid var(--bs-border-color);
}

.helios-search-panel {
    width: 480px;
    max-height: 70vh;
    overflow-y: auto;
    padding: 0;
}
.helios-search-panel .helios-search-group + .helios-search-group {
    border-top: 1px solid var(--bs-border-color);
}
.helios-search-group-header {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .5rem .75rem;
    font-size: .75rem;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--bs-secondary-color);
    background: var(--bs-tertiary-bg);
}
.helios-search-result {
    display: block;
    padding: .5rem .75rem;
    text-decoration: none;
    color: var(--bs-body-color);
    border-radius: 6px;
}
.helios-search-result:hover,
.helios-search-result[aria-selected="true"] {
    background: var(--bs-tertiary-bg);
}
.helios-search-result strong { font-weight: 600; }

/* Offcanvas-width: laat een backdrop-strip zichtbaar links zodat de
   gebruiker erop kan tikken om te sluiten (mirror van sidebar-pattern).
   min(420px, 92vw) → op smalle phones (<456px) wint 92vw met ~8% backdrop;
   op bredere phones/tablets cap op 420px. */
.helios-search-offcanvas { --bs-offcanvas-width: min(420px, 92vw); }

/* Defensive: ensure mobile search-trigger button is visible inside
   #mobileHeader. Inherits sizing from .orbit-toolbar--mobile .orbit-toolbar-tool
   (44×44). Explicit display blocks any utility-class override that would
   hide the button. */
.helios-search-trigger-mobile {
    display: inline-flex !important;
    flex-shrink: 0;
}

/* iOS keyboard-claim ghost input — see orbit-search.js wireOffcanvas() docs.
   Must be in layout + focusable (not display:none, not visibility:hidden — iOS
   refuses focus on those), but visually invisible and not user-tappable. The
   trigger-click handler focuses this synchronously so iOS pops the soft-
   keyboard inside the gesture; we transfer focus to the real input on
   shown.bs.offcanvas. */
.helios-search-ghost-input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
    border: 0;
    padding: 0;
    margin: 0;
    background: transparent;
    font-size: 16px; /* prevent iOS pinch-zoom-on-focus */
}

/* "Toon alle resultaten →" row — distinct from regular result rows.
   Rendered by orbit-search.js when a group has more matches than fit (server
   sets g.more=true + g.more_url from the provider's list_url config). */
.helios-search-more {
    color: var(--bs-primary);
    font-weight: 500;
    text-align: center;
    font-size: .875rem;
}

/* Loading-state — thin animated 2px bar at the top of the result panel.
   Toggled by orbit-search.js via .is-loading on the INNER [data-orbit-search-panel]
   div, NIET op de offcanvas-root. Class-change op een position:fixed parent met
   geanimeerde pseudo triggert op iOS Safari een full-paint van die parent —
   gevolg was dat de hele offcanvas leek te flikkeren/verspringen bij elke
   AJAX-fetch ook al raken we maar één inner div met replaceChildren. Door de
   class op de smaller inner element te zetten blijft de repaint scoped tot
   dat element en blijft de offcanvas rotsvast staan. */
[data-orbit-search-panel].is-loading {
    position: relative;
}
[data-orbit-search-panel].is-loading::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 2px;
    background: linear-gradient(90deg, transparent 0%, var(--bs-primary) 50%, transparent 100%);
    background-size: 200% 100%;
    animation: orbit-search-loading 1.2s ease-in-out infinite;
    pointer-events: none;
    z-index: 2;
}
@keyframes orbit-search-loading {
    0%   { background-position: 100% 0; }
    100% { background-position: -100% 0; }
}

/* Hint-strip — keyboard-shortcut legend at the bottom of the search panel.
   Rendered by orbit-search-pill.php + orbit-toolbar.php (mobile offcanvas).
   Subtle muted background so the eye lands on the results, not the hint. */
.helios-search-hint {
    font-size: .75rem;
    background: var(--bs-tertiary-bg);
    color: var(--bs-secondary-color);
    border-bottom-left-radius: var(--orbit-radius, 10px);
    border-bottom-right-radius: var(--orbit-radius, 10px);
}
.helios-search-hint kbd {
    font-size: .7rem;
    padding: .05rem .25rem;
    border-radius: 3px;
    background: var(--bs-body-bg);
    border: 1px solid var(--bs-border-color);
}

/* Floating clear-X button — wipes the search query.
   Lives inside `.helios-search-input-wrap` (or the mobile offcanvas-equivalent
   wrapper) which is `position:relative`. Toggled visible by orbit-search.js
   based on input value (hidden attribute).

   Visual = native-mobile clear pattern: filled gray circle with a clear ✕,
   centered vertically at the right edge inside the input. Mimics iOS Safari's
   built-in `<input type="search">` clear button + slightly larger for finger
   tap-targets. The mobile-offcanvas variant gets even bigger via modifier. */
.helios-search-clear {
    position: absolute;
    top: 50%;
    right: .375rem;                /* match input vertical-padding for equal top/bottom/right gap */
    transform: translateY(-50%);
    width: 22px;                   /* input ≈38px − 2*6px vertical-pad − 2px border ≈ 22px */
    height: 22px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--bs-secondary-color);
    border: none;
    border-radius: 50%;
    color: var(--bs-body-bg);
    cursor: pointer;
    padding: 0;
    opacity: 0.55;
    transition: opacity .15s ease, background-color .15s ease, transform .12s ease;
    z-index: 2;
}
.helios-search-clear:hover,
.helios-search-clear:focus-visible {
    opacity: 1;
    background: var(--bs-body-color);
    outline: none;
}
.helios-search-clear:active {
    transform: translateY(-50%) scale(0.9);
}
.helios-search-clear[hidden] { display: none; }
/* CSS-spec: presentation attributes on SVG (incl. stroke-width) lose to
   matching CSS rules. Bump from Lucide-default 2 → 2.5 so the X reads
   clearly at the small 12-14px icon size. */
.helios-search-clear svg,
.helios-search-clear [data-lucide="x"] {
    width: 12px;
    height: 12px;
    stroke-width: 2.5;
}

/* Mobile offcanvas variant — slightly bigger touch-target while keeping
   the same visual balance (gap on all three sides ≈ input vertical-pad).
   `right` inherits .375rem from base `.helios-search-clear` rule — the
   button now sits inside a tight `.helios-search-input-wrap` whose bounds
   equal the input's bounds, so .375rem = 6px gap from input's right edge
   (matches the 6px top/bottom gap inside a 38px input around a 26px ✕). */
.helios-search-clear--mobile {
    width: 26px;
    height: 26px;
    opacity: 0.6;
}
.helios-search-clear--mobile svg,
.helios-search-clear--mobile [data-lucide="x"] {
    width: 14px;
    height: 14px;
}

/* Reserve room on the right of the input so the clear-X doesn't overlap
   typed text. Applied to inputs that have a sibling clear-button. The mobile
   offcanvas variant of the input gets extra padding to match the larger ✕. */
.helios-search-input-padded { padding-right: 2.25rem; }
.helios-search-offcanvas .helios-search-input-padded { padding-right: 2.75rem; }

/* Partial-results banner — shown when dispatcher's 1000ms budget cut off
   slow providers. Rendered by orbit-search.js renderResults() when
   data.partial === true. Warning-subtle so it's visible but non-alarming. */
.helios-search-partial {
    background: var(--bs-warning-bg-subtle, #fff3cd);
    color: var(--bs-warning-text-emphasis, #664d03);
    border-bottom: 1px solid var(--bs-border-color);
    padding: .35rem .75rem;
    font-size: .75rem;
    display: flex;
    align-items: center;
    gap: .35rem;
}
.helios-search-partial i[data-lucide] {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
}

/* Filter-chips — rendered above the result-groups by orbit-search.js when
   data.groups.length >= 2. "Alles" chip resets the filter; per-group chips
   show count. Active chip = primary fill. Pill shape via border-radius 999px.
   `flex-wrap: nowrap` is intentional: between consecutive AJAX-renders the
   chip-count varies (different group-set per query) and on narrow mobile a
   wrapped bar swaps between 1/2/3 rows → ~30px vertical jump in the panel
   below. Single-row + horizontal scroll keeps the bar's height deterministic;
   extra chips scroll touch-natively. */
.helios-search-chips {
    display: flex;
    gap: .35rem;
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none; /* Firefox — hide horizontal scrollbar */
}
.helios-search-chips::-webkit-scrollbar { display: none; }
.helios-search-chip {
    display: inline-flex;
    align-items: center;
    padding: .15rem .6rem;
    font-size: .75rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 999px;
    background: transparent;
    color: var(--bs-secondary-color);
    cursor: pointer;
    white-space: nowrap;
    transition: background-color .12s ease, color .12s ease, border-color .12s ease;
}
.helios-search-chip:hover {
    background: var(--bs-tertiary-bg);
}
.helios-search-chip.active {
    background: var(--bs-primary);
    color: #fff;
    border-color: var(--bs-primary);
}

/* Empty-state — centered icon + message for the three states rendered by
   orbit-search.js: "no input yet" (search), "min-chars warning" (keyboard),
   "no results" (search-x). Replaces the previous text-only treatment. */
.helios-search-empty {
    padding: 2rem 1rem;
}
.helios-search-empty-icon {
    width: 32px;
    height: 32px;
    color: var(--bs-secondary-color);
    opacity: 0.5;
    display: inline-block;
}
.helios-search-empty-hint {
    font-size: .8rem;
    opacity: 0.75;
}

/* ============================================================================
   MODAL MOBILE-OPTIMALISATIES (canon §10)
   Globale tweaks die élke modal automatisch verbeteren op <576px.
   Targets vier terugkerende krappe-ruimte-problemen:
     1. modal-title — kort woord-break wanneer h5 + icon + close-btn
        op smal scherm botsen.
     2. accordion-button binnen modal — `label + meta-badge + chevron`
        clusters wrappen onleesbaar; badge moet onder de label kunnen
        zakken zonder chevron uit lijn te trekken.
     3. card-header binnen modal-body (terminal-blok, share-strip, …)
        — flex-row met label + action-button; action mag wrappen ipv
        de label te knellen.
     4. .orbit-copy-btn — dubbele icon+label-spans zijn label-zwaar;
        op mobiel alleen icon (aria-label houdt a11y intact).
   Géén per-modal-overrides nodig — alle bestaande modals erven dit. */
@media (max-width: 575.98px) {
    .modal-title {
        font-size: 15px;
        line-height: 1.3;
        overflow-wrap: anywhere;
    }

    .modal .accordion-button {
        flex-wrap: wrap;
        row-gap: .25rem;
    }
    /* `order: 3` zet badge na BS's ::after-chevron (default order 0) zodat
       de badge naar een eigen wrap-rij valt en de chevron op de top-rij
       blijft naast de label. `margin-left: auto` mirror't de chevron's
       right-alignment voor visuele consistentie. */
    .modal .accordion-button .badge {
        order: 3;
        margin-left: auto;
    }

    .modal .card-header {
        flex-wrap: wrap;
        row-gap: .35rem;
    }

    .orbit-copy-btn .orbit-copy-default:not(i):not(svg),
    .orbit-copy-btn .orbit-copy-success:not(i):not(svg) {
        display: none;
    }
    .orbit-copy-btn.is-copied .orbit-copy-success:not(i):not(svg) {
        display: none;
    }

    /* Per-modal opt-out: agentCommandInfoModal verbergt de "vereist: X"-badge
       in de accordion-knop op mobiel — titel + chevron blijven op één rij.
       Diezelfde info verschijnt binnen de accordion-body via een mobile-only
       chip (zie view.php), zodat klanten het bij expand wél zien. */
    #agentCommandInfoModal .accordion-button > .badge {
        display: none;
    }
}

/* ============================================================
   Backup Snapshot Card-Row — list-item within snapshots-tab
   accordion-pane (mirror van .admin-notification shape, simpler
   omdat snapshots geen unread/dismissed-state hebben).
   Whole row is een <a> die naar snapshot-detail navigeert.
   ============================================================ */

.backup-snapshot-card {
    position: relative;
    overflow: hidden;
    display: block;
    margin-bottom: .5rem;
    padding: .75rem 1rem .75rem 1.25rem;
    border: 1px solid var(--helios-border-subtle);
    border-radius: var(--orbit-radius, 10px);
    background: var(--helios-surface-raised);
    color: var(--helios-text);
    text-decoration: none;
    transition: background-color .15s ease, border-color .15s ease;
}
.backup-snapshot-card:hover,
.backup-snapshot-card:focus-visible {
    background: var(--helios-surface-sunken);
    color: var(--helios-text);
    text-decoration: none;
    border-color: var(--helios-border);
    outline: none;
}
.backup-snapshot-card::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 4px;
    background: var(--helios-border-subtle);
}
.backup-snapshot-card[data-snapshot-tone="success"]::before { background: var(--bs-success); }
.backup-snapshot-card[data-snapshot-tone="info"]::before    { background: var(--bs-info); }

.backup-snapshot-card .backup-snapshot-icon {
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    border-radius: var(--orbit-radius, 10px);
    background: var(--helios-surface-sunken);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--helios-text-muted);
}
.backup-snapshot-card:hover .backup-snapshot-icon {
    background: var(--helios-surface-raised);
}

/* ---------------------------------------------------------------
   Backup tables — sprint-2 polish utilities.
   - .backup-msg-col: max-width voor bericht/error-kolommen die
     vroeger inline style="max-width:360px" gebruikten.
   - .backup-pool-col: min-width voor de pool-progress-bar kolom
     in destinations-list (vroeger style="min-width:140px").
   - .backup-server-col: max-width voor server-naam kolom
     (vroeger style="max-width:180px" — eigenschap van panel-label).
   --------------------------------------------------------------- */
.backup-msg-col {
    max-width: 360px;
}
.backup-pool-col {
    min-width: 140px;
}
.backup-server-col {
    max-width: 220px;
}

/* ---------------------------------------------------------------
   Helios activity-row — extended tone-classes (sprint-3 polish).
   Used by backup-recent-feed (_pane-dashboard.php) and JS-rendered
   updates (backup-dashboard.js). Theme-aware via Bootstrap's
   --bs-*-rgb variables; dark-mode boosts alpha for visibility.
   --------------------------------------------------------------- */

/* Left-stripe: 4px color-band naast border-left van de card.
   Status-toon scaffold: tone-success/warning/danger/muted vervangen
   de default border-left. */
.helios-activity-row-stripe {
    border-left: 4px solid var(--bs-secondary, #6c757d);
}
.helios-activity-row-stripe.tone-success { border-left-color: var(--bs-success, #198754); }
.helios-activity-row-stripe.tone-warning { border-left-color: var(--bs-warning, #ffc107); }
.helios-activity-row-stripe.tone-danger  { border-left-color: var(--bs-danger,  #dc3545); }
.helios-activity-row-stripe.tone-muted   { border-left-color: var(--bs-secondary, #6c757d); }
.helios-activity-row-stripe.tone-info    { border-left-color: var(--bs-info, #0dcaf0); }

/* Dark-mode stripe: Bootstrap's default --bs-success/warning/danger blijven
   in Orbit dark-theme op hun light-mode hex (Orbit gebruikt [data-theme] niet
   [data-bs-theme], dus BS 5.3 dark-vars activeren niet). Resultaat = donker
   groen/rood op donkere kaart = onzichtbaar. Brighten met chip-ink tokens. */
[data-theme="dark"] .helios-activity-row-stripe.tone-success,
[data-bs-theme="dark"] .helios-activity-row-stripe.tone-success {
    border-left-color: var(--x-status-success-chip-ink, #b5d488);
}
[data-theme="dark"] .helios-activity-row-stripe.tone-warning,
[data-bs-theme="dark"] .helios-activity-row-stripe.tone-warning {
    border-left-color: var(--x-status-warning-chip-ink, #efcf6f);
}
[data-theme="dark"] .helios-activity-row-stripe.tone-danger,
[data-bs-theme="dark"] .helios-activity-row-stripe.tone-danger {
    border-left-color: var(--x-status-danger-chip-ink, #e88087);
}
[data-theme="dark"] .helios-activity-row-stripe.tone-muted,
[data-bs-theme="dark"] .helios-activity-row-stripe.tone-muted {
    border-left-color: rgba(var(--bs-secondary-rgb, 108, 117, 125), 0.6);
}
[data-theme="dark"] .helios-activity-row-stripe.tone-info,
[data-bs-theme="dark"] .helios-activity-row-stripe.tone-info {
    border-left-color: var(--x-status-info-chip-ink, #8ec5e8);
}

/* Icon-pill: 36×36 rounded square met soft-bg in status-kleur.
   Geeft visuele anker voor scan. Tone-classes mirror van stripe. */
.helios-activity-icon-pill {
    width: 36px;
    height: 36px;
    border-radius: 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    background: rgba(var(--bs-secondary-rgb, 108, 117, 125), 0.10);
}
.helios-activity-icon-pill.tone-success { background: rgba(var(--bs-success-rgb, 25, 135, 84),   0.12); }
.helios-activity-icon-pill.tone-warning { background: rgba(var(--bs-warning-rgb, 255, 193, 7),    0.16); }
.helios-activity-icon-pill.tone-danger  { background: rgba(var(--bs-danger-rgb,  220, 53, 69),    0.12); }
.helios-activity-icon-pill.tone-muted   { background: rgba(var(--bs-secondary-rgb, 108, 117, 125), 0.10); }
.helios-activity-icon-pill.tone-info    { background: rgba(var(--bs-info-rgb, 13, 202, 240),       0.12); }

/* Button-variant van de pill (retry-actie op failed/stuck rows).
   Behoudt zelfde 36×36 tone-bg, maar wordt clickable met hover-feedback. */
button.helios-activity-icon-pill {
    border: 0;
    padding: 0;
    cursor: pointer;
    transition: transform .12s ease, background-color .12s ease, box-shadow .12s ease;
}
button.helios-activity-icon-pill:hover {
    transform: scale(1.06);
    box-shadow: 0 2px 6px rgba(var(--bs-danger-rgb, 220, 53, 69), 0.25);
}
button.helios-activity-icon-pill.tone-danger:hover  { background: rgba(var(--bs-danger-rgb,  220, 53, 69), 0.22); }
button.helios-activity-icon-pill.tone-warning:hover { background: rgba(var(--bs-warning-rgb, 255, 193, 7),  0.28); }
button.helios-activity-icon-pill:active  { transform: scale(0.96); }
button.helios-activity-icon-pill:disabled { cursor: not-allowed; opacity: 0.55; transform: none; box-shadow: none; }

/* Dark-mode: boost alpha zodat tint visible blijft. Orbit zet
   [data-theme="dark"] op <html>; Bootstrap 5.3 [data-bs-theme="dark"]. */
[data-theme="dark"] .helios-activity-icon-pill.tone-success,
[data-bs-theme="dark"] .helios-activity-icon-pill.tone-success { background: rgba(var(--bs-success-rgb), 0.22); }
[data-theme="dark"] .helios-activity-icon-pill.tone-warning,
[data-bs-theme="dark"] .helios-activity-icon-pill.tone-warning { background: rgba(var(--bs-warning-rgb), 0.24); }
[data-theme="dark"] .helios-activity-icon-pill.tone-danger,
[data-bs-theme="dark"] .helios-activity-icon-pill.tone-danger  { background: rgba(var(--bs-danger-rgb),  0.22); }
[data-theme="dark"] .helios-activity-icon-pill.tone-muted,
[data-bs-theme="dark"] .helios-activity-icon-pill.tone-muted   { background: rgba(var(--bs-secondary-rgb), 0.18); }
[data-theme="dark"] .helios-activity-icon-pill.tone-info,
[data-bs-theme="dark"] .helios-activity-icon-pill.tone-info    { background: rgba(var(--bs-info-rgb), 0.22); }

/* Multifunctioneel output/error details-box. Tone-class bepaalt kleur:
   - default (geen tone) = danger (fout-runs)
   - .tone-warning = waarschuwingen (partial-success)
   - .tone-muted = output (success/cancelled met restic-output, geen error)
   Chevron via summary::before roteert bij [open]. Dark-mode boost via
   chip-ink tokens (BS defaults zijn dim op Orbit dark-theme). */
.helios-activity-details-box {
    position: relative;
    margin-top: 0.5rem;
    padding: 0.5rem 0.75rem;
    /* Border-left rgba (alpha-tinted) ipv solid — subtieler en past zich aan
       de tone-bg aan. Was 3px solid #dc3545 (knal-rood), nu 2px tone-rgb 0.55. */
    border-left: 2px solid rgba(var(--bs-danger-rgb, 220, 53, 69), 0.55);
    background: rgba(var(--bs-danger-rgb, 220, 53, 69), 0.08);
    border-radius: 0 6px 6px 0;
    transition: background-color .12s ease-in-out;
}
.helios-activity-details-box:hover {
    background: rgba(var(--bs-danger-rgb, 220, 53, 69), 0.12);
}
.helios-activity-details-box.tone-warning {
    border-left-color: rgba(var(--bs-warning-rgb, 255, 193, 7), 0.60);
    background: rgba(var(--bs-warning-rgb, 255, 193, 7), 0.10);
}
.helios-activity-details-box.tone-warning:hover {
    background: rgba(var(--bs-warning-rgb, 255, 193, 7), 0.16);
}
.helios-activity-details-box.tone-muted {
    border-left-color: rgba(var(--bs-secondary-rgb, 108, 117, 125), 0.45);
    background: rgba(var(--bs-secondary-rgb, 108, 117, 125), 0.06);
}
.helios-activity-details-box.tone-muted:hover {
    background: rgba(var(--bs-secondary-rgb, 108, 117, 125), 0.10);
}
/* Dark mode — borders iets feller (dark-bg vraagt meer alpha voor zichtbaarheid) */
[data-theme="dark"] .helios-activity-details-box,
[data-bs-theme="dark"] .helios-activity-details-box {
    border-left-color: rgba(var(--bs-danger-rgb), 0.65);
    background: var(--x-status-danger-chip-bg, rgba(220, 53, 69, 0.18));
}
[data-theme="dark"] .helios-activity-details-box:hover,
[data-bs-theme="dark"] .helios-activity-details-box:hover {
    background: rgba(var(--bs-danger-rgb, 220, 53, 69), 0.28);
}
[data-theme="dark"] .helios-activity-details-box.tone-warning,
[data-bs-theme="dark"] .helios-activity-details-box.tone-warning {
    border-left-color: rgba(var(--bs-warning-rgb), 0.70);
    background: var(--x-status-warning-chip-bg, rgba(232, 185, 60, 0.18));
}
[data-theme="dark"] .helios-activity-details-box.tone-warning:hover,
[data-bs-theme="dark"] .helios-activity-details-box.tone-warning:hover {
    background: rgba(var(--bs-warning-rgb, 255, 193, 7), 0.26);
}
[data-theme="dark"] .helios-activity-details-box.tone-muted,
[data-bs-theme="dark"] .helios-activity-details-box.tone-muted {
    border-left-color: rgba(var(--bs-secondary-rgb), 0.55);
    background: rgba(var(--bs-secondary-rgb), 0.14);
}
[data-theme="dark"] .helios-activity-details-box.tone-muted:hover,
[data-bs-theme="dark"] .helios-activity-details-box.tone-muted:hover {
    background: rgba(var(--bs-secondary-rgb), 0.22);
}
/* Summary = volledige rij klikbaar (display:flex spant width:100%, was inline-flex
   wat alleen text-area klikbaar maakte). UX-verbetering. */
.helios-activity-details-box > summary {
    list-style: none;
    cursor: pointer;
    user-select: none;
    display: flex;
    align-items: center;
    gap: 0.35rem;
    color: var(--bs-danger-text-emphasis, #b02a37);
    margin: -0.5rem -0.75rem;
    padding: 0.5rem 0.75rem;
    border-radius: 0 6px 6px 0;
    transition: background-color .12s;
}
.helios-activity-details-box > summary:hover {
    background: rgba(var(--bs-body-color-rgb, 33, 37, 41), 0.04);
}
.helios-activity-details-box[open] > summary {
    margin-bottom: 0;
}
.helios-activity-details-box.tone-warning > summary {
    color: var(--bs-warning-text-emphasis, #997404);
}
.helios-activity-details-box.tone-muted > summary {
    color: var(--bs-secondary, #6c757d);
}
[data-theme="dark"] .helios-activity-details-box > summary,
[data-bs-theme="dark"] .helios-activity-details-box > summary {
    color: var(--x-status-danger-chip-ink, #e88087);
}
[data-theme="dark"] .helios-activity-details-box.tone-warning > summary,
[data-bs-theme="dark"] .helios-activity-details-box.tone-warning > summary {
    color: var(--x-status-warning-chip-ink, #efcf6f);
}
[data-theme="dark"] .helios-activity-details-box.tone-muted > summary,
[data-bs-theme="dark"] .helios-activity-details-box.tone-muted > summary {
    color: rgba(var(--bs-secondary-rgb), 0.95);
}
.helios-activity-details-box > summary::-webkit-details-marker { display: none; }
.helios-activity-details-box > summary::before {
    content: "";
    display: inline-block;
    width: 0;
    height: 0;
    border-top: 4px solid transparent;
    border-bottom: 4px solid transparent;
    border-left: 6px solid currentColor;
    margin-right: 2px;
    transition: transform .15s ease-in-out;
    flex-shrink: 0;
}
.helios-activity-details-box[open] > summary::before {
    transform: rotate(90deg);
}
/* When open: pre-wrap volgt direct na summary; full-bleed-margin van summary
   blijft want hover-area moet ook open-state covered houden. mb via pre-wrap mt. */
.helios-activity-details-box[open] > .helios-activity-pre-wrap {
    margin-top: 0.5rem;
}
.helios-activity-details-box pre {
    margin: 0;
    /* py-2 (0.625rem) zodat single-line content niet tegen de copy-btn edge zit;
       padding-right groot genoeg om de absoluut-gepositioneerde btn te clearen */
    padding: 0.625rem 2.5rem 0.625rem 0.75rem;
    background: rgba(0, 0, 0, 0.03);
    border-radius: 4px;
    max-height: 220px;
    overflow-y: auto;
    min-height: calc(20px + 1rem);  /* btn-height + py-2 */
}
[data-theme="dark"] .helios-activity-details-box pre,
[data-bs-theme="dark"] .helios-activity-details-box pre {
    background: rgba(0, 0, 0, 0.25);
}
/* Inline copy-button in details <pre>: floating icon-only knop top-right
   van het pre-blok. Gebruikt canonical orbit-copy.js: dual icon-spans
   (copy → check) swappen via .is-copied class-state.
   Tone-match: copy-icon erft kleur van de box-tone (danger/warning/muted)
   zodat de knop visueel rust binnen het blok. Check blijft success-groen. */
.helios-activity-pre-wrap {
    position: relative;
}
.helios-activity-pre-wrap .orbit-copy-btn {
    position: absolute;
    top: 0.5rem;
    right: 0.5rem;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    padding: 0;
    background: transparent;
    /* Border alpha-tinted in plaats van currentColor — subtieler en
       past zich aan aan de box-tone via dezelfde rgb-var. */
    border: 1px solid rgba(var(--bs-danger-rgb, 220, 53, 69), 0.35);
    border-radius: 4px;
    cursor: pointer;
    opacity: 0.8;
    transition: opacity .12s, background-color .12s, border-color .12s;
    /* Default color (danger box) — tone-warning/tone-muted overrides hieronder. */
    color: var(--bs-danger-text-emphasis, #b02a37);
}
.helios-activity-details-box.tone-warning .orbit-copy-btn {
    color: var(--bs-warning-text-emphasis, #997404);
    border-color: rgba(var(--bs-warning-rgb, 255, 193, 7), 0.45);
}
.helios-activity-details-box.tone-muted .orbit-copy-btn {
    color: var(--bs-secondary, #6c757d);
    border-color: rgba(var(--bs-secondary-rgb, 108, 117, 125), 0.32);
}
[data-theme="dark"] .helios-activity-pre-wrap .orbit-copy-btn,
[data-bs-theme="dark"] .helios-activity-pre-wrap .orbit-copy-btn {
    color: var(--x-status-danger-chip-ink, #e88087);
    border-color: rgba(var(--bs-danger-rgb), 0.45);
}
[data-theme="dark"] .helios-activity-details-box.tone-warning .orbit-copy-btn,
[data-bs-theme="dark"] .helios-activity-details-box.tone-warning .orbit-copy-btn {
    color: var(--x-status-warning-chip-ink, #efcf6f);
    border-color: rgba(var(--bs-warning-rgb), 0.50);
}
[data-theme="dark"] .helios-activity-details-box.tone-muted .orbit-copy-btn,
[data-bs-theme="dark"] .helios-activity-details-box.tone-muted .orbit-copy-btn {
    color: rgba(var(--bs-secondary-rgb), 0.95);
    border-color: rgba(var(--bs-secondary-rgb), 0.40);
}
.helios-activity-pre-wrap .orbit-copy-btn:hover {
    opacity: 1;
    background: rgba(var(--bs-body-color-rgb, 33, 37, 41), 0.06);
}
.helios-activity-pre-wrap .orbit-copy-btn.is-copied {
    opacity: 1;
    color: var(--bs-success-text-emphasis, #0a3622);
    background: rgba(var(--bs-success-rgb), 0.12);
}
[data-theme="dark"] .helios-activity-pre-wrap .orbit-copy-btn.is-copied,
[data-bs-theme="dark"] .helios-activity-pre-wrap .orbit-copy-btn.is-copied {
    color: var(--x-status-success-chip-ink, #b5d488);
    background: rgba(var(--bs-success-rgb), 0.20);
}

/* Right-aligned trailing-group (badge + tijd): horizontaal naast elkaar.
   1-regel hoogte zodat primary-row niet stretcht en de meta-row eronder
   direct aansluit (geen onnodige witruimte tussen server-naam en bestanden). */
.helios-activity-trailing {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 0.5rem;
    flex-shrink: 0;
}
/* Mobile (<sm): stack title-group + trailing onder elkaar; trailing blijft
   horizontaal binnen (badge + tijd compact in 1 regel). */
@media (max-width: 575.98px) {
    .helios-activity-primary {
        flex-direction: column;
        align-items: flex-start;
    }
}

/* ---------------------------------------------------------------
   helios-list-row — GLOBAL compact list/feed row.

   Een horizontale "lead-icon + main(titel+meta) + status + tijd" rij,
   bedoeld binnen een .helios-activity-row card-shell (left-stripe tone) met
   een .helios-activity-icon-pill als lead. Herbruikbaar over modules heen —
   eerste afnemer is de backup-module (Ingepland / Recent / Logboek / history).

   Canonieke markup (zie design-system.md §52 + helios-components.md):
     .helios-activity-row.helios-activity-row-stripe.tone-*      (card-shell)
       └ .card-body
           └ .helios-list-row
               ├ .helios-activity-icon-pill.tone-*    (lead; mag een <button>
               │                                        zijn voor retry/info)
               ├ .helios-list-row-main                (titel + meta, flex:1)
               │   ├ <a|span>.text-truncate.d-block    (titel/hostnaam)
               │   └ .helios-list-row-meta             (inline meta-chips; tag
               │        een laag-prioriteit chip met .helios-list-row-meta-dest
               │        om 'm op telefoons te verbergen)
               ├ .helios-list-row-status               (badge; mobiel verborgen)
               └ .helios-list-row-when.text-end        (2 regels: rel + abs tijd)

   Desktop (≥md): 4-zone horizontale rij. Het component bezit z'n EIGEN
   `display` (krijgt NIET de .d-flex utility) — bewust: .d-flex is
   `display:flex !important` en zou de mobiele `display:grid`-override hieronder
   verslaan, waardoor de responsive-laag dood blijft (de bug die dit vervangt).

   Mobiel (<md): titel/hostnaam krijgt de volle breedte op rij 1, meta op een
   eigen regel, en de tijd wordt een footer-strip op rij 2. De tekst-status-
   badge wordt verborgen — status leest al af van de left-stripe tone + de
   gekleurde icon-pill (incl. de vorm van het icoon).
   --------------------------------------------------------------- */
.helios-list-row {
    display: flex;
    gap: 1rem;
    align-items: center;
}
.helios-list-row-main {
    flex: 1 1 auto;
    min-width: 0;
}
.helios-list-row-status,
.helios-list-row-when {
    flex: 0 0 140px;
}

@media (max-width: 767.98px) {
    .helios-list-row {
        display: grid;
        grid-template-columns: auto 1fr;
        grid-template-areas:
            "lead main"
            "lead foot";
        column-gap: 0.75rem;
        row-gap: 0.4rem;
        align-items: start;
    }
    .helios-list-row > .helios-activity-icon-pill {
        grid-area: lead;
        align-self: start;
    }
    .helios-list-row-main { grid-area: main; }
    /* status leest af van stripe + icon-pill op mobiel */
    .helios-list-row-status { display: none; }
    /* tijd-footer-strip: rel-tijd (bold) links, abs-tijd (muted) rechts */
    .helios-list-row-when {
        grid-area: foot;
        min-width: 0;
        width: 100%;
        display: flex;
        flex-direction: row;
        align-items: baseline;
        text-align: left !important; /* overschrijft de .text-end utility */
    }
    .helios-list-row-when > :first-child { font-weight: 600; }
    .helios-list-row-when > :last-child { margin-left: auto; }
}

/* Phone (<sm): compacter meta — kleinere gap + font; laag-prioriteit meta
   (bv. bestemming) verbergen om wrap-naar-2-regels te voorkomen. */
@media (max-width: 575.98px) {
    .helios-list-row-meta {
        gap: 0.5rem !important;
        font-size: 0.72rem;
    }
    .helios-list-row-meta .helios-list-row-meta-dest {
        display: none !important;
    }
    .helios-list-row-when {
        font-size: 0.72rem;
    }
}

/* ---------------------------------------------------------------
   Backup unified job-card — stripe-overlay differentiation.

   Eén partial (private/tpl/backup/job-card.php) rendert backup/restore/
   download-cards visueel identiek. Type-differentiatie via een subtle
   diagonal-stripe overlay op de card-surface:
     - backup    → geen overlay (default white card)
     - restore   → .backup-card-restore-stripe   (neutraal grijs)
     - download  → .backup-card-download-stripe  (orbit-primary blauw)

   Dark-mode varianten in public_html/assets/css/dark.css.
   --------------------------------------------------------------- */
.backup-card-restore-stripe {
    background-image: repeating-linear-gradient(
        135deg,
        transparent 0,
        transparent 8px,
        rgba(0, 0, 0, 0.025) 8px,
        rgba(0, 0, 0, 0.025) 12px
    );
}
.backup-card-download-stripe {
    background-image: repeating-linear-gradient(
        135deg,
        transparent 0,
        transparent 8px,
        rgba(47, 111, 179, 0.07) 8px,
        rgba(47, 111, 179, 0.07) 12px
    );
}

/* ---------------------------------------------------------------
   Status-filter chip-group (.helios-filter-chips). Compact-variant
   versmalt op xs naar icon-only zodat 4-5 chips passen op mobiel.
   Gebruikt op backup dashboard recent + server-view historie.
   --------------------------------------------------------------- */
.helios-filter-chips .btn {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
}
.helios-filter-chips .btn .chip-label {
    white-space: nowrap;
}
/* Per-status telling in de chip (geslaagd/onvolledig/mislukt/geannuleerd).
   Neutraal-getoonde pill — de gekleurde status-icoon draagt al de tone
   (badge-canon: neutraal tenzij actie-vereisend). Blijft zichtbaar op de
   compact-variant (mobile) naast het icon. */
.helios-filter-chips .btn .chip-count {
    font-size: 0.7rem;
    font-weight: 600;
    line-height: 1;
    padding: 0.1rem 0.35rem;
    border-radius: 999px;
    background-color: rgba(var(--bs-body-color-rgb, 33, 37, 41), 0.08);
    color: var(--bs-secondary-color, #6c757d);
    font-variant-numeric: tabular-nums;
    min-width: 1.35em;
    text-align: center;
}
[data-theme="dark"] .helios-filter-chips .btn .chip-count,
[data-bs-theme="dark"] .helios-filter-chips .btn .chip-count {
    background-color: rgba(255, 255, 255, 0.12);
    color: rgba(255, 255, 255, 0.65);
}
.helios-filter-chips .btn.active {
    background-color: rgba(var(--bs-body-color-rgb, 33, 37, 41), 0.08);
    border-color: rgba(var(--bs-body-color-rgb, 33, 37, 41), 0.25);
    font-weight: 600;
}
[data-theme="dark"] .helios-filter-chips .btn.active,
[data-bs-theme="dark"] .helios-filter-chips .btn.active {
    background-color: rgba(255, 255, 255, 0.10);
    border-color: rgba(255, 255, 255, 0.28);
}
/* Compact-variant: op xs (<sm) wordt het btn-group full-width met equal-
   width chips (flex 1 1 0). Labels van chips MET icon verdwijnen → icon-only.
   De "Alles"-chip (geen icon) houdt label want anders niet herkenbaar.
   Padding ruimer (py-2 px-3-equivalent) zodat tap-target ≥ 44px is. */
@media (max-width: 575.98px) {
    .helios-filter-chips-compact {
        display: flex;
        width: 100%;
    }
    .helios-filter-chips-compact .btn {
        flex: 1 1 0;
        justify-content: center;
        padding: 0.5rem 0.5rem;
        min-height: 40px;
    }
    .helios-filter-chips-compact .btn:has(> i[data-lucide]) .chip-label {
        display: none;
    }
    .helios-filter-chips-compact .btn > i[data-lucide] {
        width: 16px !important;
        height: 16px !important;
        vertical-align: middle !important;
    }
}

/* ---------------------------------------------------------------
   Backup card sparkline (sprint-6).
   7-daagse mini-bars onderaan server-card/destination-card.
   Server-variant: status-tinted (success/partial/failed/none).
   Destination-variant: success-tinted bars met variabele hoogte
   gestuurd door --bar-fill (CSS var op de span).
   --------------------------------------------------------------- */
.backup-sparkline {
    height: 22px;
}
.backup-sparkline-bar {
    flex: 1 1 0;
    height: 22px;
    border-radius: 3px;
    background: rgba(var(--bs-secondary-rgb, 108, 117, 125), .15);
    transition: opacity .15s ease-in-out;
    cursor: default;
}
.backup-sparkline-bar:hover {
    opacity: .8;
}
.backup-sparkline-bar.tone-success {
    background: rgba(var(--bs-success-rgb), .65);
}
.backup-sparkline-bar.tone-partial {
    background: rgba(var(--bs-warning-rgb), .65);
}
.backup-sparkline-bar.tone-failed {
    background: rgba(var(--bs-danger-rgb), .65);
}
.backup-sparkline-bar.tone-none {
    background: rgba(var(--bs-secondary-rgb, 108, 117, 125), .15);
}
/* Volume-variant (destinations): height-scaled bars in een 22px slot. */
.backup-sparkline-volume {
    height: 22px;
}
.backup-sparkline-volume .backup-sparkline-bar {
    align-self: flex-end;
    height: var(--bar-fill, 8%);
    min-height: 2px;
}
[data-theme="dark"] .backup-sparkline-bar {
    background: rgba(var(--bs-secondary-rgb, 108, 117, 125), .25);
}
[data-theme="dark"] .backup-sparkline-bar.tone-success {
    background: rgba(var(--bs-success-rgb), .55);
}
[data-theme="dark"] .backup-sparkline-bar.tone-partial {
    background: rgba(var(--bs-warning-rgb), .55);
}
[data-theme="dark"] .backup-sparkline-bar.tone-failed {
    background: rgba(var(--bs-danger-rgb), .55);
}

/* ---------------------------------------------------------------
   Backup job-config card (sprint-4): definition-list styling.
   Compactere dt-spacing + max-height op paden-lists zodat lange
   path-arrays de card niet doen exploderen.
   --------------------------------------------------------------- */
.backup-job-dl > dt {
    font-weight: normal;
    padding-top: 0.125rem;
}
.backup-job-paths summary {
    cursor: pointer;
    user-select: none;
    color: var(--bs-body-color);
}
.backup-job-paths summary::-webkit-details-marker {
    display: none;
}
.backup-job-paths summary::before {
    content: "▸";
    display: inline-block;
    width: 0.85rem;
    color: var(--bs-secondary, #6c757d);
    transition: transform .15s ease-in-out;
}
.backup-job-paths[open] > summary::before {
    transform: rotate(90deg);
}
.backup-job-paths-list {
    max-height: 240px;
    overflow-y: auto;
    word-break: break-all;
}

/* ────────────────────────────────────────────────────────────────────
   Helios — Skeleton shimmer (canonical loading-placeholder).
   Reusable block for any "content is loading" state. `.helios-skeleton`
   is the shimmering surface; `.helios-skeleton-row` is a table-row variant
   (one shimmer-bar per <td>, sized via width:60-90%).

   Reduced-motion-safe: the shimmer animation is disabled under
   prefers-reduced-motion, falling back to a static subtle tint so the
   placeholder is still distinguishable from real content.

   Reference: tpl/backup/filemanager.php (file-manager loading state).
   ──────────────────────────────────────────────────────────────────── */
.helios-skeleton {
    position: relative;
    overflow: hidden;
    border-radius: var(--orbit-radius, 10px);
    background-color: var(--helios-border-subtle, #e9ecef);
}
.helios-skeleton::after {
    content: "";
    position: absolute;
    inset: 0;
    transform: translateX(-100%);
    background-image: linear-gradient(
        90deg,
        rgba(255, 255, 255, 0) 0,
        rgba(255, 255, 255, 0.55) 50%,
        rgba(255, 255, 255, 0) 100%
    );
    animation: helios-skeleton-shimmer 1.4s ease-in-out infinite;
}
[data-theme="dark"] .helios-skeleton {
    background-color: rgba(255, 255, 255, 0.08);
}
[data-theme="dark"] .helios-skeleton::after {
    background-image: linear-gradient(
        90deg,
        rgba(255, 255, 255, 0) 0,
        rgba(255, 255, 255, 0.10) 50%,
        rgba(255, 255, 255, 0) 100%
    );
}

/* Table-row variant: each cell holds a shimmer-bar of fixed height. */
.helios-skeleton-row > td {
    padding-top: .55rem;
    padding-bottom: .55rem;
}
.helios-skeleton-row .helios-skeleton-bar {
    display: block;
    height: 14px;
    width: 80%;
}
.helios-skeleton-row .helios-skeleton-bar--sm { width: 40%; }
.helios-skeleton-row .helios-skeleton-bar--full { width: 100%; }

/* Standalone spin utility — applies the helios-spin keyframes directly to the
   element (works on a lucide-rendered <svg>, unlike `.helios-spinning [data-lucide]`
   which only matches the pre-render <i data-lucide>). Used by the file-manager
   "Map laden…" header hint. */
.helios-spin { animation: helios-spin .8s linear infinite; }

@keyframes helios-skeleton-shimmer {
    100% { transform: translateX(100%); }
}
@media (prefers-reduced-motion: reduce) {
    .helios-skeleton::after {
        animation: none;
        opacity: .35;
        transform: none;
    }
}

/* Restore-kind keuze-cards (backup restore-modal §28a).
   btn-check + label.btn-light gestyled als card; selected = primary-border +
   subtiele primary-bg (content blijft leesbaar, anders dan helios-day-chips die
   primary vult). Thema-aware via --bs-tokens. */
.restore-kind-card {
    transition: border-color .12s ease, box-shadow .12s ease, background-color .12s ease;
}
.btn-check:checked + .restore-kind-card {
    border-color: var(--bs-primary) !important;
    box-shadow: inset 0 0 0 1px var(--bs-primary);
    background-color: var(--bs-primary-bg-subtle);
}
.btn-check:focus-visible + .restore-kind-card {
    box-shadow: inset 0 0 0 1px var(--bs-primary), 0 0 0 0.2rem rgba(var(--bs-primary-rgb), 0.18);
}
