/* /Components/Layout/MainLayout.razor.rz.scp.css */
.page[b-ln6b6nx6u0] {
    position: relative;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

/* Two-row header: a fixed-height brand strip on top (sticks to viewport) and a
   flexible section-nav strip below it. */
.app-header[b-ln6b6nx6u0] {
    position: sticky;
    top: 0;
    z-index: 10;
    background: linear-gradient(180deg, #0f172a 0%, #1e293b 100%);
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.app-header-bar[b-ln6b6nx6u0] {
    display: flex;
    align-items: stretch;
    height: 3rem;
}

.app-brand[b-ln6b6nx6u0] {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0 1.25rem;
    color: #ffffff;
    font-size: 1.05rem;
    font-weight: 600;
    letter-spacing: -0.01em;
    text-decoration: none;
    border-right: 1px solid rgba(255, 255, 255, 0.06);
    flex-shrink: 0;
    white-space: nowrap;
}

.app-brand:hover[b-ln6b6nx6u0] {
    color: #ffffff;
    text-decoration: none;
}

/* The header is dark slate in every theme, so the accent here is its chrome
   shade (app.css --color-chrome-accent-ink; the raw #2563eb read 2.8:1). The
   section rail's icons share it. */
.app-brand-icon[b-ln6b6nx6u0] {
    font-size: 1.25rem;
    color: var(--color-chrome-accent-ink);
}

.app-brand-logo[b-ln6b6nx6u0] {
    height: 1.75rem;
    width: auto;
    max-width: 9rem;
    object-fit: contain;
    display: block;
}

.app-header-actions[b-ln6b6nx6u0] {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0 1rem;
    margin-left: auto;
    border-left: 1px solid rgba(255, 255, 255, 0.06);
    flex-shrink: 0;
}

.app-header-actions[b-ln6b6nx6u0]  a,
.app-header-actions[b-ln6b6nx6u0]  .btn-link {
    color: rgba(203, 213, 225, 0.85);
    text-decoration: none;
    font-size: 0.875rem;
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.375rem 0.625rem;
    border-radius: var(--radius-sm);
    transition: color 0.15s ease, background-color 0.15s ease;
}

.app-header-actions[b-ln6b6nx6u0]  a:hover,
.app-header-actions[b-ln6b6nx6u0]  .btn-link:hover {
    color: #ffffff;
    background-color: rgba(255, 255, 255, 0.08);
    text-decoration: none;
}

.app-header-actions[b-ln6b6nx6u0]  .text-muted {
    color: rgba(203, 213, 225, 0.85) !important;
}

/* Body: the section icon rail (TopSectionNav) sits to the left of <main>; the
   horizontal section menu (NavMenu) + content stack vertically inside <main>. */
.app-body[b-ln6b6nx6u0] {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

main[b-ln6b6nx6u0] {
    flex: 1;
    display: flex;
    flex-direction: column;
    background-color: var(--color-bg);
    min-width: 0;
}

@media (max-width: 640.98px) {
    /* The 48px slot on the leading edge is the fixed nav hamburger that
       TopSectionNav pins into this strip at phone widths — reserve it so the
       brand isn't sitting underneath the burger. */
    .app-brand[b-ln6b6nx6u0] {
        padding-inline: 3rem 0.75rem;
    }

    .app-header-actions[b-ln6b6nx6u0] {
        padding: 0 0.5rem;
        gap: 0.25rem;
    }

    /* 44x44 touch floor for the header controls — at phone widths their text
       hides and only the icons remain. Scoped to the toggles and top links so
       the switchers' popover MENU items keep their own sizing. */
    .app-header-actions[b-ln6b6nx6u0]  .top-row-link,
    .app-header-actions[b-ln6b6nx6u0]  .theme-switcher-toggle,
    .app-header-actions[b-ln6b6nx6u0]  .lang-switcher-toggle {
        min-width: 44px;
        min-height: 44px;
        justify-content: center;
    }

    /* The actions side is floored (up to 5 x 44px) and flex-shrink: 0, so the
       BRAND is the side that must give way: a tenant wordmark logo near the
       9rem cap plus the floored actions exceeds 390px, and with nothing
       shrinkable the whole document pans horizontally. Let the brand compress
       and clip instead — the logo scales down (height stays 1.75rem), and in
       the 576-640px band where the text brand shows it clips rather than
       widening the page. */
    .app-brand[b-ln6b6nx6u0] {
        flex-shrink: 1;
        min-width: 0;
        overflow: hidden;
    }

    .app-brand-logo[b-ln6b6nx6u0] {
        max-width: 100%;
    }

    /* Reclaim 16px of horizontal space per side from Bootstrap's px-4. */
    article.content[b-ln6b6nx6u0] {
        padding-left: 1rem !important;
        padding-right: 1rem !important;
    }
}

@media (min-width: 641px) {
    .app-body[b-ln6b6nx6u0] {
        flex-direction: row;
    }

    article.content[b-ln6b6nx6u0] {
        padding-top: 1.5rem !important;
        padding-left: 2rem !important;
        padding-right: 1.5rem !important;
    }
}

/* #blazor-error-ui now lives in wwwroot/app.css — it has to be GLOBAL, because
   PortalLayout and VendorLayout render the same div and scoped CSS only ever
   matched MainLayout's copy of it. */
/* /Components/Layout/NavMenu.razor.rz.scp.css */
/* layout-50 — single horizontal section menu bar (replaces the vertical
   sub-sidebar). One collapsible row of the active module's pages; the admin/
   config items live in the left rail under the module, not here.
   Theme-aware via the Pack-1 design tokens. */

.section-bar[b-egyi0gpqew] {
    display: flex;
    align-items: center;
    gap: .4rem;
    flex-wrap: wrap;
    padding: .4rem .85rem;
    background: var(--color-bg-card, #ffffff);
    border-bottom: 1px solid var(--color-border, #e5e7eb);
}

.section-toggle[b-egyi0gpqew] {
    flex-shrink: 0;
    width: 1.85rem;
    height: 1.85rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid transparent;
    border-radius: var(--radius-sm, .375rem);
    background: transparent;
    color: var(--color-text-muted, #6b7280);
    cursor: pointer;
    transition: background-color .15s ease, color .15s ease;
}

.section-toggle:hover[b-egyi0gpqew] {
    background: var(--color-bg-subtle, #f3f4f6);
    color: var(--color-text, #111827);
}

.section-label[b-egyi0gpqew] {
    flex-shrink: 0;
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .03em;
    text-transform: uppercase;
    color: var(--color-text-muted, #6b7280);
    margin-right: .25rem;
    white-space: nowrap;
}

.section-items[b-egyi0gpqew] {
    display: flex;
    align-items: center;
    gap: .15rem;
    flex-wrap: wrap;
    flex: 1 1 auto;
    min-width: 0;
}

/* The page tabs are rendered by <NavLink> (a child component), so their <a>
   does NOT carry this component's scoped-CSS attribute — target them through
   ::deep from the scoped .section-items wrapper, or they fall back to the global
   blue/underlined link style. */
.section-items[b-egyi0gpqew]  .section-tab {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .35rem .7rem;
    border-radius: var(--radius-sm, .375rem);
    border: 1px solid transparent;
    background: transparent;
    color: var(--color-text, #111827);
    text-decoration: none;
    font-size: .85rem;
    line-height: 1.2;
    white-space: nowrap;
    cursor: pointer;
    transition: background-color .15s ease, color .15s ease;
}

.section-items[b-egyi0gpqew]  .section-tab:hover {
    background: var(--color-bg-subtle, #f3f4f6);
    color: var(--color-text, #111827);
    text-decoration: none;
}

/* The active tab is a --color-primary FILL, so its label follows the semantic
   on-primary token rather than a hardcoded white (which was only 3.44:1 on the
   Operator magenta). */
.section-items[b-egyi0gpqew]  .section-tab.active {
    background: var(--color-primary, #2563eb);
    color: var(--color-on-primary, #ffffff);
}

.section-items[b-egyi0gpqew]  .section-tab.active .bi {
    color: var(--color-on-primary, #ffffff);
}

.section-items[b-egyi0gpqew]  .section-tab .bi {
    font-size: .95rem;
}

.section-collapsed-hint[b-egyi0gpqew] {
    font-size: .8rem;
    color: var(--color-text-muted, #6b7280);
}

@media (max-width: 640.98px) {
    .section-label[b-egyi0gpqew] {
        display: none;
    }

    .section-bar[b-egyi0gpqew] {
        padding: .4rem .6rem;
        /* One row: the toggle stays put and the tab lane scrolls beside it —
           the wrapped bar cost up to four rows of viewport on a phone. */
        flex-wrap: nowrap;
    }

    /* The page tabs become a single horizontally scrollable lane (the
       .app-scroll-x idiom): every destination stays reachable by swipe, the
       document never widens, and snap keeps a tab from being cut mid-label. */
    .section-items[b-egyi0gpqew] {
        flex-wrap: nowrap;
        min-width: 0;
        overflow-x: auto;
        overscroll-behavior-x: contain;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
        scroll-snap-type: x proximity;
        scroll-padding-inline: .5rem;
    }

    .section-items[b-egyi0gpqew]::-webkit-scrollbar {
        display: none;
    }

    .section-items[b-egyi0gpqew]  .section-tab {
        flex: 0 0 auto;
        max-width: 80vw;
        overflow: hidden;
        text-overflow: ellipsis;
        scroll-snap-align: start;
        /* Comfortable tap target on touch — the desktop chip is ~26px tall. */
        min-height: 40px;
    }

    .section-toggle[b-egyi0gpqew] {
        width: 2.5rem;
        height: 2.5rem;
        min-width: 2.5rem;
    }
}
/* /Components/Layout/PortalLayout.razor.rz.scp.css */
/* Self-service portal layout. Linear/Vercel-inspired: deep neutral canvas,
   tenant-brand accent, slow ambient gradients, sharp typography. Scoped so
   nothing leaks into the admin shell. */

.portal-shell[b-2hk7lilw2e] {
    /* Was #6366f1, which is 4.46:1 against white — 0.04 short of WCAG AA for
       the normal-size labels on .btn-primary. Darkened by 2/3/3 in RGB, an
       imperceptible hue shift, to clear it at 4.60:1 while keeping the
       white-on-indigo look the portal shipped with. Keep in step with
       PortalTheme.LightPalette["accent"]. */
    --portal-accent: #6164ee;
    /* Foreground for anything FILLED with --portal-accent. White is the
       shipped look for this built-in indigo; the dark preset and any tenant
       accent re-point it to a value validated at >= 4.5:1
       (PortalTheme.OnColorFor). */
    --portal-on-accent: #ffffff;
    /* The accent as TEXT — eyebrows, links, active pills, chips, icon glyphs.
       Not the accent itself: a brand tuned for one palette cannot read in the
       other (navy #1e3a8a is 1.64:1 on the dark surface), and even this indigo
       is 4.30:1 on the canvas and ~3.5:1 on its own pill wash. PortalLayout
       writes the tenant's under polarity-tagged names, like the neutrals
       below; this default is PortalTheme.DefaultAccentInk(Light) — the same
       indigo, deepened until it clears 4.5:1 on every backdrop it is set on.
       Fills, borders, focus rings and the aurora stay on --portal-accent. */
    --portal-accent-ink: var(--portal-accent-ink-light, #514fd7);
    /* Sticky offset the left rail pins itself to — it must clear the topbar.
       Derived from the bar's own box: 14px padding + the 44px user chip (its
       tallest child) + 14px padding + the 1px hairline. Enforced as the bar's
       min-height below, so the two can only drift if a NEW topbar control is
       taller than the chip. */
    --portal-topbar-h: 73px;

    /* ── B6: this block is the LIGHT PALETTE, and it is the only place the
       portal's light colours are stated. Two rules state a palette, and the
       tenant's overrides reach each one only through it:
         1. this rule                           (light)  reads --portal-*-light
         2. the dark rule below                 (dark)   reads --portal-*-dark
       PortalLayout renders the overrides inline under the name of the polarity
       PortalTheme.Resolve measured them against (PortalTheme.PolarityVar), so
       a Light tenant's colours exist only here. A reader whose own theme turns
       the portal dark gets the dark rule — and with it the whole built-in dark
       palette, because no -dark override was ever written for that tenant.

       Before this was so, the overrides went out as --portal-* themselves. An
       inline declaration outranks every author rule, so a Light tenant's
       surface beat the dark rule while the dark ink it does not override did
       not: #e6edf7 text on a #fffaf0 article, 1.13:1. Only the ACCENT is still
       declared inline under its own name, on purpose — it is the brand, and
       outranking both rules is what carries it into either polarity.

       NOTE for anyone tempted to write `--portal-canvas: var(--portal-canvas,
       #f6f7fb)` here: a custom property that references ITSELF is a cycle and
       resolves to the guaranteed-invalid value, taking the token out entirely.
       That is why the overrides have names of their own.

       --portal-ink / -ink-soft / --portal-surface stay anchored to the shared
       token scale (identical or same-role match) so the portal keeps tracking
       any future adjustment to those shared roles. The dark rule pins them
       to literals instead, because the shared scale is following the OPERATOR
       app's theme, not the tenant's portal choice. */
    --portal-canvas: var(--portal-canvas-light, #f6f7fb);
    --portal-surface: var(--portal-surface-light, var(--color-bg-card, #ffffff));
    --portal-surface-elevated: var(--portal-surface-elevated-light, rgba(255, 255, 255, 0.78));
    --portal-ink: var(--portal-ink-light, var(--color-text-dark, #0f172a));
    --portal-ink-soft: var(--portal-ink-soft-light, var(--color-text-muted, #475569));
    /* The faint tier is INFORMATION, not decoration — form hints, "1–6 of 6",
       item counts, list status ("InUse"), card eyebrows, the rail headings and
       its Profile / Notifications links — so it has to clear AA (owner's call,
       2026-10-15). Was #94a3b8, 2.4–2.6:1. On this palette there is no room
       for a lighter tier: the soft ink is itself only 4.45:1 on the canvas,
       so faint follows the same shared muted role — and with it the
       high-contrast arm and any future move of that role. The tiers still
       differ on the dark palette. Keep in step with
       PortalTheme.LightPalette["inkFaint"]. */
    --portal-ink-faint: var(--portal-ink-faint-light, var(--color-text-muted, #546478));
    --portal-line: var(--portal-line-light, rgba(15, 23, 42, 0.08));
    --portal-shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.04), 0 1px 3px rgba(15, 23, 42, 0.05);
    --portal-shadow-md: 0 8px 24px -8px rgba(15, 23, 42, 0.18);
    --portal-shadow-lg: 0 24px 56px -16px rgba(15, 23, 42, 0.22);
    --portal-radius: 16px;
    --portal-radius-sm: 10px;

    /* ── B6 derived tokens. Every one of these replaced a hardcoded white or
       slate literal further down this file — the glass topbar, the card
       surfaces, the hairline strengths, the hover wash, the accent-tint base
       and the drawer scrim were all pinned light. Each is expressed as a
       color-mix off --portal-surface or --portal-ink, so:
         - on the light palette they compute to the EXACT literal they replaced
           (surface resolves to #ffffff and ink to #0f172a = rgb(15 23 42), so
           e.g. 6% of ink over transparent is rgba(15,23,42,0.06));
         - a tenant that repoints canvas/surface/ink drags all of them along,
           with no second set of knobs to keep in sync. */
    --portal-topbar-bg: color-mix(in srgb, var(--portal-surface) 72%, transparent);
    --portal-surface-hover: color-mix(in srgb, var(--portal-surface) 94%, transparent);
    --portal-line-soft: color-mix(in srgb, var(--portal-ink) 6%, transparent);
    --portal-line-strong: color-mix(in srgb, var(--portal-ink) 12%, transparent);
    --portal-hover-wash: color-mix(in srgb, var(--portal-ink) 4%, transparent);
    /* What accent tints are mixed INTO for chips, icon tiles and active pills
       (was the literal `white`). */
    --portal-tint-base: var(--portal-surface);
    --portal-scrim: color-mix(in srgb, var(--portal-ink) 42%, transparent);
    --portal-subtle: var(--color-bg-subtle, #f8fafc);

    position: relative;
    min-height: 100vh;
    background: var(--portal-canvas);
    color: var(--portal-ink);
    font-feature-settings: "ss01", "cv11";
    /* `clip`, not `hidden`: a *scrolling* overflow value on one axis forces the
       other axis to compute to `auto`, which turns this element into a scroll
       container and silently neuters `position: sticky` on its descendants —
       the topbar and the left rail both depend on it. `clip` is not a scrolling
       value, so the block axis stays `visible` and sticky keeps working while
       stray horizontal overflow is still cut off. */
    overflow-x: clip;
}

/* ── B6: the DARK palette ───────────────────────────────────────────────────
   Reached by two independent triggers, and the ORDER OF PRECEDENCE between
   them is the whole point (portal pack P0 item 4):

     - the TENANT chooses the brand palette. data-portal-preset is stamped on
       the shell by PortalLayout from the tenant's stored PortalTheme; the
       attribute is ABSENT for a tenant that never configured one, so it
       cannot affect anybody who did not opt in. The tenant's accent arrives
       as an INLINE declaration and therefore outranks every rule in this
       file — that is what keeps branding intact in both light and dark.

     - the USER chooses light or dark WITHIN it, via ThemeSwitcher, which
       stamps data-theme on <html>. Two of the four user themes are dark
       ("dark" and the Operator Console); "high-contrast" is documented as
       having no dark bridge yet and is deliberately not listed here.

   User choice wins the neutrals (a requester who asked for dark gets dark
   even on a tenant pinned to the light preset); the tenant keeps the brand.
   The neutrals below read only the tenant's -dark overrides, which exist only
   when the tenant's own effective preset is dark — so a dark tenant's colours
   reach every reader, and a light tenant's never reach this rule (see the
   light palette above for the bug the untagged names caused).

   WHY THIS IS A BUG FIX AND NOT POLISH. Three of the base tokens above are
   aliased to the SHARED role scale (--color-bg-card / --color-text-dark /
   --color-text-muted) and the rest are light literals. So before this rule
   existed, a user on the dark theme got a HALF-flip: --portal-ink followed
   the shared scale to near-white (#f1f5f9) while --portal-canvas stayed the
   light literal #f6f7fb. .portal-shell sets `background: var(--portal-canvas)`
   and `color: var(--portal-ink)` — near-white text on a near-white canvas,
   about 1.03:1. Every heading and paragraph rendered directly on the canvas
   rather than inside a card was effectively invisible. Cards happened to
   survive because --portal-surface is one of the aliased three.

   Only the base palette is restated here — every derived token above is a
   color-mix off --portal-surface / --portal-ink and follows automatically. The
   three exceptions are listed below with their reasons.

   Keep in step with PortalTheme.DarkPalette (C# cannot read a custom
   property, so the contrast maths needs its own copy of these values). */
.portal-shell[data-portal-preset="dark"][b-2hk7lilw2e],
html[data-theme="dark"] .portal-shell[b-2hk7lilw2e],
html[data-theme="operator"] .portal-shell[b-2hk7lilw2e] {
    --portal-canvas: var(--portal-canvas-dark, #0b1220);
    --portal-surface: var(--portal-surface-dark, #131c2e);
    --portal-surface-elevated: var(--portal-surface-elevated-dark, rgba(23, 33, 53, 0.78));
    --portal-ink: var(--portal-ink-dark, #e6edf7);
    --portal-ink-soft: var(--portal-ink-soft-dark, #9fb0c9);
    /* Was #6b7d99: 3.89–4.47:1 where the faint tier actually sits (cards,
       rail, surface, canvas) and 3.5:1 on an active row's accent wash. The
       same hue lifted until it clears 4.5:1 on every one of them, and still a
       step below --portal-ink-soft (1.47:1 apart) so meta text reads as meta.
       See the light rule for what the tier carries. */
    --portal-ink-faint: var(--portal-ink-faint-dark, #7e90ad);
    --portal-line: var(--portal-line-dark, rgba(226, 232, 240, 0.12));
    /* Only reached when the tenant has NO brand colour — the branding accent
       still arrives as an inline declaration and outranks this. */
    --portal-accent: #818cf8;
    /* White on this pale indigo is 2.98:1 — well under WCAG AA for the
       normal-size labels on .btn-primary. The deep ink reads 6.60:1 on it. */
    --portal-on-accent: #0b1020;
    /* ...and its partner: under a dark label the accent fills' gradients run
       LIGHTER, not darker (PortalTheme.AccentLiftVar). The light rule declares
       none, so every use falls back to the shipped darkening stop. The
       tenant's arrives inline with its label, as `initial` under white. */
    --portal-accent-lift: #ffffff;
    /* The accent as text on THIS palette (see the light rule). The tenant's
       arrives as --portal-accent-ink-dark — measured against the dark palette
       even for a Light tenant, because this rule is what a dark reader gets.
       Default = PortalTheme.DefaultAccentInk(Dark). */
    --portal-accent-ink: var(--portal-accent-ink-dark, #8e9aff);

    /* 1–2. Shadows and the drawer scrim are the two things that must NOT
       follow the ink: ink is near-white here, and a light "shadow" is a glow.
       Both stay tied to the canvas end of the scale, at the deeper alphas a
       dark surface needs to show any depth at all. */
    --portal-shadow-sm: 0 1px 2px rgba(2, 6, 16, 0.5), 0 1px 3px rgba(2, 6, 16, 0.42);
    --portal-shadow-md: 0 8px 24px -8px rgba(2, 6, 16, 0.68);
    --portal-shadow-lg: 0 24px 56px -16px rgba(2, 6, 16, 0.78);
    --portal-scrim: rgba(2, 6, 16, 0.62);
    /* 3. The subtle wash defaults to the shared --color-bg-subtle, which is
       following the OPERATOR theme; pin it to this palette instead. */
    --portal-subtle: #1a2438;

    /* Native widgets (scrollbars, date pickers, the default form-control
       chrome) read this, so they stop rendering as light rectangles. */
    color-scheme: dark;
}

/* The APP tokens (--color-*) that portal pages, plain links and the shared
   topbar menus are written in are re-pointed for this shell in app.css, not
   here: a dark-PRESET portal under a light reader is listed beside
   html[data-theme="dark"] in the dark theme block (the "dark-preset portal
   island"), so it gets the dark theme's link ink, text, washes and state
   colours from the one place they are defined. Operator readers keep their
   own; its magenta link already clears 4.5:1 here (4.95 / 4.51). */

/* Bootstrap bridge — portal-design-finalization batch C. ~43 portal pages use
   plain Bootstrap .btn-primary (Submit / Save / Send request, etc.), which
   follows the ADMIN's --color-primary token — a fixed blue for every tenant,
   regardless of their configured brand colour. Rather than touch every page,
   one scoped override here (mirrors the operator theme's own Bootstrap bridge
   in app.css) redirects every primary button rendered inside the portal shell
   to the signed-in tenant's own --portal-accent. */
[b-2hk7lilw2e] .btn-primary {
    /* Bootstrap 5.3 reads .btn's colour from --bs-btn-*-color, and `.btn:hover`
       (0,2,0) outranks a plain `.btn-primary { color }` — re-point the
       variables or the label snaps back to white on hover. */
    --bs-btn-color: var(--portal-on-accent, #fff);
    --bs-btn-hover-color: var(--portal-on-accent, #fff);
    --bs-btn-active-color: var(--portal-on-accent, #fff);
    --bs-btn-disabled-color: var(--portal-on-accent, #fff);
    color: var(--portal-on-accent, #fff);
    background-color: var(--portal-accent, #6164ee);
    border-color: var(--portal-accent, #6164ee);
}
[b-2hk7lilw2e] .btn-primary:hover {
    background-color: color-mix(in oklab, var(--portal-accent, #6164ee) 85%, black);
    border-color: color-mix(in oklab, var(--portal-accent, #6164ee) 85%, black);
    box-shadow: 0 4px 6px -1px color-mix(in oklab, var(--portal-accent, #6164ee) 25%, transparent);
}
[b-2hk7lilw2e] .btn-primary:disabled,
[b-2hk7lilw2e] .btn-primary.disabled {
    background-color: var(--portal-accent, #6164ee);
    border-color: var(--portal-accent, #6164ee);
    opacity: 0.6;
}
[b-2hk7lilw2e] .btn-check:checked + .btn-outline-primary,
[b-2hk7lilw2e] .btn-outline-primary:active {
    background-color: var(--portal-accent, #6164ee);
    border-color: var(--portal-accent, #6164ee);
}
[b-2hk7lilw2e] .btn-outline-primary {
    color: var(--portal-accent-ink, #514fd7);
    border-color: var(--portal-accent, #6164ee);
}
[b-2hk7lilw2e] .btn-outline-primary:hover {
    background-color: var(--portal-accent, #6164ee);
    border-color: var(--portal-accent, #6164ee);
    color: var(--portal-on-accent, #fff);
}

/* Slow-drifting aurora behind the content. Pure CSS, GPU-only props,
   muted opacity so it never fights the foreground. */
.portal-aurora[b-2hk7lilw2e] {
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    overflow: hidden;
}
.portal-aurora-blob[b-2hk7lilw2e] {
    position: absolute;
    border-radius: 50%;
    filter: blur(80px);
    opacity: 0.55;
    will-change: transform;
}
.portal-aurora-blob-a[b-2hk7lilw2e] {
    width: 520px; height: 520px;
    top: -160px; left: -120px;
    background: radial-gradient(circle, var(--portal-accent), transparent 70%);
    animation: portal-drift-a-b-2hk7lilw2e 22s ease-in-out infinite alternate;
}
.portal-aurora-blob-b[b-2hk7lilw2e] {
    width: 460px; height: 460px;
    top: 30%; right: -120px;
    background: radial-gradient(circle, color-mix(in oklab, var(--portal-accent) 65%, #ec4899), transparent 70%);
    opacity: 0.35;
    animation: portal-drift-b-b-2hk7lilw2e 28s ease-in-out infinite alternate;
}
.portal-aurora-blob-c[b-2hk7lilw2e] {
    width: 380px; height: 380px;
    bottom: -120px; left: 30%;
    background: radial-gradient(circle, color-mix(in oklab, var(--portal-accent) 50%, #06b6d4), transparent 70%);
    opacity: 0.3;
    animation: portal-drift-c-b-2hk7lilw2e 34s ease-in-out infinite alternate;
}
@keyframes portal-drift-a-b-2hk7lilw2e {
    0%   { transform: translate3d(0, 0, 0) scale(1); }
    100% { transform: translate3d(120px, 80px, 0) scale(1.08); }
}
@keyframes portal-drift-b-b-2hk7lilw2e {
    0%   { transform: translate3d(0, 0, 0) scale(1); }
    100% { transform: translate3d(-90px, 60px, 0) scale(1.05); }
}
@keyframes portal-drift-c-b-2hk7lilw2e {
    0%   { transform: translate3d(0, 0, 0) scale(1); }
    100% { transform: translate3d(140px, -100px, 0) scale(1.1); }
}

/* Top bar: glassy, sticks to the top with a sharp 1px line. Page navigation
   moved to the left rail (PortalNavRail) — what stays here is brand, search,
   appearance/language, notifications and the user chip. */
.portal-topbar[b-2hk7lilw2e] {
    position: sticky;
    top: 0;
    z-index: 30;
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: var(--portal-topbar-h);
    box-sizing: border-box;
    padding: 14px 24px;
    background: var(--portal-topbar-bg);
    border-bottom: 1px solid var(--portal-line);
    backdrop-filter: saturate(180%) blur(14px);
    -webkit-backdrop-filter: saturate(180%) blur(14px);
}
.portal-topbar-spacer[b-2hk7lilw2e] {
    flex: 1 1 auto;
}

.portal-brand[b-2hk7lilw2e] {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    font-weight: 600;
    color: var(--portal-ink);
    text-decoration: none;
    letter-spacing: -0.01em;
}
.portal-brand-mark[b-2hk7lilw2e] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: 9px;
    /* The label is --portal-on-accent and the gradient turns away from it
       (--portal-accent-lift, declared only under a dark label): it was a white
       glyph on the dark palette's #818cf8, 2.98:1. */
    background: linear-gradient(135deg,
        var(--portal-accent),
        color-mix(in oklab, var(--portal-accent) 60%, var(--portal-accent-lift, #1e1b4b)));
    color: var(--portal-on-accent, #fff);
    box-shadow: 0 6px 14px -4px color-mix(in oklab, var(--portal-accent) 65%, transparent);
}
.portal-brand-logo[b-2hk7lilw2e] {
    height: 32px;
    width: auto;
    border-radius: 8px;
    object-fit: contain;
}
.portal-brand-text[b-2hk7lilw2e] {
    font-size: 0.95rem;
}

/* Icon-only topbar affordance (search). What used to be .portal-nav-link,
   minus the strip: the 17 page links it styled now live in the rail. */
.portal-topbar-action[b-2hk7lilw2e] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: 999px;
    font-size: 0.95rem;
    color: var(--portal-ink-soft);
    text-decoration: none;
    transition: color 160ms ease, background 160ms ease;
}
.portal-topbar-action:hover[b-2hk7lilw2e] {
    color: var(--portal-ink);
    background: var(--portal-hover-wash);
}
.portal-topbar-action.is-active[b-2hk7lilw2e] {
    color: var(--portal-accent-ink);
    background: color-mix(in oklab, var(--portal-accent) 10%, var(--portal-tint-base));
}

/* Drawer trigger — hidden until the rail goes off-canvas at phone width. */
.portal-burger[b-2hk7lilw2e] {
    display: none;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 34px;
    height: 34px;
    margin: 0;
    border-radius: var(--portal-radius-sm);
    color: var(--portal-ink-soft);
    font-size: 1.15rem;
    cursor: pointer;
}
.portal-burger:hover[b-2hk7lilw2e] {
    color: var(--portal-ink);
    background: color-mix(in srgb, var(--portal-ink) 5%, transparent);
}

/* The checkbox is the drawer's only state. Fully removed (not just visually
   hidden) above the drawer breakpoint, so it can never sit in the tab order
   with no visible affordance — the sr-only treatment that keeps it
   keyboard-operable is restored alongside the drawer itself. */
.portal-rail-toggle[b-2hk7lilw2e] {
    display: none;
}

.portal-userbox[b-2hk7lilw2e] {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    padding: 6px 6px 6px 14px;
    border: 1px solid var(--portal-line);
    border-radius: 999px;
    background: var(--portal-surface);
    box-shadow: var(--portal-shadow-sm);
}
/* In RTL, the userbox sits at the visual right; using logical
   padding so the asymmetric 6px/14px flips automatically. */
.portal-userbox[b-2hk7lilw2e] { padding-inline: 14px 6px; }
.portal-userbox-name[b-2hk7lilw2e] {
    font-size: 0.85rem;
    color: var(--portal-ink);
    font-weight: 500;
    max-width: 14ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    text-decoration: none;
    transition: color 160ms ease;
}
.portal-userbox-name:hover[b-2hk7lilw2e] {
    color: var(--portal-accent-ink, #514fd7);
}
.portal-userbox-signout[b-2hk7lilw2e] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border-radius: 999px;
    color: var(--portal-ink-soft);
    text-decoration: none;
    transition: background 160ms ease, color 160ms ease;
}
.portal-userbox-signout:hover[b-2hk7lilw2e] {
    background: color-mix(in oklab, var(--portal-accent) 14%, var(--portal-tint-base));
    color: var(--portal-accent-ink);
}

/* Shell body — left rail beside the routed page. */
.portal-body[b-2hk7lilw2e] {
    position: relative;
    z-index: 1;
    display: flex;
    align-items: flex-start;
}

/* Page area. Generous vertical rhythm; the @key on the inner div forces
   Blazor to swap nodes on navigation, which lets the fade-in animation
   replay so each route entry feels intentional. */
.portal-main[b-2hk7lilw2e] {
    position: relative;
    z-index: 1;
    flex: 1 1 auto;
    min-width: 0;
    padding: 40px clamp(20px, 4vw, 64px) 80px;
    max-width: 1200px;
    margin: 0 auto;
}
/* 🔴 `backwards`, not `both` — same reason as .app-fade-up in app.css.
   This element wraps every portal page, and the forwards fill would keep the
   final keyframe applied forever. `transform: translateY(0)` computes to the
   identity matrix, NOT to `none`, and a non-none transform makes this the
   containing block for `position: fixed` descendants — so a page's own
   full-screen overlay resolves `inset: 0` against this box instead of the
   viewport. Approvals.razor renders two `position:fixed; inset:0` modals
   inside the page body; with the forwards fill their backdrops stopped at the
   content column instead of covering the screen.
   The final keyframe equals the element's natural state, so releasing the
   fill changes nothing visually. */
.portal-content[b-2hk7lilw2e] {
    animation: portal-page-in-b-2hk7lilw2e 380ms cubic-bezier(0.22, 1, 0.36, 1) backwards;
}
@keyframes portal-page-in-b-2hk7lilw2e {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* Tap-outside-to-close backdrop for the mobile drawer. Off (and unclickable)
   at every width until the drawer is actually open. */
.portal-rail-scrim[b-2hk7lilw2e] {
    display: none;
}

/* Mobile: the rail becomes an off-canvas drawer driven by the hidden
   checkbox above. `::deep` because .portal-rail belongs to PortalNavRail —
   this layout's scoped CSS stops at its own markup otherwise. */
@media (max-width: 720px) {
    .portal-shell[b-2hk7lilw2e] {
        /* Same arithmetic with the tighter phone padding: 10 + 44 + 10 + 1. */
        --portal-topbar-h: 65px;
    }
    .portal-topbar[b-2hk7lilw2e] {
        gap: 8px;
        padding: 10px 14px;
    }
    .portal-burger[b-2hk7lilw2e] {
        display: inline-flex;
    }
    .portal-main[b-2hk7lilw2e] {
        padding: 28px 16px 64px;
    }

    /* sr-only: off-screen for sighted users, still focusable and toggleable
       with Space. The focus ring is painted on the hamburger they can see. */
    .portal-rail-toggle[b-2hk7lilw2e] {
        display: block;
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        padding: 0;
        border: 0;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }
    .portal-rail-toggle:focus-visible + .portal-topbar .portal-burger[b-2hk7lilw2e] {
        outline: 2px solid var(--portal-accent);
        outline-offset: 2px;
    }

    .portal-rail-scrim[b-2hk7lilw2e] {
        display: block;
        position: fixed;
        inset: 0;
        z-index: 39;
        background: var(--portal-scrim);
        opacity: 0;
        pointer-events: none;
        transition: opacity 200ms ease;
    }

    .portal-rail-toggle:checked ~ .portal-body[b-2hk7lilw2e]  .portal-rail {
        inset-inline-start: 0;
    }
    .portal-rail-toggle:checked ~ .portal-body .portal-rail-scrim[b-2hk7lilw2e] {
        opacity: 1;
        pointer-events: auto;
    }
}

/* Honor users who've opted out of motion. */
@media (prefers-reduced-motion: reduce) {
    .portal-aurora-blob[b-2hk7lilw2e],
    .portal-content[b-2hk7lilw2e] {
        animation: none !important;
    }
    .portal-rail-scrim[b-2hk7lilw2e] {
        transition: none !important;
    }
}

/* ── Shared component styles for child portal pages ─────────────────────
   Blazor scoped CSS only applies to the layout's own DOM; using ::deep
   forwards selectors into descendant components (the routed page Body).
   Anything used across multiple portal pages lives here so each page
   can stay markup-only. */

[b-2hk7lilw2e] .portal-hero {
    margin-bottom: 32px;
    padding-bottom: 4px;
}
[b-2hk7lilw2e] .portal-eyebrow {
    display: inline-block;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.18em;
    color: var(--portal-accent-ink, #514fd7);
    font-weight: 600;
    margin-bottom: 10px;
}
[b-2hk7lilw2e] .portal-title {
    font-size: clamp(1.75rem, 3vw, 2.4rem);
    font-weight: 700;
    letter-spacing: -0.02em;
    margin: 0 0 8px;
    color: var(--portal-ink);
    background: linear-gradient(135deg,
        var(--portal-ink) 0%,
        color-mix(in oklab, var(--portal-ink) 60%, var(--portal-accent-ink, #514fd7)) 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}
[b-2hk7lilw2e] .portal-subtitle {
    font-size: 1.025rem;
    color: var(--portal-ink-soft);
    max-width: 620px;
    line-height: 1.55;
    margin: 0;
}

[b-2hk7lilw2e] .portal-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 18px;
    margin-top: 28px;
}

/* Cards. Slight glassmorphism, lift on hover, staggered enter via
   --stagger custom property set inline by the page. */
[b-2hk7lilw2e] .portal-card {
    --stagger: 0;
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 22px 22px 20px;
    border-radius: 16px;
    background: var(--portal-surface-elevated);
    border: 1px solid var(--portal-line-soft);
    box-shadow: var(--portal-shadow-sm);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    color: inherit;
    text-decoration: none;
    transition:
        transform 220ms cubic-bezier(0.22, 1, 0.36, 1),
        box-shadow 220ms ease,
        border-color 220ms ease,
        background 220ms ease;
    animation: portal-card-in-b-2hk7lilw2e 460ms cubic-bezier(0.22, 1, 0.36, 1) both;
    animation-delay: calc(var(--stagger) * 60ms);
}
[b-2hk7lilw2e] .portal-card:hover {
    transform: translateY(-3px);
    background: var(--portal-surface-hover);
    border-color: color-mix(in oklab, var(--portal-accent, #6164ee) 35%, transparent);
    box-shadow: var(--portal-shadow-lg);
}
[b-2hk7lilw2e] .portal-card:focus-visible {
    outline: 2px solid var(--portal-accent, #6164ee);
    outline-offset: 3px;
}
[b-2hk7lilw2e] .portal-card-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: 12px;
    background: linear-gradient(135deg,
        color-mix(in oklab, var(--portal-accent, #6164ee) 18%, var(--portal-tint-base)),
        color-mix(in oklab, var(--portal-accent, #6164ee) 30%, var(--portal-tint-base)));
    color: var(--portal-accent-ink, #514fd7);
    font-size: 1.15rem;
}
[b-2hk7lilw2e] .portal-card-eyebrow {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--portal-ink-faint);
    font-weight: 600;
}
[b-2hk7lilw2e] .portal-card-title {
    font-size: 1.125rem;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--portal-ink);
    margin: 0;
}
[b-2hk7lilw2e] .portal-card-meta {
    font-size: 0.875rem;
    color: var(--portal-ink-soft);
    line-height: 1.45;
    margin: 0;
}
[b-2hk7lilw2e] .portal-card-count {
    font-family: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
    font-feature-settings: "tnum";
    font-size: 1.85rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    line-height: 1;
    color: var(--portal-ink);
}
[b-2hk7lilw2e] .portal-card-cta {
    margin-top: auto;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 0.85rem;
    font-weight: 500;
    color: var(--portal-accent-ink, #514fd7);
}
[b-2hk7lilw2e] .portal-card-cta i {
    transition: transform 200ms ease;
}
[b-2hk7lilw2e] .portal-card:hover .portal-card-cta i {
    transform: translateX(3px);
}
[b-2hk7lilw2e] .portal-card-disabled {
    opacity: 0.55;
    cursor: not-allowed;
    pointer-events: none;
}
@keyframes portal-card-in-b-2hk7lilw2e {
    from { opacity: 0; transform: translateY(14px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* Section frame. The opaque alternative to a card — used for lists where
   transparency would compete with row content. */
[b-2hk7lilw2e] .portal-section {
    margin-top: 36px;
    padding: 26px 28px;
    background: var(--portal-surface);
    border-radius: 18px;
    border: 1px solid var(--portal-line-soft);
    box-shadow: var(--portal-shadow-sm);
}
[b-2hk7lilw2e] .portal-section-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 16px;
}
[b-2hk7lilw2e] .portal-section-title {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--portal-ink);
    letter-spacing: -0.005em;
    margin: 0;
}
[b-2hk7lilw2e] .portal-section-meta {
    font-size: 0.8rem;
    color: var(--portal-ink-faint);
}

/* Item list. Repeat-pattern row used by Devices, Licenses, Tickets, etc. */
[b-2hk7lilw2e] .portal-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
}
[b-2hk7lilw2e] .portal-list-row {
    --stagger: 0;
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 14px 4px;
    border-bottom: 1px solid var(--portal-line-soft);
    animation: portal-card-in-b-2hk7lilw2e 360ms cubic-bezier(0.22, 1, 0.36, 1) both;
    animation-delay: calc(var(--stagger) * 40ms);
}
[b-2hk7lilw2e] .portal-list-row:last-child { border-bottom: 0; }
[b-2hk7lilw2e] .portal-list-icon {
    width: 38px;
    height: 38px;
    border-radius: 10px;
    background: color-mix(in oklab, var(--portal-accent, #6164ee) 12%, var(--portal-tint-base));
    color: var(--portal-accent-ink, #514fd7);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    font-size: 1rem;
}
[b-2hk7lilw2e] .portal-list-main {
    min-width: 0;
    flex: 1;
}
[b-2hk7lilw2e] .portal-list-title {
    font-size: 0.95rem;
    font-weight: 500;
    color: var(--portal-ink);
    line-height: 1.3;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
[b-2hk7lilw2e] .portal-list-meta {
    font-size: 0.8rem;
    color: var(--portal-ink-soft);
    margin-top: 2px;
}
[b-2hk7lilw2e] .portal-list-aside {
    font-size: 0.78rem;
    color: var(--portal-ink-faint);
    text-align: right;
    flex-shrink: 0;
}

/* Empty state. Centered, soft, with a calm illustration glyph. */
[b-2hk7lilw2e] .portal-empty {
    text-align: center;
    padding: 56px 24px;
    color: var(--portal-ink-soft);
}
[b-2hk7lilw2e] .portal-empty-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
    border-radius: 16px;
    background: color-mix(in oklab, var(--portal-accent, #6164ee) 10%, var(--portal-tint-base));
    color: var(--portal-accent-ink, #514fd7);
    font-size: 1.5rem;
    margin-bottom: 14px;
}
[b-2hk7lilw2e] .portal-empty-title {
    font-size: 1rem;
    font-weight: 600;
    color: var(--portal-ink);
    margin: 0 0 4px;
}
[b-2hk7lilw2e] .portal-empty-meta {
    font-size: 0.875rem;
    margin: 0;
}

/* Status pill — was a bespoke ::deep class system (Color-coded by status);
   every portal page has been migrated to the shared <Pill> component
   (Components/Shared/Pill.razor) instead, so this whole block is gone. */

/* Buttons. Primary = brand gradient with shadow, secondary = soft outline. */
[b-2hk7lilw2e] .portal-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 10px 18px;
    border-radius: 10px;
    font-size: 0.9rem;
    font-weight: 500;
    letter-spacing: -0.005em;
    border: 1px solid transparent;
    cursor: pointer;
    transition: transform 140ms ease, box-shadow 200ms ease, background 200ms ease;
    text-decoration: none;
}
[b-2hk7lilw2e] .portal-btn:active { transform: translateY(1px); }
/* Label and gradient as on .portal-brand-mark: the label is the accent's own
   foreground and the far stop turns away from it. The literal white label read
   2.98:1 on the dark palette's #818cf8 for every dark reader. */
[b-2hk7lilw2e] .portal-btn-primary {
    color: var(--portal-on-accent, #fff);
    background: linear-gradient(135deg,
        var(--portal-accent, #6164ee),
        color-mix(in oklab, var(--portal-accent, #6164ee) 60%, var(--portal-accent-lift, #1e1b4b)));
    box-shadow: 0 8px 22px -8px color-mix(in oklab, var(--portal-accent, #6164ee) 65%, transparent);
}
[b-2hk7lilw2e] .portal-btn-primary:hover {
    box-shadow: 0 14px 28px -10px color-mix(in oklab, var(--portal-accent, #6164ee) 70%, transparent);
}
[b-2hk7lilw2e] .portal-btn-primary:disabled {
    opacity: 0.6;
    cursor: not-allowed;
    box-shadow: none;
}
[b-2hk7lilw2e] .portal-btn-secondary {
    color: var(--portal-ink);
    background: var(--portal-surface);
    border-color: color-mix(in srgb, var(--portal-ink) 10%, transparent);
}
[b-2hk7lilw2e] .portal-btn-secondary:hover {
    border-color: color-mix(in srgb, var(--portal-ink) 25%, transparent);
    background: var(--portal-subtle);
}

/* Form controls — used by the ticket submission form. */
[b-2hk7lilw2e] .portal-field {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-bottom: 18px;
}
[b-2hk7lilw2e] .portal-field-label {
    font-size: 0.825rem;
    font-weight: 500;
    color: var(--portal-ink);
}
[b-2hk7lilw2e] .portal-field-hint {
    font-size: 0.75rem;
    color: var(--portal-ink-faint);
}
[b-2hk7lilw2e] .portal-input,
[b-2hk7lilw2e] .portal-textarea,
[b-2hk7lilw2e] .portal-select {
    width: 100%;
    padding: 10px 14px;
    border-radius: 10px;
    border: 1px solid var(--portal-line-strong);
    background: var(--portal-surface);
    font-size: 0.925rem;
    color: var(--portal-ink);
    transition: border-color 160ms ease, box-shadow 160ms ease;
    font-family: inherit;
}
[b-2hk7lilw2e] .portal-textarea {
    min-height: 140px;
    line-height: 1.55;
    resize: vertical;
}
[b-2hk7lilw2e] .portal-input:focus,
[b-2hk7lilw2e] .portal-textarea:focus,
[b-2hk7lilw2e] .portal-select:focus {
    outline: none;
    border-color: var(--portal-accent, #6164ee);
    box-shadow: 0 0 0 4px color-mix(in oklab, var(--portal-accent, #6164ee) 18%, transparent);
}

@media (prefers-reduced-motion: reduce) {
    [b-2hk7lilw2e] .portal-card,
    [b-2hk7lilw2e] .portal-list-row,
    [b-2hk7lilw2e] .portal-card-cta i {
        animation: none !important;
        transition: none !important;
    }
}

/* ── P4 commit E — form/kv grids that can actually collapse ───────────────────
   Four portal pages hardcoded their column counts in an inline style attribute
   (`style="display:grid; grid-template-columns: 2fr 1fr 1fr"` and friends).
   A media query cannot override an inline style, so those grids kept three
   columns on a 390px phone no matter what any stylesheet said — the fields
   were ~90px wide and their inputs unusable. Same shape, now as classes, so
   the <= 560px block below can stack them. ── */
[b-2hk7lilw2e] .portal-field-grid {
    display: grid;
    gap: 12px;
}
[b-2hk7lilw2e] .portal-field-grid-2 { grid-template-columns: 1fr 1fr; }
[b-2hk7lilw2e] .portal-field-grid-3 { grid-template-columns: 2fr 1fr 1fr; }

/* Devices' per-asset key/value list — same inline-style problem. */
[b-2hk7lilw2e] .portal-kv-grid {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 2px 10px;
}

/* ── P4 commit E — 44px touch targets ─────────────────────────────────────────
   .portal-btn computed to ~38-40px tall, under the 44px minimum the rest of
   this app already holds itself to (MainLayout.razor.css, TopSectionNav.razor.css
   and several rules in app.css). Padding alone cannot fix it without changing
   the visual weight, so min-height carries it and the flex centring keeps the
   label where it was. ── */
[b-2hk7lilw2e] .portal-btn {
    min-height: 44px;
}

/* The portal had focus rings on the drawer toggle, .portal-card and the nav —
   but not on its own buttons, which are the primary action on most pages. */
[b-2hk7lilw2e] .portal-btn:focus-visible {
    outline: 2px solid var(--portal-accent);
    outline-offset: 2px;
}

/* ── Phone density (<= 560px) ──
   The tile grid is minmax(280px, 1fr), so a 390px phone got ONE tall card per
   row and /portal ran to ~3050px of scroll. The secondary cards go two-up and
   compact here; the hero and the quick-action row (the PRIMARY actions) keep
   their full size deliberately.

   MUST stay at the END of this file: these selectors have the same specificity
   as the base .portal-card / .portal-grid rules above, so source order is the
   only thing that decides the winner. */
@media (max-width: 560px) {
    [b-2hk7lilw2e] .portal-grid {
        grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr));
        gap: 10px;
        margin-top: 20px;
    }
    [b-2hk7lilw2e] .portal-card {
        gap: 8px;
        padding: 14px 14px 12px;
        border-radius: 14px;
    }
    [b-2hk7lilw2e] .portal-card-icon {
        width: 34px;
        height: 34px;
        border-radius: 10px;
        font-size: 0.95rem;
    }
    [b-2hk7lilw2e] .portal-card-eyebrow {
        font-size: 0.62rem;
        letter-spacing: 0.1em;
    }
    [b-2hk7lilw2e] .portal-card-title { font-size: 0.95rem; }
    [b-2hk7lilw2e] .portal-card-count { font-size: 1.4rem; }
    [b-2hk7lilw2e] .portal-card-meta { font-size: 0.78rem; line-height: 1.35; }
    [b-2hk7lilw2e] .portal-card-cta { font-size: 0.78rem; }

    /* ── P4 commit E ──────────────────────────────────────────────────────────
       .portal-list-row is display:flex with NO wrap and no phone override, and
       it backs the row layout on ~13 portal pages. On a 390px screen the icon,
       title, meta and action buttons all competed for one line: the text
       squeezed to a couple of characters per line and the trailing actions were
       pushed off the edge. Wrapping the row and letting the main column take
       the full width stacks it the way every other card on these pages does. */
    [b-2hk7lilw2e] .portal-list-row {
        flex-wrap: wrap;
        align-items: flex-start;
        gap: 10px 12px;
    }
    [b-2hk7lilw2e] .portal-list-row > .portal-list-main {
        flex: 1 1 100%;
        min-width: 0;
    }
    /* The leading icon keeps its own line-start position rather than wrapping
       to a row of its own. */
    [b-2hk7lilw2e] .portal-list-row > .portal-list-icon {
        flex: 0 0 auto;
    }

    /* Fixed-column form grids stack (see the class definitions above — they
       exist precisely so this rule can win, which it could not against the
       inline styles these replaced). */
    [b-2hk7lilw2e] .portal-field-grid-2,
    [b-2hk7lilw2e] .portal-field-grid-3 {
        grid-template-columns: 1fr;
    }
    [b-2hk7lilw2e] .portal-kv-grid {
        grid-template-columns: 1fr;
        gap: 0 0;
    }
    [b-2hk7lilw2e] .portal-kv-grid dt { margin-top: 6px; }

    /* ── Card-collapse for the one raw <table> left in the portal ─────────────
       MyVisitors renders a 6-column Bootstrap table, which on a phone either
       overflows the viewport or crushes every column to unreadable. Collapsing
       to one card per visit is the pattern the rest of the portal already uses.
       The header row is hidden and each cell carries its own label from
       data-label — without that a stacked row is an unlabelled list of values,
       which is worse than the scroll it replaces. Empty cells (the escort chip,
       the action column when no actions apply) collapse away rather than
       leaving a labelled blank. */
    [b-2hk7lilw2e] table.portal-cardify,
    [b-2hk7lilw2e] table.portal-cardify tbody,
    [b-2hk7lilw2e] table.portal-cardify tr,
    [b-2hk7lilw2e] table.portal-cardify td {
        display: block;
        width: auto;
    }
    [b-2hk7lilw2e] table.portal-cardify thead {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }
    [b-2hk7lilw2e] table.portal-cardify tr {
        margin-bottom: 12px;
        padding: 12px 14px;
        border: 1px solid var(--portal-line);
        border-radius: var(--portal-radius-sm);
        background: var(--portal-surface);
    }
    [b-2hk7lilw2e] table.portal-cardify td {
        border: 0;
        padding: 4px 0;
        text-align: start;
    }
    [b-2hk7lilw2e] table.portal-cardify td:empty {
        display: none;
    }
    [b-2hk7lilw2e] table.portal-cardify td[data-label]::before {
        content: attr(data-label);
        display: block;
        font-size: 0.72rem;
        font-weight: 600;
        letter-spacing: 0.06em;
        text-transform: uppercase;
        /* --portal-ink-faint was #94a3b8 then, 2.59:1 on the light surface — well
           under the 4.5:1 AA floor, and this is ~11.5px uppercase text that
           carries the COLUMN NAME on phones, i.e. the only thing telling a
           reader what each value in a collapsed row means. --portal-ink-soft is
           ~7.4:1 light / ~8.6:1 dark and is already the token every other
           secondary label on this shell uses, so it needs no new keep-in-step
           contract between the two palette blocks. (Adversarial review P12.) */
        color: var(--portal-ink-soft);
    }
}
/* /Components/Layout/PortalNavRail.razor.rz.scp.css */
/* Self-service portal LEFT navigation rail.

   Every colour, radius and shadow here comes from the --portal-* custom
   properties declared on .portal-shell (PortalLayout.razor.css). CSS custom
   properties inherit through the DOM regardless of scoped-CSS boundaries, so
   the rail picks up the tenant's --portal-accent automatically — and the
   upcoming portal-theming work only has to move those tokens.

   Responsive behaviour is PURE CSS (no JS, no interactive island):
     >1080px  full rail, labels + section headings
     721-1080 icons-only strip, headings collapse to hairline dividers
     <=720px  off-canvas drawer, opened by the topbar hamburger (the checkbox
              and the open-state rule live in PortalLayout.razor.css, which
              owns the checkbox element). */

.portal-rail[b-uu2gcks63u] {
    flex: 0 0 auto;
    position: sticky;
    top: var(--portal-topbar-h, 73px);
    align-self: flex-start;
    z-index: 5;
    box-sizing: border-box;
    width: 244px;
    max-height: calc(100vh - var(--portal-topbar-h, 73px));
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 22px 14px 32px;
    display: flex;
    flex-direction: column;
    gap: 20px;
    border-inline-end: 1px solid var(--portal-line, rgba(15, 23, 42, 0.08));
    background: var(--portal-surface-elevated, rgba(255, 255, 255, 0.78));
    backdrop-filter: saturate(180%) blur(14px);
    -webkit-backdrop-filter: saturate(180%) blur(14px);
}

.portal-rail-section[b-uu2gcks63u] {
    display: block;
}

.portal-rail-heading[b-uu2gcks63u] {
    margin: 0 0 6px;
    padding-inline: 12px;
    font-size: 0.68rem;
    font-weight: 600;
    line-height: 1.4;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--portal-ink-faint, #546478);
}
/* The group containing the active entry gets the tenant accent on its
   heading, so the rail reads as "you are here" even above the fold. */
.portal-rail-section.is-current .portal-rail-heading[b-uu2gcks63u] {
    color: var(--portal-accent-ink, #514fd7);
}

/* Footer weight (portal pack P0 item 3) — account housekeeping: profile,
   notification preferences, onboarding, feedback. These have to be FINDABLE,
   which is the whole point of the item, but they must not compete with the
   two Required cards ("raise a request" / "track it") for attention.

   The rail is a flex column, so margin-block-start:auto absorbs whatever slack
   is left and pins the group to the bottom; when the rail is taller than the
   viewport there is no slack and it simply follows the last group, which is
   the behaviour we want rather than an overlap.

   Only the FIRST footer group takes the auto margin — a second one would
   otherwise absorb its own share of the slack and the two would drift apart.
   Today there is exactly one, and this keeps that from being load-bearing. */
.portal-rail-section.is-footer[b-uu2gcks63u] {
    margin-block-start: auto;
    padding-block-start: 18px;
    border-block-start: 1px solid var(--portal-line-soft, rgba(15, 23, 42, 0.06));
}
.portal-rail-section.is-footer + .portal-rail-section.is-footer[b-uu2gcks63u] {
    margin-block-start: 0;
    padding-block-start: 0;
    border-block-start: none;
}
/* De-emphasised, but deliberately NOT below the contrast floor: these are
   real destinations, not decoration. The faint token is the same one the
   section headings already use, and it clears 4.5:1 on both palettes
   (PortalLayout.razor.css; it used to read 2.5 light / 4.0 dark here). */
.portal-rail-section.is-footer .portal-rail-link[b-uu2gcks63u] {
    font-weight: 400;
    color: var(--portal-ink-faint, #546478);
}
/* Hover/active must still read normally — the de-emphasis is a resting state,
   not a permanent handicap. */
.portal-rail-section.is-footer .portal-rail-link:hover[b-uu2gcks63u],
.portal-rail-section.is-footer .portal-rail-link:focus-visible[b-uu2gcks63u],
.portal-rail-section.is-footer .portal-rail-link.is-active[b-uu2gcks63u] {
    color: var(--portal-ink, #0f172a);
}

.portal-rail-list[b-uu2gcks63u] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.portal-rail-item[b-uu2gcks63u] {
    display: block;
}

.portal-rail-link[b-uu2gcks63u] {
    position: relative;
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 9px 12px;
    border-radius: var(--portal-radius-sm, 10px);
    font-size: 0.875rem;
    font-weight: 500;
    line-height: 1.3;
    color: var(--portal-ink-soft, #475569);
    text-decoration: none;
    transition: color 160ms ease, background 160ms ease;
}
.portal-rail-icon[b-uu2gcks63u] {
    flex: 0 0 auto;
    width: 1.15rem;
    text-align: center;
    font-size: 1rem;
    color: var(--portal-ink-faint, #546478);
    transition: color 160ms ease;
}
.portal-rail-label[b-uu2gcks63u] {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.portal-rail-link:hover[b-uu2gcks63u] {
    color: var(--portal-ink, #0f172a);
    background: color-mix(in oklab, var(--portal-accent, #6164ee) 9%, transparent);
}
.portal-rail-link:hover .portal-rail-icon[b-uu2gcks63u] {
    color: var(--portal-ink-soft, #475569);
}
.portal-rail-link:focus-visible[b-uu2gcks63u] {
    outline: 2px solid var(--portal-accent, #6164ee);
    outline-offset: 2px;
}

.portal-rail-link.is-active[b-uu2gcks63u] {
    color: var(--portal-ink, #0f172a);
    font-weight: 600;
    background: color-mix(in oklab, var(--portal-accent, #6164ee) 13%, transparent);
}
.portal-rail-link.is-active .portal-rail-icon[b-uu2gcks63u] {
    color: var(--portal-accent-ink, #514fd7);
}
/* Accent bar on the inline-start edge — logical inset so RTL flips it. */
.portal-rail-link.is-active[b-uu2gcks63u]::before {
    content: "";
    position: absolute;
    inset-inline-start: 0;
    top: 7px;
    bottom: 7px;
    width: 3px;
    border-radius: 3px;
    background: var(--portal-accent, #6164ee);
    box-shadow: 0 0 12px color-mix(in oklab, var(--portal-accent, #6164ee) 60%, transparent);
}

/* ── Icons-only band ────────────────────────────────────────────────────
   Narrow enough that 244px of labels crowds the content, wide enough that a
   drawer would be overkill. Labels collapse; the title= tooltip resolved in
   the component keeps every entry identifiable, and the heading text stays in
   the accessibility tree (font-size:0 hides it visually only). */
@media (max-width: 1080px) and (min-width: 721px) {
    .portal-rail[b-uu2gcks63u] {
        width: 68px;
        padding-inline: 10px;
        gap: 14px;
    }
    .portal-rail-heading[b-uu2gcks63u] {
        height: 1px;
        margin: 4px 8px 8px;
        padding: 0;
        font-size: 0;
        line-height: 0;
        letter-spacing: 0;
        overflow: hidden;
        background: var(--portal-line, rgba(15, 23, 42, 0.08));
    }
    .portal-rail-section:first-child .portal-rail-heading[b-uu2gcks63u] {
        display: none;
    }
    .portal-rail-link[b-uu2gcks63u] {
        justify-content: center;
        padding-inline: 0;
    }
    .portal-rail-label[b-uu2gcks63u] {
        display: none;
    }
    .portal-rail-icon[b-uu2gcks63u] {
        width: auto;
        font-size: 1.15rem;
    }
    .portal-rail-link.is-active[b-uu2gcks63u]::before {
        display: none;
    }
}

/* ── Off-canvas drawer ──────────────────────────────────────────────────
   Slides in from the inline-start edge (logical property, so RTL comes out
   right without a mirrored rule). The open state is a single rule in
   PortalLayout.razor.css keyed off the hidden checkbox the topbar hamburger
   drives — that element lives in the layout, so the rule has to as well. */
@media (max-width: 720px) {
    .portal-rail[b-uu2gcks63u] {
        position: fixed;
        top: var(--portal-topbar-h, 65px);
        bottom: 0;
        inset-inline-start: -100%;
        z-index: 40;
        width: min(82vw, 288px);
        max-height: none;
        border-inline-end: 1px solid var(--portal-line, rgba(15, 23, 42, 0.08));
        background: var(--portal-surface, #ffffff);
        box-shadow: var(--portal-shadow-lg, 0 24px 56px -16px rgba(15, 23, 42, 0.22));
        transition: inset-inline-start 220ms cubic-bezier(0.22, 1, 0.36, 1);
    }
}

@media (prefers-reduced-motion: reduce) {
    .portal-rail[b-uu2gcks63u],
    .portal-rail-link[b-uu2gcks63u],
    .portal-rail-icon[b-uu2gcks63u] {
        transition: none !important;
    }
}
/* /Components/Layout/ReconnectModal.razor.rz.scp.css */
.components-reconnect-first-attempt-visible[b-ma0jk3j6so],
.components-reconnect-repeated-attempt-visible[b-ma0jk3j6so],
.components-reconnect-failed-visible[b-ma0jk3j6so],
.components-pause-visible[b-ma0jk3j6so],
.components-resume-failed-visible[b-ma0jk3j6so],
.components-rejoining-animation[b-ma0jk3j6so] {
    display: none;
}

#components-reconnect-modal.components-reconnect-show .components-reconnect-first-attempt-visible[b-ma0jk3j6so],
#components-reconnect-modal.components-reconnect-show .components-rejoining-animation[b-ma0jk3j6so],
#components-reconnect-modal.components-reconnect-paused .components-pause-visible[b-ma0jk3j6so],
#components-reconnect-modal.components-reconnect-resume-failed .components-resume-failed-visible[b-ma0jk3j6so],
#components-reconnect-modal.components-reconnect-retrying[b-ma0jk3j6so],
#components-reconnect-modal.components-reconnect-retrying .components-reconnect-repeated-attempt-visible[b-ma0jk3j6so],
#components-reconnect-modal.components-reconnect-retrying .components-rejoining-animation[b-ma0jk3j6so],
#components-reconnect-modal.components-reconnect-failed[b-ma0jk3j6so],
#components-reconnect-modal.components-reconnect-failed .components-reconnect-failed-visible[b-ma0jk3j6so] {
    display: block;
}


#components-reconnect-modal[b-ma0jk3j6so] {
    background-color: white;
    width: 20rem;
    margin: 20vh auto;
    padding: 2rem;
    border: 0;
    border-radius: 0.5rem;
    box-shadow: 0 3px 6px 2px rgba(0, 0, 0, 0.3);
    opacity: 0;
    transition: display 0.5s allow-discrete, overlay 0.5s allow-discrete;
    animation: components-reconnect-modal-fadeOutOpacity-b-ma0jk3j6so 0.5s both;
    &[open]

{
    animation: components-reconnect-modal-slideUp-b-ma0jk3j6so 1.5s cubic-bezier(.05, .89, .25, 1.02) 0.3s, components-reconnect-modal-fadeInOpacity-b-ma0jk3j6so 0.5s ease-in-out 0.3s;
    animation-fill-mode: both;
}

}

#components-reconnect-modal[b-ma0jk3j6so]::backdrop {
    background-color: rgba(0, 0, 0, 0.4);
    animation: components-reconnect-modal-fadeInOpacity-b-ma0jk3j6so 0.5s ease-in-out;
    opacity: 1;
}

@keyframes components-reconnect-modal-slideUp-b-ma0jk3j6so {
    0% {
        transform: translateY(30px) scale(0.95);
    }

    100% {
        transform: translateY(0);
    }
}

@keyframes components-reconnect-modal-fadeInOpacity-b-ma0jk3j6so {
    0% {
        opacity: 0;
    }

    100% {
        opacity: 1;
    }
}

@keyframes components-reconnect-modal-fadeOutOpacity-b-ma0jk3j6so {
    0% {
        opacity: 1;
    }

    100% {
        opacity: 0;
    }
}

.components-reconnect-container[b-ma0jk3j6so] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
}

#components-reconnect-modal p[b-ma0jk3j6so] {
    margin: 0;
    text-align: center;
}

#components-reconnect-modal button[b-ma0jk3j6so] {
    border: 0;
    background-color: #6b9ed2;
    color: white;
    padding: 4px 24px;
    border-radius: 4px;
}

    #components-reconnect-modal button:hover[b-ma0jk3j6so] {
        background-color: #3b6ea2;
    }

    #components-reconnect-modal button:active[b-ma0jk3j6so] {
        background-color: #6b9ed2;
    }

.components-rejoining-animation[b-ma0jk3j6so] {
    position: relative;
    width: 80px;
    height: 80px;
}

    .components-rejoining-animation div[b-ma0jk3j6so] {
        position: absolute;
        border: 3px solid #0087ff;
        opacity: 1;
        border-radius: 50%;
        animation: components-rejoining-animation-b-ma0jk3j6so 1.5s cubic-bezier(0, 0.2, 0.8, 1) infinite;
    }

        .components-rejoining-animation div:nth-child(2)[b-ma0jk3j6so] {
            animation-delay: -0.5s;
        }

@keyframes components-rejoining-animation-b-ma0jk3j6so {
    0% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 0;
    }

    4.9% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 0;
    }

    5% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 1;
    }

    100% {
        top: 0px;
        left: 0px;
        width: 80px;
        height: 80px;
        opacity: 0;
    }
}
/* /Components/Layout/TopSectionNav.razor.rz.scp.css */
/* Vertical icon rail on the left. Two states:
   - default: 64px wide, icons only
   - hover anywhere on the rail: expands to 240px, labels fade in inline
   The rail is position:absolute inside a 64px-wide flex slot so the
   expansion overlays the sub-sidebar instead of pushing it right. */

.section-rail-host[b-z61fy8m6f8] {
    width: 64px;
    flex-shrink: 0;
    align-self: stretch;
    position: relative;
}

/* The phone-only hamburger. Hidden at rail widths; the media query at the
   bottom of this file turns it on and pins it into the header strip. */
.section-rail-burger[b-z61fy8m6f8] {
    display: none;
}

/* Tap-outside-to-close backdrop. Off (and unclickable) until the drawer mode
   is active AND open, so it can never swallow desktop clicks. */
.section-rail-scrim[b-z61fy8m6f8] {
    display: none;
}

.section-nav[b-z61fy8m6f8] {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 64px;
    /* overflow-x clips the labels at the collapsed width (that IS the reveal
       mechanism); overflow-y lets a long module list scroll INSIDE the rail
       instead of being cut off at the viewport edge. */
    overflow-x: hidden;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    padding: 0.5rem 0;
    background: linear-gradient(180deg, #0f172a 0%, #1e293b 100%);
    border-right: 1px solid rgba(255, 255, 255, 0.05);
    z-index: 50;
    transition:
        width 220ms cubic-bezier(0.22, 1, 0.36, 1),
        box-shadow 220ms ease;
    scrollbar-width: none;
}

.section-nav[b-z61fy8m6f8]::-webkit-scrollbar {
    display: none;
}

/* Hover anywhere on the rail → expands and reveals labels inline.
   :focus-within does the same for keyboard users, who never generate a hover
   and previously tabbed through a rail of unlabelled icons. */
.section-nav:hover[b-z61fy8m6f8],
.section-nav:focus-within[b-z61fy8m6f8] {
    width: 240px;
    box-shadow: 6px 0 24px -6px rgba(0, 0, 0, 0.45);
}

/* Hover-intent delay: the expansion OVERLAYS the page content, so a mouse
   merely crossing the rail on its way somewhere else must not pop a 240px
   overlay over what the user is reading. Expansion waits ~250ms of sustained
   hover; collapse (the base rule, no delay) and keyboard focus (the rule
   below, ordered after so it wins the tie when both apply) stay immediate. */
.section-nav:hover[b-z61fy8m6f8] {
    transition-delay: 250ms;
}

.section-nav:focus-within[b-z61fy8m6f8] {
    transition-delay: 0s;
}

.section-tab[b-z61fy8m6f8] {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 14px;
    padding: 0 14px;
    height: 44px;
    /* A rail taller than the viewport made every item flex-shrink below its
       44px touch target. Pin the height and let the rail scroll instead. */
    flex: 0 0 auto;
    min-height: 44px;
    margin: 2px 8px;
    border-radius: 8px;
    color: rgba(203, 213, 225, 0.85);
    text-decoration: none;
    white-space: nowrap;
    overflow: hidden;
    transition: background-color 0.15s ease, color 0.15s ease;
    cursor: pointer;
    font-size: 0.88rem;
    font-weight: 500;
}

.section-tab:hover[b-z61fy8m6f8] {
    color: #ffffff;
    background-color: rgba(255, 255, 255, 0.08);
    text-decoration: none;
}

.section-tab:hover .section-tab-icon[b-z61fy8m6f8] {
    color: var(--color-chrome-accent-ink);
}

.section-tab.active[b-z61fy8m6f8] {
    color: #ffffff;
    background-color: rgba(255, 255, 255, 0.1);
}

/* Active accent stripe on the leading edge of the active tab. */
.section-tab.active[b-z61fy8m6f8]::before {
    content: "";
    position: absolute;
    left: -8px;
    top: 8px;
    bottom: 8px;
    width: 3px;
    background: var(--color-primary, #60a5fa);
    border-radius: 0 3px 3px 0;
}

.section-tab.active .section-tab-icon[b-z61fy8m6f8] {
    color: var(--color-chrome-accent-ink);
}

.section-tab-icon[b-z61fy8m6f8] {
    flex-shrink: 0;
    width: 24px;
    text-align: center;
    font-size: 1.3rem;
    line-height: 1;
}

/* Label sits inline next to its icon but stays hidden at the rail's
   default 64px width (overflow:hidden on the rail clips it). Fades in
   when the rail expands. */
.section-tab-label[b-z61fy8m6f8] {
    opacity: 0;
    transition: opacity 180ms ease;
}

.section-nav:hover .section-tab-label[b-z61fy8m6f8],
.section-nav:focus-within .section-tab-label[b-z61fy8m6f8] {
    opacity: 1;
    transition-delay: 80ms;
}

/* Labels follow the rail's hover-intent delay on mouse, but reveal promptly
   for keyboard (same ordering trick as the width rules above). */
.section-nav:hover .section-tab-label[b-z61fy8m6f8] {
    transition-delay: 330ms;
}

.section-nav:focus-within .section-tab-label[b-z61fy8m6f8] {
    transition-delay: 80ms;
}

/* Active module's config/admin sub-items, nested under the active tab.
   Hidden while the rail is collapsed (icons-only); revealed inline when the
   rail expands. Indented + smaller so they read as children of the module.
   These are rendered by <NavLink> (a child component), so they don't carry this
   component's scoped-CSS attribute — reach them via ::deep from the scoped
   .section-nav, else they fall back to the global blue/underlined link style. */
.section-nav[b-z61fy8m6f8]  .section-subtab {
    /* Collapsed via max-height (not display:none) so the reveal can honour
       the rail's hover-intent delay — display flips can't be delayed, and an
       instant flip made the icons below reflow the moment the pointer merely
       crossed the rail. Still zero-height + invisible while collapsed. */
    display: flex;
    flex: 0 0 auto;
    align-items: center;
    gap: 10px;
    height: 34px;
    max-height: 0;
    opacity: 0;
    margin: 0 8px;
    padding: 0 12px 0 30px;
    border-radius: 6px;
    color: rgba(203, 213, 225, 0.7);
    text-decoration: none;
    white-space: nowrap;
    overflow: hidden;
    font-size: 0.82rem;
    font-weight: 500;
    transition: background-color 0.15s ease, color 0.15s ease,
        max-height 140ms ease, opacity 140ms ease, margin 140ms ease;
}

.section-nav:hover[b-z61fy8m6f8]  .section-subtab,
.section-nav:focus-within[b-z61fy8m6f8]  .section-subtab {
    max-height: 34px;
    opacity: 1;
    margin: 1px 8px;
}

.section-nav:hover[b-z61fy8m6f8]  .section-subtab {
    transition-delay: 0s, 0s, 250ms, 250ms, 250ms;
}

.section-nav:focus-within[b-z61fy8m6f8]  .section-subtab {
    transition-delay: 0s;
}

.section-nav[b-z61fy8m6f8]  .section-subtab:hover {
    color: #ffffff;
    background-color: rgba(255, 255, 255, 0.06);
    text-decoration: none;
}

.section-nav[b-z61fy8m6f8]  .section-subtab.active {
    color: #ffffff;
    background-color: rgba(255, 255, 255, 0.08);
}

.section-nav[b-z61fy8m6f8]  .section-subtab-icon {
    flex-shrink: 0;
    width: 18px;
    text-align: center;
    font-size: 0.95rem;
    line-height: 1;
    opacity: 0.9;
}

.section-nav[b-z61fy8m6f8]  .section-subtab.active .section-subtab-icon,
.section-nav[b-z61fy8m6f8]  .section-subtab:hover .section-subtab-icon {
    color: var(--color-chrome-accent-ink);
}

/* Collapsible "Additional modules" group header. Renders as a <button> so it
   needs the UA button chrome reset to match the <a> tabs around it. */
.section-tab-group-header[b-z61fy8m6f8] {
    appearance: none;
    background: transparent;
    border: none;
    font-family: inherit;
    width: auto;
    color: rgba(203, 213, 225, 0.7);
    margin-top: 6px;
}

.section-tab-group-header:hover[b-z61fy8m6f8] {
    color: #ffffff;
    background-color: rgba(255, 255, 255, 0.08);
}

.section-tab-chevron[b-z61fy8m6f8] {
    margin-left: auto;
    font-size: 0.7rem;
    opacity: 0;
    transition: opacity 180ms ease;
}

.section-nav:hover .section-tab-chevron[b-z61fy8m6f8],
.section-nav:focus-within .section-tab-chevron[b-z61fy8m6f8] {
    opacity: 0.7;
    transition-delay: 80ms;
}

.section-tab-disabled[b-z61fy8m6f8] {
    opacity: 0.45;
    cursor: not-allowed;
}

.section-tab-disabled:hover[b-z61fy8m6f8] {
    color: rgba(203, 213, 225, 0.85);
    background-color: transparent;
}

.section-tab-disabled:hover .section-tab-icon[b-z61fy8m6f8] {
    color: rgba(203, 213, 225, 0.85);
}

.section-tab-lock[b-z61fy8m6f8] {
    margin-left: auto;
    font-size: 0.8rem;
    opacity: 0;
    transition: opacity 180ms ease;
}

.section-nav:hover .section-tab-lock[b-z61fy8m6f8],
.section-nav:focus-within .section-tab-lock[b-z61fy8m6f8] {
    opacity: 0.85;
    transition-delay: 80ms;
}

/* Menu-order editor entry point — pinned to the rail's bottom edge. */
.section-tab-customize[b-z61fy8m6f8] {
    margin-top: auto;
    color: rgba(203, 213, 225, 0.6);
}

/* The pin toggle inherits the tab look; it's a <button>, so it needs the same
   UA chrome reset as the group header. */
.section-rail-pin[b-z61fy8m6f8] {
    appearance: none;
    background: transparent;
    border: none;
    font-family: inherit;
    width: auto;
    color: rgba(203, 213, 225, 0.6);
}

.section-rail-pin:hover[b-z61fy8m6f8] {
    color: #ffffff;
    background-color: rgba(255, 255, 255, 0.08);
}

.section-rail-pin:focus-visible[b-z61fy8m6f8] {
    outline: 2px solid var(--color-primary, #60a5fa);
    outline-offset: -2px;
}

/* ============================================================================
   DESKTOP (>= 641px) — click-to-pin.
   ----------------------------------------------------------------------------
   Pinned, the host slot itself widens to 240px, so the rail becomes a normal
   flex column that PUSHES the content aside instead of overlaying it. The
   rules are desktop-scoped on purpose: at phone widths the host must stay a
   zero-size stub and the drawer rules own the rail.
   ============================================================================ */
@media (min-width: 641px) {
    .section-rail-host[b-z61fy8m6f8] {
        transition: width 220ms cubic-bezier(0.22, 1, 0.36, 1);
    }

    .section-rail-host.is-pinned[b-z61fy8m6f8] {
        width: 240px;
    }

    .is-pinned .section-nav[b-z61fy8m6f8] {
        width: 240px;
        box-shadow: none;
    }

    .is-pinned .section-nav .section-tab-label[b-z61fy8m6f8] {
        opacity: 1;
        transition-delay: 0ms;
    }

    .is-pinned .section-nav .section-tab-chevron[b-z61fy8m6f8] {
        opacity: 0.7;
        transition-delay: 0ms;
    }

    .is-pinned .section-nav .section-tab-lock[b-z61fy8m6f8] {
        opacity: 0.85;
        transition-delay: 0ms;
    }

    .is-pinned .section-nav[b-z61fy8m6f8]  .section-subtab {
        max-height: 34px;
        opacity: 1;
        margin: 1px 8px;
        transition-delay: 0s;
    }
}

/* ============================================================================
   PHONE (<= 640.98px) — the rail becomes an off-canvas drawer.
   ----------------------------------------------------------------------------
   MainLayout flips .app-body to a column at this breakpoint. The host used to
   stay a 64px-wide slot holding an absolutely-positioned rail, which collapsed
   to 64x16px: the primary module navigation was simply gone on a phone.

   Here the host takes NO space in the column, the burger is pinned into the
   3rem header strip beside the brand, and the rail slides in from the leading
   edge over a scrim. Labels are always visible in this mode — nothing is
   hover-gated, because there is no hover on touch.
   ============================================================================ */
@media (max-width: 640.98px) {
    /* Out of the flow entirely: no 64px column, no 16px stub, no contribution
       to document width. */
    .section-rail-host[b-z61fy8m6f8] {
        width: 0;
        height: 0;
        align-self: auto;
        position: static;
    }

    .section-rail-burger[b-z61fy8m6f8] {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        position: fixed;
        top: 0;
        inset-inline-start: 0;
        /* 48x48 — comfortably past the 44x44 touch-target floor, and exactly
           the .app-header-bar height so it sits flush in the brand strip. */
        width: 48px;
        height: 48px;
        padding: 0;
        border: 0;
        background: transparent;
        color: #e2e8f0;
        font-size: 1.4rem;
        line-height: 1;
        cursor: pointer;
        z-index: 60;
    }

    .section-rail-burger:hover[b-z61fy8m6f8] {
        color: #ffffff;
        background-color: rgba(255, 255, 255, 0.08);
    }

    .section-rail-burger:focus-visible[b-z61fy8m6f8] {
        outline: 2px solid var(--color-primary, #60a5fa);
        outline-offset: -3px;
    }

    .section-rail-scrim[b-z61fy8m6f8] {
        display: block;
        position: fixed;
        inset: 3rem 0 0 0;   /* below the sticky header, which stays usable */
        z-index: 45;
        background: rgba(2, 6, 23, 0.55);
        opacity: 0;
        pointer-events: none;
        transition: opacity 200ms ease;
    }

    .is-open .section-rail-scrim[b-z61fy8m6f8] {
        opacity: 1;
        pointer-events: auto;
    }

    .section-nav[b-z61fy8m6f8] {
        position: fixed;
        top: 3rem;
        bottom: 0;
        inset-inline-start: 0;
        width: min(82vw, 288px);
        z-index: 50;
        /* Off-canvas by transform, not by width, so the drawer keeps its full
           layout while hidden. visibility keeps it out of the tab order and
           off the a11y tree when closed. */
        transform: translateX(-100%);
        visibility: hidden;
        box-shadow: none;
        border-inline-end: 1px solid rgba(255, 255, 255, 0.08);
        transition:
            transform 220ms cubic-bezier(0.22, 1, 0.36, 1),
            visibility 0s linear 220ms;
    }

    /* Drawer state is explicit — hover/focus-within must NOT open it here,
       and the desktop hover-intent delay must not defer the drawer's own
       transform transitions. Per-property delays (transform, visibility —
       the base rule's property order): a single 0s would also zero the
       220ms visibility delay that keeps the drawer visible while it slides
       out, so closing it from inside (link tap, Escape) would blink instead
       of animating. Opening is unaffected — .is-open redefines the whole
       transition later in source at equal specificity. */
    .section-nav:hover[b-z61fy8m6f8],
    .section-nav:focus-within[b-z61fy8m6f8] {
        width: min(82vw, 288px);
        box-shadow: none;
        transition-delay: 0s, 220ms;
    }

    /* The pin toggle is a desktop affordance — in drawer mode it's noise. */
    .section-rail-pin[b-z61fy8m6f8] {
        display: none;
    }

    .is-open .section-nav[b-z61fy8m6f8] {
        transform: none;
        visibility: visible;
        box-shadow: 6px 0 28px -8px rgba(0, 0, 0, 0.6);
        transition:
            transform 220ms cubic-bezier(0.22, 1, 0.36, 1),
            visibility 0s;
    }

    /* Full-width drawer → labels and sub-items are always shown. No hover
       dependency, and touch targets get a little more room. */
    .section-tab-label[b-z61fy8m6f8],
    .section-nav:hover .section-tab-label[b-z61fy8m6f8] {
        opacity: 1;
    }

    .section-tab-chevron[b-z61fy8m6f8],
    .section-tab-lock[b-z61fy8m6f8] {
        opacity: 0.75;
    }

    .section-nav[b-z61fy8m6f8]  .section-subtab {
        display: flex;
        flex: 0 0 auto;
        min-height: 40px;
        max-height: none;
        opacity: 1;
        margin: 1px 8px;
    }

    .section-tab[b-z61fy8m6f8] {
        height: 48px;
        min-height: 48px;
    }
}

@media (prefers-reduced-motion: reduce) {
    .section-nav[b-z61fy8m6f8],
    .is-open .section-nav[b-z61fy8m6f8],
    .section-rail-scrim[b-z61fy8m6f8],
    .section-rail-host[b-z61fy8m6f8] {
        transition: none;
    }

    /* The hover-intent delay is not motion — keep it as a zero-duration,
       delayed state change so a mouse crossing the rail still doesn't pop
       the overlay over the content. Keyboard focus stays immediate. */
    .section-nav:hover[b-z61fy8m6f8] {
        transition: width 0s linear 250ms, box-shadow 0s linear 250ms;
    }

    .section-nav:focus-within[b-z61fy8m6f8] {
        transition: none;
    }

    .section-nav[b-z61fy8m6f8]  .section-subtab {
        transition: none;
    }

    .section-nav:hover[b-z61fy8m6f8]  .section-subtab {
        transition: max-height 0s linear 250ms, opacity 0s linear 250ms, margin 0s linear 250ms;
    }

    .section-nav:focus-within[b-z61fy8m6f8]  .section-subtab {
        transition: none;
    }
}
/* /Components/Layout/VendorLayout.razor.rz.scp.css */
/* Portal-design-finalization batch A — give the vendor shell a visible tenant
   accent instead of a flat Bootstrap navbar-dark. Stays a serious, neutral
   dark bar (vendors are external, not portal users) but tints toward the
   tenant's own colour and puts it plainly on the brand icon. The slate and the
   24% tint are PortalTheme.VendorBarSlate / VendorBarTint (keep in step): the
   icon's shade is measured against both stops. */
.vendor-topbar[b-4doyjmsto0] {
    background: linear-gradient(135deg,
        #1e293b,
        color-mix(in oklab, var(--portal-accent, #6164ee) 24%, #1e293b));
    border-bottom: 2px solid color-mix(in oklab, var(--portal-accent, #6164ee) 55%, transparent);
}

/* The brand as a glyph on the strip: the shade of it that reads there
   (PortalTheme.VendorBarInk), written by VendorLayout with the brand. The raw
   brand was 1.41:1 for a navy one, and the default indigo 2.47:1 at the
   tinted end; the fallback is VendorBarInk of that default. */
.vendor-brand-icon[b-4doyjmsto0] {
    color: var(--portal-accent-ink, #b2bdff);
}
/* /Components/Pages/Admin/BrandingPage.razor.rz.scp.css */
.branding-preview[b-ljuqfnxedw] {
    border: 1px dashed var(--color-border);
    border-radius: var(--radius-md);
    background: linear-gradient(135deg, var(--color-bg-subtle) 0%, #f1f5f9 100%);
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
}

.branding-preview img[b-ljuqfnxedw] {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

.branding-preview-logo[b-ljuqfnxedw] {
    height: 5rem;
    padding: 0.75rem;
}

.branding-preview-banner[b-ljuqfnxedw] {
    height: 9rem;
}

.branding-preview-banner img[b-ljuqfnxedw] {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.branding-preview-empty[b-ljuqfnxedw] {
    color: var(--color-text-muted);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.25rem;
    font-size: 0.875rem;
}

.branding-preview-empty i[b-ljuqfnxedw] {
    font-size: 1.5rem;
    opacity: 0.5;
}

/* The shades the shell paints the colour in as text (ShellAccent), shown
   when it needed one: the /admin/portal-theme note's layout. */
.branding-accentink[b-ljuqfnxedw] {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    font-size: 0.78rem;
    color: var(--color-text-muted);
}

.branding-accentink-list[b-ljuqfnxedw] {
    display: flex;
    flex-wrap: wrap;
    gap: 0.9rem;
}

.branding-accentink-item[b-ljuqfnxedw] {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    color: var(--color-text);
}

.branding-accentink-sample[b-ljuqfnxedw] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2rem;
    padding: 0.1rem 0.4rem;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    font-weight: 600;
}
/* /Components/Pages/KnowledgeBase/KbConflictPanel.razor.rz.scp.css */
/* The two bodies, side by side. Moved out of an inline <style> (the
   anti-pattern layout-50 retires) when P4 capped what the cells render. */
.kb-conflict-body[b-t8l1x53c8b] {
    max-height: 14rem;
    overflow: auto;
    white-space: pre-wrap;
    word-break: break-word;
    margin: 0;
}

/* KB Markdown plan P4 — "Show the full texts" and "Copy my text out" sit on
   the warning wash. Bootstrap's link blue is not themed for dark or operator
   and fails there; --color-text on the wash, underlined so it still reads as
   a control, clears 4.5:1 in all three themes (the PR carries the table). */
.kb-conflict-showall[b-t8l1x53c8b],
.kb-conflict-copy[b-t8l1x53c8b],
.kb-conflict-showall:hover[b-t8l1x53c8b],
.kb-conflict-copy:hover[b-t8l1x53c8b] {
    color: var(--color-text);
    text-decoration: underline;
}

.kb-conflict-showall:focus-visible[b-t8l1x53c8b],
.kb-conflict-copy:focus-visible[b-t8l1x53c8b] {
    outline: 2px solid var(--color-text);
    outline-offset: 2px;
    box-shadow: none;
}
/* /Components/Pages/KnowledgeBase/KnowledgeBaseEdit.razor.rz.scp.css */
/* KB Markdown plan P4 — "Discard them" on the unsaved-changes offer. Bootstrap's
   outline-secondary grey is not themed for dark or operator and sinks into the
   info wash there; --color-text on the wash and a --color-text-muted border
   clear 4.5:1 and 3:1 in all three themes (the PR carries the table). */
.kb-draft-discard[b-k84flsbb8l] {
    color: var(--color-text);
    background-color: transparent;
    border-color: var(--color-text-muted);
}

.kb-draft-discard:hover:not(:disabled)[b-k84flsbb8l],
.kb-draft-discard:focus-visible[b-k84flsbb8l] {
    color: var(--color-text);
    background-color: transparent;
    border-color: var(--color-text);
}

/* The KB Style Guide link beside "Content": --color-info, as in the editor's
   Markdown help — the global link colour (--color-primary) is 2.83:1 on the
   dark card. */
.kb-styleguide-link[b-k84flsbb8l],
.kb-styleguide-link:hover[b-k84flsbb8l] {
    color: var(--color-info);
}
/* /Components/Pages/MobilePlans/MobilePlanCreate.razor.rz.scp.css */
/* ============================================================================
   Guided plan-creation flow.

   Desktop: a generous editing surface with a compact live summary rail.
   Narrow:  everything stacks in DOM order (editor first, summary after), the
            step indicator collapses to compact numbered dots, and nothing may
            widen the document.
   Tokens only — no hard-coded colors, so light/dark/high-contrast and the
   density/font-scale themes all apply.
   ============================================================================ */

.plan-create-intro[b-4h5o6c3o3k] {
    max-width: 60ch;
}

/* ── Step indicator ── */
.plan-steps[b-4h5o6c3o3k] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    list-style: none;
    padding: 0;
    margin: 0 0 var(--space-3) 0;
}

.plan-steps__item[b-4h5o6c3o3k] {
    display: flex;
    align-items: center;
}

/* The connector line between steps. */
.plan-steps__item + .plan-steps__item[b-4h5o6c3o3k]::before {
    content: "";
    display: inline-block;
    width: 1.25rem;
    height: 1px;
    background: var(--color-border-strong);
    margin-inline-end: var(--space-2);
}

.plan-steps__btn[b-4h5o6c3o3k] {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    border: 0;
    background: transparent;
    padding: 0.25rem 0.4rem;
    border-radius: var(--radius-md);
    color: var(--color-text-muted);
    cursor: pointer;
    min-height: 44px; /* touch target */
}

.plan-steps__btn:disabled[b-4h5o6c3o3k] {
    cursor: default;
}

.plan-steps__btn:not(:disabled):hover[b-4h5o6c3o3k] {
    color: var(--color-primary-ink);
}

.plan-steps__num[b-4h5o6c3o3k] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 50%;
    border: 1px solid var(--color-border-strong);
    background: var(--color-bg-subtle);
    font-weight: var(--font-weight-medium);
    flex: 0 0 auto;
}

.plan-steps__item.is-current .plan-steps__btn[b-4h5o6c3o3k] {
    color: var(--color-text);
    font-weight: var(--font-weight-medium);
}

.plan-steps__item.is-current .plan-steps__num[b-4h5o6c3o3k] {
    background: var(--color-primary);
    border-color: var(--color-primary);
    color: var(--color-on-primary, #fff);
}

.plan-steps__item.is-done .plan-steps__num[b-4h5o6c3o3k] {
    border-color: var(--color-primary);
    color: var(--color-primary-ink);
}

/* ── Two-column layout: editor + summary rail ── */
.plan-create-layout[b-4h5o6c3o3k] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 300px;
    gap: var(--space-3);
    align-items: start;
}

.plan-create-summary[b-4h5o6c3o3k] {
    position: sticky;
    top: var(--space-3);
}

.plan-create-summary__title[b-4h5o6c3o3k] {
    margin-bottom: var(--space-2);
}

.plan-create-summary__subtitle[b-4h5o6c3o3k] {
    margin-top: var(--space-3);
    margin-bottom: var(--space-1);
    color: var(--color-text-muted);
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.plan-create-summary__list[b-4h5o6c3o3k] {
    list-style: none;
    margin: 0;
    padding: 0;
}

.plan-create-summary__list li[b-4h5o6c3o3k] {
    display: flex;
    justify-content: space-between;
    gap: var(--space-2);
    padding: 0.15rem 0;
    font-size: 0.9rem;
}

.plan-step-heading[b-4h5o6c3o3k] {
    margin-bottom: var(--space-2);
}

.plan-step-heading:focus[b-4h5o6c3o3k] {
    outline: none;
}

/* ── Staged item lists (bundles, options, review rows) ── */
.plan-staged-list[b-4h5o6c3o3k] {
    list-style: none;
    margin: 0 0 var(--space-3) 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.plan-staged-list__item[b-4h5o6c3o3k] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-bg-subtle);
    padding: var(--space-2) var(--space-3);
}

.plan-staged-list__item.is-editing[b-4h5o6c3o3k] {
    border-color: var(--color-primary);
}

.plan-staged-list__body[b-4h5o6c3o3k] {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.plan-staged-list__meta[b-4h5o6c3o3k] {
    color: var(--color-text-muted);
    font-size: 0.9rem;
}

.plan-staged-list__actions[b-4h5o6c3o3k] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
}

/* Keep the small action buttons comfortably tappable. */
.plan-staged-list__actions[b-4h5o6c3o3k]  .btn,
.plan-staged-list__actions .btn[b-4h5o6c3o3k] {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
}

/* ── Bundle / option sub-forms ── */
.plan-subform[b-4h5o6c3o3k] {
    background: var(--color-bg-subtle);
}

.plan-subform__title[b-4h5o6c3o3k] {
    margin-bottom: var(--space-3);
}

.plan-subform__legend[b-4h5o6c3o3k] {
    float: none;
    width: auto;
    font-size: inherit;
    font-weight: var(--font-weight-medium);
    margin-bottom: 0.25rem;
}

.plan-subform__actions[b-4h5o6c3o3k] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.plan-amount-row[b-4h5o6c3o3k] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    max-width: 20rem;
}

.plan-amount-row__unit[b-4h5o6c3o3k] {
    color: var(--color-text-muted);
    white-space: nowrap;
}

.plan-amount-row__unit-select[b-4h5o6c3o3k] {
    width: auto;
    flex: 0 0 auto;
}

.plan-date-input[b-4h5o6c3o3k] {
    max-width: 14rem;
}

/* ── Bundle price: list price, discount, payable side by side while they fit,
   stacked on a narrow form. ── */
.plan-price-grid[b-4h5o6c3o3k] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    gap: var(--space-2) var(--space-3);
    max-width: 40rem;
}

.plan-price-grid .plan-amount-row[b-4h5o6c3o3k] {
    max-width: none;
}

/* The computed amount reads as a value, not an input: same height as the boxes
   beside it, no border, emphasised. */
.plan-payable[b-4h5o6c3o3k] {
    display: inline-flex;
    align-items: center;
    min-height: calc(1.5em + 0.75rem + 2px);
    font-weight: var(--font-weight-semibold, 600);
    font-variant-numeric: tabular-nums;
}

.plan-bundle-price[b-4h5o6c3o3k] {
    display: flex;
    flex-wrap: wrap;
    gap: 0 var(--space-3);
    margin: 0.15rem 0 0;
    font-size: 0.9rem;
}

.plan-bundle-price dt[b-4h5o6c3o3k] {
    color: var(--color-text-muted);
    font-weight: normal;
}

.plan-bundle-price dt[b-4h5o6c3o3k]::after {
    content: ":";
}

.plan-bundle-price dd[b-4h5o6c3o3k] {
    margin: 0 var(--space-2) 0 0.25rem;
    font-variant-numeric: tabular-nums;
}

.plan-bundle-price dt[b-4h5o6c3o3k],
.plan-bundle-price dd[b-4h5o6c3o3k] {
    display: inline;
}

.plan-create-summary__price[b-4h5o6c3o3k] {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    text-align: end;
    font-variant-numeric: tabular-nums;
}

/* ── Options rows ── */
.plan-option__check[b-4h5o6c3o3k] {
    min-width: 0;
    flex: 1 1 14rem;
}

.plan-option__check[b-4h5o6c3o3k]  .form-check-label,
.plan-option__check .form-check-label[b-4h5o6c3o3k] {
    display: flex;
    flex-direction: column;
}

.plan-option__pricing[b-4h5o6c3o3k] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.plan-option__catalogue[b-4h5o6c3o3k] {
    color: var(--color-text-muted);
    font-size: 0.9rem;
    white-space: nowrap;
}

.plan-option__override[b-4h5o6c3o3k] {
    max-width: 13rem;
}

.plan-option__override input[b-4h5o6c3o3k],
.plan-option__override[b-4h5o6c3o3k]  input {
    max-width: 7rem;
}

/* ── Review ── */
.plan-review-section[b-4h5o6c3o3k] {
    border-top: 1px solid var(--color-border);
    padding-top: var(--space-3);
    margin-bottom: var(--space-3);
}

.plan-review-section__head[b-4h5o6c3o3k] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    margin-bottom: var(--space-2);
}

.plan-review-section__head h5[b-4h5o6c3o3k] {
    margin: 0;
}

.plan-review-dl[b-4h5o6c3o3k] {
    display: grid;
    grid-template-columns: minmax(8rem, max-content) 1fr;
    column-gap: var(--space-3);
    row-gap: 0.25rem;
    margin: 0;
}

.plan-review-dl dt[b-4h5o6c3o3k] {
    color: var(--color-text-muted);
    font-weight: var(--font-weight-medium);
}

.plan-review-dl dd[b-4h5o6c3o3k] {
    margin: 0;
    overflow-wrap: anywhere;
}

.plan-review-dl--compact[b-4h5o6c3o3k] {
    font-size: 0.9rem;
    grid-template-columns: minmax(6.5rem, max-content) 1fr;
}

.plan-readiness[b-4h5o6c3o3k] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-bg-subtle);
    padding: var(--space-2) var(--space-3);
}

.plan-readiness i[b-4h5o6c3o3k] {
    color: var(--color-success);
    font-size: 1.25rem;
}

.plan-readiness__counts[b-4h5o6c3o3k] {
    display: block;
    color: var(--color-text-muted);
}

/* ── Footer actions ── */
.plan-create-actions[b-4h5o6c3o3k] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.plan-create-actions__left[b-4h5o6c3o3k],
.plan-create-actions__right[b-4h5o6c3o3k] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.plan-create-actions[b-4h5o6c3o3k]  .btn,
.plan-create-actions .btn[b-4h5o6c3o3k] {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
}

/* ── Secondary master-data affordances ── */
.plan-secondary__form[b-4h5o6c3o3k] {
    max-width: 22rem;
}

/* ── Narrow screens ── */
@media (max-width: 991.98px) {
    .plan-create-layout[b-4h5o6c3o3k] {
        grid-template-columns: minmax(0, 1fr);
    }

    .plan-create-summary[b-4h5o6c3o3k] {
        position: static;
        order: 2;
    }
}

@media (max-width: 640.98px) {
    /* Compact numbered steps: dots stay, labels drop except the current one. */
    .plan-steps__item:not(.is-current) .plan-steps__label[b-4h5o6c3o3k] {
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        overflow: hidden;
        clip: rect(0 0 0 0);
        white-space: nowrap;
    }

    .plan-steps__item + .plan-steps__item[b-4h5o6c3o3k]::before {
        width: 0.6rem;
    }

    /* Staged rows and their actions stack into readable blocks. */
    .plan-staged-list__item[b-4h5o6c3o3k] {
        flex-direction: column;
        align-items: stretch;
    }

    .plan-staged-list__actions[b-4h5o6c3o3k] {
        justify-content: flex-start;
    }

    .plan-option__pricing[b-4h5o6c3o3k] {
        justify-content: flex-start;
    }

    /* Primary action stays prominent: full-width on phones. */
    .plan-create-actions[b-4h5o6c3o3k] {
        flex-direction: column-reverse;
        align-items: stretch;
    }

    .plan-create-actions__right[b-4h5o6c3o3k]  .btn,
    .plan-create-actions__right .btn[b-4h5o6c3o3k] {
        width: 100%;
        justify-content: center;
    }

    .plan-create-actions__left[b-4h5o6c3o3k] {
        justify-content: space-between;
    }

    .plan-amount-row[b-4h5o6c3o3k] {
        max-width: none;
    }
}
/* /Components/Pages/Portal/ServiceCatalog.razor.rz.scp.css */
/* SSP-B5 — group filter chips for the portal service catalog.

   Page-scoped on purpose: the shared portal vocabulary lives in
   PortalLayout.razor.css, but a chip row is this page's own concern and a
   sibling PR owns that file. Every colour is a --portal-* token inherited from
   .portal-shell, with NO hardcoded fallback, so the per-tenant portal theme can
   restyle the chips by re-declaring the tokens alone. */

.portal-chips[b-u29h9dmdod] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 0 0 18px;
}

.portal-chip[b-u29h9dmdod] {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 6px 14px;
    border-radius: 999px;
    border: 1px solid var(--portal-line);
    background: var(--portal-surface);
    color: var(--portal-ink-soft);
    font: inherit;
    font-size: 0.825rem;
    line-height: 1.4;
    cursor: pointer;
    transition: border-color 160ms ease, background 160ms ease, color 160ms ease;
}

.portal-chip:hover[b-u29h9dmdod] {
    color: var(--portal-ink);
    border-color: color-mix(in oklab, var(--portal-accent) 45%, transparent);
}

/* Keyboard reachability is native to <button>; make the focus ring obvious. */
.portal-chip:focus-visible[b-u29h9dmdod] {
    outline: 2px solid var(--portal-accent);
    outline-offset: 2px;
}

.portal-chip.is-active[b-u29h9dmdod] {
    color: var(--portal-accent-ink);
    border-color: var(--portal-accent);
    background: color-mix(in oklab, var(--portal-accent) 12%, transparent);
    font-weight: 600;
}

/* Still selectable (it leads to the empty state, which offers the way back) —
   just visibly not worth a click under the current search. */
.portal-chip.is-empty[b-u29h9dmdod] {
    opacity: 0.55;
}

.portal-chip-count[b-u29h9dmdod] {
    font-size: 0.72rem;
    opacity: 0.7;
    font-variant-numeric: tabular-nums;
}

@media (prefers-reduced-motion: reduce) {
    .portal-chip[b-u29h9dmdod] {
        transition: none;
    }
}
/* /Components/Pages/Tickets/TicketsPage.razor.rz.scp.css */
/* layout-50 consistency — the Tickets action toolbar.
   Every tool renders as the SAME fixed-size icon-over-label chip, so the row
   reads as a uniform grid of blocks instead of buttons of varying width. */

.ticket-tools[b-9g669myrjd] {
    display: flex;
    flex-wrap: wrap;
    gap: .375rem;
    align-items: stretch;
}

/* ── Queue header ──
   Title/description and the command area are separate blocks. On desktop they
   sit side by side exactly as the old single row did; below 900px the commands
   drop under the title instead of compressing it, and below 641px the toolbar
   itself wraps (see .app-toolbar in app.css). */
.tickets-header[b-9g669myrjd] {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}

.tickets-header__titles[b-9g669myrjd] {
    min-width: 0;
    flex: 0 1 auto;
}

.tickets-header__commands[b-9g669myrjd] {
    /* .app-toolbar sets its own margin-bottom; the header owns the spacing. */
    margin-bottom: 0;
    flex: 1 1 30rem;
    min-width: 0;
    justify-content: flex-end;
}

@media (max-width: 899.98px) {
    .tickets-header__commands[b-9g669myrjd] {
        flex-basis: 100%;
        justify-content: flex-start;
    }
}

/* The status filters' scroll lane. It is a flex item of the toolbar, so it
   needs a basis of its own — otherwise it would size to the (much wider)
   btn-group and push the row out again. Snap keeps a swipe from stranding a
   button half-clipped at the edge. */
.ticket-status-lane[b-9g669myrjd] {
    flex: 1 1 auto;
    min-width: 0;
    scroll-snap-type: x proximity;
    scroll-padding-inline: .25rem;
}

.ticket-status-lane .btn[b-9g669myrjd] {
    scroll-snap-align: start;
}

/* Between 641 and 899.98px the global .app-scroll-x styling gives the lane no
   scroll affordance at all — overflow there read as a plain clip. Extend the
   phone lane treatment (inset surface + thin scrollbar) up to the toolbar's
   own folding breakpoint so a clipped strip always LOOKS scrollable. */
@media (max-width: 899.98px) {
    .ticket-status-lane[b-9g669myrjd] {
        padding: 0.3rem;
        border: 1px solid var(--color-border);
        border-radius: var(--radius-md);
        background: var(--color-bg-subtle);
    }
}

/* ── Secondary-tool overflow ──
   `display: contents` makes the wrapper vanish from layout, so on desktop its
   chips are direct flex children of .ticket-tools and the row is the same
   layout that shipped. The phone rules below turn it into a disclosure. */
.ticket-tools__overflow[b-9g669myrjd] {
    display: contents;
}

/* Specificity is deliberate (0,3,0): the uniform-chip rule below is
   `.ticket-tools .btn { display: inline-flex }` (0,2,0) AND sits later in the
   file, so anything weaker left this phone-only button visible on desktop.
   The phone media query re-states the same selector to switch it back on. */
.ticket-tools > .btn.ticket-tools__more[b-9g669myrjd] {
    display: none;
}

.ticket-tools .btn[b-9g669myrjd] {
    flex: 0 0 5.5rem;
    width: 5.5rem;
    min-height: 3.5rem;
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .15rem;
    padding: .3rem .25rem;
    font-size: .72rem;
    line-height: 1.05;
    text-align: center;
    white-space: normal;
    overflow: hidden;
}

.ticket-tools .btn .bi[b-9g669myrjd] {
    font-size: 1.05rem;
    line-height: 1;
}

/* active-count badges sit under the label without stretching the block */
.ticket-tools .btn .badge[b-9g669myrjd] {
    margin: 0 !important;
    font-size: .6rem;
    padding: .1rem .3rem;
}

/* ── Grouped tool menus (Analytics / Tools) ──
   The trigger inherits the uniform chip sizing above; the open menu is a
   token-surfaced popover. A fixed transparent backdrop (rendered while a
   menu is open) closes it on outside click — the page is InteractiveServer,
   so plain Blazor state drives open/close. */
.tool-menu[b-9g669myrjd] {
    position: relative;
    display: inline-flex;
    /* Above the click-away backdrop (1060) so the OTHER menu's trigger stays
       one click away while a menu is open — without this, switching menus cost
       two clicks (the first only dismissed the backdrop). The open menu list
       (1061) still paints above the triggers. */
    z-index: 1062;
}

.tool-menu-list[b-9g669myrjd] {
    position: absolute;
    top: calc(100% + 4px);
    right: 0;
    min-width: 220px;
    padding: 6px;
    background: var(--color-bg-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    z-index: 1061;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.tool-menu-item[b-9g669myrjd] {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 7px 10px;
    border: 0;
    background: transparent;
    border-radius: var(--radius-md);
    color: var(--color-text);
    font-size: var(--font-size-sm);
    text-align: left;
    text-decoration: none;
    cursor: pointer;
}

.tool-menu-item:hover[b-9g669myrjd] {
    background: var(--color-bg-subtle);
    color: var(--color-text);
}

.tool-menu-item.is-active[b-9g669myrjd] {
    color: var(--color-primary-ink);
}

.tool-menu-item .bi[b-9g669myrjd] {
    font-size: .95rem;
    width: 18px;
    text-align: center;
}

.tool-menu-backdrop[b-9g669myrjd] {
    position: fixed;
    inset: 0;
    z-index: 1060;
    background: transparent;
}

/* ── Operator filter card disclosure ──
   Desktop: the header button is hidden and the body always shows — exactly the
   card that shipped. ≤899.98px the header becomes the only visible row and the
   body folds away until opened (matching the toolbar's More disclosure), so
   the ticket list starts several rows earlier on a phone. */
.ticket-advfilters__toggle[b-9g669myrjd] {
    display: none;
}

@media (max-width: 899.98px) {
    .ticket-advfilters__toggle[b-9g669myrjd] {
        display: flex;
        align-items: center;
        gap: .5rem;
        width: 100%;
        min-height: 44px;
        padding: .55rem .85rem;
        border: 0;
        background: transparent;
        color: var(--color-text);
        font-size: .85rem;
        font-weight: 600;
        text-align: start;
        cursor: pointer;
    }

    .ticket-advfilters__toggle:focus-visible[b-9g669myrjd] {
        outline: 2px solid var(--color-primary);
        outline-offset: -2px;
    }

    .ticket-advfilters__chevron[b-9g669myrjd] {
        margin-inline-start: auto;
        color: var(--color-text-muted);
    }

    .ticket-advfilters:not(.is-open) .ticket-advfilters__body[b-9g669myrjd] {
        display: none;
    }
}

/* ============================================================================
   PHONE + TABLET (<= 899.98px)
   ----------------------------------------------------------------------------
   Filters and "New ticket" stay on the bar; everything else folds behind the
   "More" disclosure so the primary action is never pushed off-screen.

   The breakpoint matches .tickets-header__commands above, where the command
   area already drops to its own full-width row. Without this the eight uniform
   5.5rem chips wrapped into a 3-row grid and the queue header cost 287px of a
   768px tablet viewport; folding the secondary six brings it to 213px.
   ============================================================================ */
@media (max-width: 899.98px) {
    .ticket-tools[b-9g669myrjd] {
        flex: 1 1 100%;
        gap: .375rem;
    }

    /* The uniform 5.5rem icon-over-label chip is a desktop density choice; on a
       phone the bar reads better — and taps better — as normal-height buttons
       that can share a row. */
    .ticket-tools > .btn[b-9g669myrjd],
    .ticket-tools__overflow > .btn[b-9g669myrjd],
    .ticket-tools__overflow > .tool-menu > .btn[b-9g669myrjd] {
        flex: 1 1 auto;
        width: auto;
        min-width: 0;
        min-height: 44px;
        flex-direction: row;
        gap: .4rem;
        padding: .35rem .7rem;
        font-size: .8rem;
    }

    .ticket-tools > .btn.ticket-tools__more[b-9g669myrjd] {
        display: inline-flex;
        flex: 0 0 auto;
    }

    .ticket-tools__primary[b-9g669myrjd] {
        /* The obvious primary action: it gets the whole remaining row width. */
        flex: 1 1 8rem;
    }

    /* Closed by default; opens as an in-flow panel under the bar. In-flow (not
       absolutely positioned) on purpose — the Analytics/Tools popovers inside
       it stay anchored to their own triggers with no stacking-context traps. */
    .ticket-tools__overflow[b-9g669myrjd] {
        display: none;
        flex: 1 1 100%;
        width: 100%;
        flex-wrap: wrap;
        gap: .375rem;
        margin-top: .25rem;
        padding: .4rem;
        border: 1px solid var(--color-border);
        border-radius: var(--radius-md);
        background: var(--color-bg-subtle);
    }

    .ticket-tools__overflow.is-open[b-9g669myrjd] {
        display: flex;
    }

    .ticket-tools__overflow > .tool-menu[b-9g669myrjd] {
        flex: 1 1 auto;
    }

    /* Anchor the popovers to the leading edge so a 220px menu opening from a
       chip near the right edge cannot spill past the viewport. */
    .tool-menu-list[b-9g669myrjd] {
        right: auto;
        inset-inline-start: 0;
        min-width: min(15rem, 78vw);
    }
}
/* /Components/Pages/Tickets/TicketViewPage.razor.rz.scp.css */
/* Two-column ticket workspace (user feedback: the stacked full-width cards
   were "too much" — work belongs in a wide main column with the ticket's
   context in a rail).
   - main column: description, threads, checklists, linked work records
   - rail: properties, SLA, requester, linked records, watchers, confidentiality
   Stacks back to one column below 1200px, where a rail would be too cramped. */

.tv-heading[b-s5ofzom2mu] {
    min-width: 0;
    max-width: 100%;
    overflow-wrap: anywhere;
}

.tv-layout[b-s5ofzom2mu] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 340px;
    gap: 1rem;
    align-items: start;
}

/* minmax(0, …) above + min-width here let wide content (tables, code, long
   attachment names) shrink the track instead of blowing out the grid.
   Both columns are flex stacks whose items come from keyed .tv-slot loops
   over the customizable layout (TicketViewLayout) — order, column and
   visibility are all real DOM placement. The gap replaces the cards' own
   mb-4/mt-3 utilities (neutralized below) so any ordering keeps even
   spacing. */
.tv-main[b-s5ofzom2mu] {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}

.tv-side[b-s5ofzom2mu] {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}

/* Each card renders inside a keyed .tv-slot wrapper (stable Blazor identity
   across reorders/column moves). display:contents makes the wrapper invisible
   to the flex/grid layout — the card itself becomes the item. */
.tv-slot[b-s5ofzom2mu] {
    display: contents;
}

/* !important because Bootstrap's mb-4/mt-3 utilities carry it; the scoped
   selector outranks them. Covers both direct children (the parent-of-#x
   banner) and the cards inside their slots — the column gap is the ONLY
   spacing, so any ordering keeps it even. */
.tv-main > *[b-s5ofzom2mu],
.tv-side > *[b-s5ofzom2mu],
.tv-slot > *[b-s5ofzom2mu] {
    margin-top: 0 !important;
    margin-bottom: 0 !important;
}

@media (max-width: 1199.98px) {
    .tv-layout[b-s5ofzom2mu] {
        grid-template-columns: minmax(0, 1fr);
    }

    /* When stacked, the context (incl. the triage Properties card) goes ABOVE
       the work column — these controls lived at the top of the page before the
       two-column split, and a tablet operator shouldn't have to scroll the
       whole thread to change status or reassign. The two-up card grid keeps
       the context block short (cards' own margins are neutralized globally
       above; per-card `order` from the customizable layout applies inside
       this grid too). */
    .tv-side[b-s5ofzom2mu] {
        order: -1;
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
        gap: 1rem;
        align-items: start;
    }
}

/* ── Layout-customize mode (order + hide) ── */

.tvc-bar[b-s5ofzom2mu] {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
    padding: .6rem .9rem;
    margin-bottom: 1rem;
    border: 1px dashed var(--color-primary);
    border-radius: var(--radius-lg);
    background: color-mix(in oklab, var(--color-primary) 8%, transparent);
}

.tvc-bar-hint[b-s5ofzom2mu] {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

/* Each customizable card gets a dashed outline + room for its floating
   handle while customizing; hidden cards stay visible but dimmed so they
   can be restored in place. */
.tvc-card[b-s5ofzom2mu] {
    position: relative;
    outline: 2px dashed var(--color-border-strong);
    outline-offset: 3px;
}

.tvc-hidden[b-s5ofzom2mu] {
    opacity: .45;
}

/* Ghost placeholder for a card whose own render gate is false on the current
   ticket (e.g. Root cause before resolution) — arrangeable in customize mode
   so the arrows never dead-click and a tenant default can position every
   card, but clearly not a real card. */
.tvc-ghost[b-s5ofzom2mu] {
    border-style: dashed;
    background: transparent;
}

.tvc-handle[b-s5ofzom2mu] {
    position: absolute;
    top: -14px;
    right: 10px;
    z-index: 5;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 6px;
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-pill);
    box-shadow: var(--shadow-lg);
}

.tvc-handle-title[b-s5ofzom2mu] {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    padding-right: 2px;
    max-width: 160px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.tvc-btn[b-s5ofzom2mu] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--color-text);
    cursor: pointer;
}

.tvc-btn:hover[b-s5ofzom2mu] {
    background: var(--color-bg-subtle);
    color: var(--color-primary-ink);
}

/* ── Properties card fields — label stacked over its control ── */
.tv-prop[b-s5ofzom2mu] {
    margin-bottom: .75rem;
}

.tv-prop:last-child[b-s5ofzom2mu] {
    margin-bottom: 0;
}

/* urgency + impact side by side; they're short selects */
.tv-prop-pair[b-s5ofzom2mu] {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: .5rem;
}

.tv-prop-pair .tv-prop[b-s5ofzom2mu] {
    margin-bottom: .75rem;
}
/* /Components/Shared/AvailabilityApprovalInbox.razor.rz.scp.css */
/* Wide enough to write a reason in: the actions cell would otherwise
   squeeze it to a sliver when the table fits its container. */
.av-inbox-reason[b-2bxcusactw] {
    min-width: 12rem;
    max-width: 260px;
}

/* A phone (the portal at 390px): each request becomes a card with labelled
   lines, so Approve and Reject are on screen instead of off to the right of
   an eight-column table. */
@media (max-width: 576px) {
    .av-inbox-table thead[b-2bxcusactw] {
        display: none;
    }

    .av-inbox-table[b-2bxcusactw],
    .av-inbox-table tbody[b-2bxcusactw],
    .av-inbox-table tr[b-2bxcusactw],
    .av-inbox-table td[b-2bxcusactw] {
        display: block;
        width: 100%;
    }

    .av-inbox-table tr[b-2bxcusactw] {
        border: 1px solid var(--color-border);
        border-radius: 8px;
        margin-bottom: 0.75rem;
        padding: 0.5rem 0.75rem;
    }

    .av-inbox-table td[b-2bxcusactw] {
        border: 0;
        padding: 0.15rem 0;
        text-align: left !important;
        white-space: normal !important;
    }

    /* No notes: no "Notes" label over nothing. */
    .av-inbox-table td:empty[b-2bxcusactw] {
        display: none;
    }

    .av-inbox-table td[data-label][b-2bxcusactw]::before {
        content: attr(data-label);
        display: block;
        font-size: 0.75rem;
        color: var(--color-text-muted);
    }

    .av-inbox-table .av-inbox-who[b-2bxcusactw] {
        font-weight: 600;
    }

    .av-inbox-table .av-inbox-actions[b-2bxcusactw] {
        padding-top: 0.5rem;
    }

    .av-inbox-reason[b-2bxcusactw] {
        max-width: none;
    }
}
/* /Components/Shared/AvailabilityPlanner.razor.rz.scp.css */
.av-toolbar[b-rurmbzamzw],
.av-filters[b-rurmbzamzw] {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
    margin-bottom: 0.75rem;
}

.av-toolbar .av-scope[b-rurmbzamzw] {
    max-width: 280px;
}

.av-filters .form-select[b-rurmbzamzw],
.av-filters .av-search[b-rurmbzamzw] {
    max-width: 200px;
}

.av-inline[b-rurmbzamzw] {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    margin: 0;
}

.av-range[b-rurmbzamzw] {
    min-width: 9rem;
    text-align: center;
}

.av-grid[b-rurmbzamzw] {
    border-collapse: collapse;
    font-size: 0.85rem;
}

.av-grid th[b-rurmbzamzw],
.av-grid td[b-rurmbzamzw] {
    border: 1px solid var(--color-border);
    padding: 2px;
}

.av-grid .av-person[b-rurmbzamzw] {
    min-width: 180px;
    padding: 6px 8px;
    text-align: left;
    font-weight: 500;
    background: var(--color-bg-card);
    position: sticky;
    left: 0;
    z-index: 1;
}

.av-grid .av-day[b-rurmbzamzw] {
    width: 30px;
    text-align: center;
    padding: 4px 2px;
}

.av-grid .av-dayname[b-rurmbzamzw] {
    font-size: 0.7rem;
    color: var(--color-text-muted);
    text-transform: uppercase;
}

.av-grid .av-daynum[b-rurmbzamzw] {
    font-weight: 600;
}

/* A tint of the text colour: darker in the light themes, lighter in the dark ones. */
.av-grid .weekend[b-rurmbzamzw] {
    background: color-mix(in srgb, var(--color-text) 7%, transparent);
}

/* P8b: a person's own days off, by their location's calendar. A weekday it doesn't work
   takes the weekend's tint; a public holiday a hatch of the success colour — both
   theme-relative, so they read in the light, dark and operator themes alike. Scoped to
   the cell: the PublicHoliday chip's own class is "holiday". */
.av-grid td.av-cell.av-nonworking[b-rurmbzamzw],
.av-legend .av-swatch.av-nonworking[b-rurmbzamzw] {
    background: color-mix(in srgb, var(--color-text) 7%, transparent);
}

.av-grid td.av-cell.av-holiday[b-rurmbzamzw],
.av-legend .av-swatch.av-holiday[b-rurmbzamzw] {
    background: repeating-linear-gradient(135deg,
        color-mix(in srgb, var(--color-success) 22%, transparent) 0 4px,
        transparent 4px 8px);
}

.av-legend .av-swatch[b-rurmbzamzw] {
    display: inline-block;
    width: 14px;
    height: 10px;
    border-radius: 2px;
    vertical-align: middle;
    outline: 1px solid color-mix(in srgb, var(--color-text) 15%, transparent);
}
.av-grid .today[b-rurmbzamzw] {
    box-shadow: inset 0 0 0 2px var(--color-warning, #f59e0b);
}

.av-grid .av-cell[b-rurmbzamzw] {
    width: 30px;
    height: 28px;
    vertical-align: middle;
}

.av-grid .av-cov[b-rurmbzamzw] {
    text-align: center;
    font-weight: 600;
    font-size: 0.75rem;
}

.av-grid .av-cov.short[b-rurmbzamzw] {
    color: var(--color-danger, #dc2626);
}

.av-chip[b-rurmbzamzw] {
    display: block;
    min-height: 8px;
    height: 100%;
    border-radius: 3px;
    margin: 1px 0;
}

.av-cell .av-chip + .av-chip[b-rurmbzamzw] {
    min-height: 6px;
}

.av-chip.morning[b-rurmbzamzw] {
    width: 50%;
}

.av-chip.afternoon[b-rurmbzamzw] {
    width: 50%;
    margin-left: 50%;
}

.av-chip.pending[b-rurmbzamzw] {
    opacity: 0.55;
    outline: 1px dashed currentColor;
    outline-offset: -1px;
}

/* A fixed blue: the operator theme's primary is a pink too close to its danger red. */
.av-chip.vacation[b-rurmbzamzw] { background: #2563eb; }
.av-chip.sick[b-rurmbzamzw] { background: var(--color-danger); }
.av-chip.personal[b-rurmbzamzw] { background: #7c3aed; }
.av-chip.parental[b-rurmbzamzw] { background: #db2777; }
.av-chip.bereavement[b-rurmbzamzw] { background: #475569; }
.av-chip.holiday[b-rurmbzamzw] { background: var(--color-success); }
.av-chip.wfh[b-rurmbzamzw],
.av-chip.remote[b-rurmbzamzw] { background: #0891b2; }
.av-chip.onsite[b-rurmbzamzw],
.av-chip.inoffice[b-rurmbzamzw] { background: #6b7280; }
.av-chip.training[b-rurmbzamzw] { background: #ea580c; }
.av-chip.other[b-rurmbzamzw] { background: #334155; }
.av-chip.away[b-rurmbzamzw] { background: #64748b; }

.av-legend[b-rurmbzamzw] {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    margin-top: 0.75rem;
}

.av-legend > span[b-rurmbzamzw] {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
}

.av-legend .av-chip[b-rurmbzamzw] {
    display: inline-block;
    width: 16px;
    height: 12px;
    min-height: 12px;
    margin: 0;
}

.av-legend .av-chip.pending[b-rurmbzamzw] {
    background: transparent;
}
/* /Components/Shared/Avatar.razor.rz.scp.css */
.avatar[b-apr0fhef50] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    flex-shrink: 0;
    font-weight: 700;
    color: var(--color-text-on-primary);
    line-height: 1;
}
/* /Components/Shared/CommandPalette.razor.rz.scp.css */
/* Entrance animation, ported from the Operator Console design mock's own
   command-palette treatment: a fast backdrop fade, then a slightly slower
   panel fade + gentle scale-in. */
.palette-backdrop[b-b69xol80ut] {
    animation: palette-backdrop-in-b-b69xol80ut 0.18s ease both;
}
@keyframes palette-backdrop-in-b-b69xol80ut {
    from { opacity: 0; }
    to   { opacity: 1; }
}

.palette-panel[b-b69xol80ut] {
    animation: palette-panel-in-b-b69xol80ut 0.24s cubic-bezier(0.22, 1, 0.36, 1) both;
}
@keyframes palette-panel-in-b-b69xol80ut {
    from { opacity: 0; transform: translateY(8px) scale(0.98); }
    to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
    .palette-backdrop[b-b69xol80ut], .palette-panel[b-b69xol80ut] { animation: none; }
}
/* /Components/Shared/CountryFlag.razor.rz.scp.css */
/* A flag the size of a capital letter, sitting on the text's middle line. The
   outline is a THEME token (defined for light, dark and operator), never a hex:
   it is what keeps a white field (Japan, the Dutch white stripe) visible on a
   white card and a black one (the Belgian stripe) visible on a dark one. */
.country-flag[b-7sw0rcr8tv] {
    display: inline-block;
    flex: none;
    width: 1.25em;
    height: 0.9em;
    vertical-align: middle;
    line-height: 0;
    overflow: hidden;
    border: 1px solid var(--color-border-strong);
}

/* The vendored 4x3 drawing fills the box; the few tenths of a percent the box is
   wider than 4:3 are cropped, never letterboxed. */
.country-flag img[b-7sw0rcr8tv] {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}
/* /Components/Shared/DateInput.razor.rz.scp.css */
.date-input[b-gln3krespu] {
    position: relative;
}

/* The native date input exists only to host the browser's own calendar. It stays
   rendered rather than display:none, because showPicker() anchors the popup to
   the element's box: shrunk to a point at the field's bottom-left corner, the
   popup opens under the field. Invisible and out of pointer hit-testing; tab
   order and the accessibility tree are handled in the markup (tabindex="-1",
   aria-hidden). */
.date-input__native[b-gln3krespu] {
    position: absolute;
    left: 0;
    bottom: 0;
    width: 1px;
    height: 1px;
    margin: 0;
    padding: 0;
    border: 0;
    opacity: 0;
    pointer-events: none;
}
/* /Components/Shared/DecimalInput.razor.rz.scp.css */
/* The wrapper stands in for the text box in a flex row (an amount followed by its
   unit): it takes the space the box would have, and may shrink below the box's
   intrinsic width on a narrow screen instead of overflowing the row. */
.decimal-input[b-bpsrxdl6o0] {
    flex: 1 1 auto;
    min-width: 0;
}
/* /Components/Shared/FormBuilder.razor.rz.scp.css */
/* WF-200 B2 — form-mode builder: palette | live preview | inspector. */

.wfb-shell[b-1hognj5ife] {
    display: grid;
    grid-template-columns: 200px 1fr 260px;
    gap: 10px;
    align-items: start;
}

.wfb-palette[b-1hognj5ife],
.wfb-inspector[b-1hognj5ife] {
    border: 1px solid var(--color-border, #e5e7eb);
    border-radius: var(--radius-md, .5rem);
    background: var(--color-bg-card, #fff);
    padding: 8px;
    position: sticky;
    top: 8px;
    max-height: calc(100vh - 7rem);
    overflow-y: auto;
}

.wfb-palette-title[b-1hognj5ife],
.wfb-inspector-title[b-1hognj5ife] {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--color-text-muted, #6b7280);
    margin-bottom: 6px;
}

.wfb-inspector-title[b-1hognj5ife] {
    font-size: 13px;
    text-transform: none;
    letter-spacing: 0;
    color: var(--color-text, #111827);
}

.wfb-palette-group[b-1hognj5ife] {
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    color: var(--color-text-muted, #9ca3af);
    margin: 8px 0 4px;
}

.wfb-palette-item[b-1hognj5ife] {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    text-align: left;
    padding: 6px 8px;
    margin-bottom: 2px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm, .375rem);
    background: transparent;
    color: var(--color-text, #111827);
    font-size: 13px;
    cursor: pointer;
    transition: background-color .12s ease, border-color .12s ease;
}

.wfb-palette-item:hover[b-1hognj5ife] {
    background: var(--color-bg-subtle, #f3f4f6);
    border-color: var(--color-primary, var(--color-primary));
}

.wfb-palette-note[b-1hognj5ife] {
    font-size: 11px;
    color: var(--color-text-muted, #9ca3af);
    margin-top: 10px;
    padding: 6px 8px;
    border-top: 1px solid var(--color-border, #e5e7eb);
}

.wfb-canvas[b-1hognj5ife] {
    min-width: 0;
    border: 1px solid var(--color-border, #e5e7eb);
    border-radius: var(--radius-md, .5rem);
    background: var(--color-bg, #f9fafb);
    padding: 12px;
    min-height: 24rem;
    position: relative; /* offset parent for the drag drop-indicator */
}

.wfb-empty[b-1hognj5ife] {
    text-align: center;
    color: var(--color-text-muted, #9ca3af);
    padding: 4rem 1rem;
}

.wfb-empty .bi[b-1hognj5ife] {
    font-size: 2rem;
    display: block;
    margin-bottom: .5rem;
    opacity: .6;
}

.wfb-control[b-1hognj5ife] {
    border: 1px solid var(--color-border, #e5e7eb);
    border-radius: var(--radius-sm, .375rem);
    background: var(--color-bg-card, #fff);
    padding: 8px 10px;
    margin-bottom: 8px;
    cursor: pointer;
}

.wfb-control.selected[b-1hognj5ife] {
    border-color: var(--color-primary, var(--color-primary));
    box-shadow: 0 0 0 1px var(--color-primary, var(--color-primary));
}

.wfb-control-bar[b-1hognj5ife] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 4px;
}

.wfb-control-type[b-1hognj5ife] {
    font-size: 11px;
    color: var(--color-text-muted, #6b7280);
    display: inline-flex;
    align-items: center;
    gap: 5px;
}

.wfb-control-tools button[b-1hognj5ife] {
    border: none;
    background: transparent;
    color: var(--color-text-muted, #6b7280);
    cursor: pointer;
    padding: 2px 4px;
    font-size: 13px;
    border-radius: var(--radius-sm, .375rem);
}

.wfb-control-tools button:hover:not(:disabled)[b-1hognj5ife] {
    background: var(--color-bg-subtle, #f3f4f6);
    color: var(--color-text, #111827);
}

.wfb-control-tools button:disabled[b-1hognj5ife] {
    opacity: .35;
    cursor: default;
}

/* ── drag-drop reorder (workflow-formbuilder.js) ─────────────────────────── */

.wfb-drag-handle[b-1hognj5ife] {
    cursor: grab;
    color: var(--color-text-muted, #9ca3af);
    padding: 2px 2px 2px 0;
    touch-action: none; /* pointer events own the gesture on touch screens */
}

.wfb-drag-handle:active[b-1hognj5ife] {
    cursor: grabbing;
}

.wfb-control.wfb-drag-source[b-1hognj5ife] {
    opacity: .45;
}

.wfb-reordering[b-1hognj5ife],
.wfb-reordering .wfb-control[b-1hognj5ife] {
    cursor: grabbing;
    user-select: none;
}

.wfb-drop-indicator[b-1hognj5ife] {
    display: none;
    position: absolute;
    left: 12px;
    right: 12px;
    height: 2px;
    border-radius: 1px;
    background: var(--color-primary, #4f46e5);
    pointer-events: none;
    z-index: 2;
}

.wfb-drop-indicator.wfb-drop-indicator-visible[b-1hognj5ife] {
    display: block;
}

.wfb-label[b-1hognj5ife] {
    display: block;
    font-size: 11px;
    font-weight: 600;
    color: var(--color-text-muted, #6b7280);
    margin: 8px 0 2px;
}

/* ── Table control — Columns[] inspector ─────────────────────────────────── */

.wfb-column[b-1hognj5ife] {
    border: 1px solid var(--color-border, #e5e7eb);
    border-radius: var(--radius-sm, .375rem);
    background: var(--color-bg-card, #fff);
    padding: 6px 8px;
    margin-bottom: 6px;
}

.wfb-column-head[b-1hognj5ife] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 4px;
}

.wfb-column-index[b-1hognj5ife] {
    font-size: 10px;
    font-weight: 600;
    color: var(--color-text-muted, #6b7280);
}

.wfb-column-remove[b-1hognj5ife] {
    border: none;
    background: transparent;
    color: var(--color-text-muted, #6b7280);
    cursor: pointer;
    padding: 2px 4px;
    font-size: 12px;
    border-radius: var(--radius-sm, .375rem);
}

.wfb-column-remove:hover[b-1hognj5ife] {
    background: var(--color-bg-subtle, #f3f4f6);
    color: var(--color-danger, #dc2626);
}

/* ── Sections ─────────────────────────────────────────────────────────────
   A section renders on the canvas as a header card followed by its control
   cards — the same shape the runtime renderer uses, so what the author drags
   is what the requester sees. */

.wfb-section-add[b-1hognj5ife] {
    gap: 6px;
    display: flex;
    justify-content: flex-end;
    margin-bottom: 8px;
}

.wfb-section[b-1hognj5ife] {
    border: 1px dashed var(--color-border, #e5e7eb);
    border-radius: var(--radius-sm, .375rem);
    background: var(--color-bg-subtle, #f3f4f6);
    padding: 6px 10px;
    margin: 12px 0 8px;
    cursor: pointer;
}

.wfb-section.selected[b-1hognj5ife] {
    border-style: solid;
    border-color: var(--color-primary, var(--color-primary));
    box-shadow: 0 0 0 1px var(--color-primary, var(--color-primary));
}

.wfb-section-bar[b-1hognj5ife] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

.wfb-section-name[b-1hognj5ife] {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    font-weight: 600;
    color: var(--color-text, #111827);
    min-width: 0;
}

.wfb-section-flag[b-1hognj5ife] {
    font-size: 10px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: .04em;
    padding: 1px 6px;
    border-radius: 999px;
    background: var(--color-bg-card, #fff);
    color: var(--color-text-muted, #6b7280);
    border: 1px solid var(--color-border, #e5e7eb);
}

.wfb-section-empty[b-1hognj5ife] {
    margin-top: 4px;
    font-size: 11px;
    color: var(--color-text-muted, #6b7280);
}

.wfb-hint[b-1hognj5ife] {
    margin-top: 6px;
    font-size: 11px;
    color: var(--color-text-muted, #6b7280);
}

/* ── Value rules ──────────────────────────────────────────────────────────
   "If these answers are X, set that field to Y." Each rule is a condition
   editor plus a list of assignments; the assignment row reads left-to-right
   as a sentence: [field] [source] [value] [lock or not]. */

.wfb-rule[b-1hognj5ife] {
    border: 1px solid var(--color-border, #e5e7eb);
    border-radius: var(--radius-sm, .375rem);
    background: var(--color-bg-card, #fff);
    padding: 8px;
    margin-top: 8px;
}

.wfb-rule-bar[b-1hognj5ife] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 4px;
}

.wfb-rule-title[b-1hognj5ife],
.wfb-rule-then[b-1hognj5ife] {
    font-size: 11px;
    font-weight: 600;
    color: var(--color-text-muted, #6b7280);
    text-transform: uppercase;
    letter-spacing: .04em;
}

.wfb-rule-then[b-1hognj5ife] {
    margin: 8px 0 4px;
}

.wfb-rule-set[b-1hognj5ife] {
    display: grid;
    grid-template-columns: 1fr 1fr auto;
    gap: 4px;
    align-items: center;
    margin-bottom: 4px;
}

/* The value editor and the mode picker wrap onto their own row so none of the
   four controls is squeezed to unreadability in the 260px inspector. */
.wfb-rule-set > :nth-child(3)[b-1hognj5ife],
.wfb-rule-set > :nth-child(4)[b-1hognj5ife] {
    grid-column: span 1;
}

.wfb-rule-del[b-1hognj5ife] {
    border: none;
    background: transparent;
    color: var(--color-text-muted, #6b7280);
    cursor: pointer;
    padding: 2px 4px;
    font-size: 12px;
    border-radius: var(--radius-sm, .375rem);
}

.wfb-rule-del:hover[b-1hognj5ife] {
    background: var(--color-bg-subtle, #f3f4f6);
    color: var(--color-text, #111827);
}
/* /Components/Shared/FormRenderer.razor.rz.scp.css */
/*
    Section headers + the step wizard for the authored form renderer.

    Sections render as a HEADER followed by their controls (not as a wrapping
    container — see the comment on the render loop), so the visual grouping is
    carried by the header's top rule plus its spacing rather than by a box.
    Only design tokens here: this component renders under all three themes.
*/

.wff-section-head[b-vnaukooryn] {
    margin: 14px 0 8px;
    padding-top: 10px;
    border-top: 1px solid var(--color-border);
}

/* The first section on a form has nothing above it to separate from. */
.wff-section-head:first-child[b-vnaukooryn] {
    margin-top: 0;
    padding-top: 0;
    border-top: 0;
}

.wff-section-title[b-vnaukooryn] {
    font-size: 13px;
    font-weight: 600;
    color: var(--color-text);
}

.wff-section-desc[b-vnaukooryn] {
    margin-top: 2px;
    font-size: 11px;
    color: var(--color-text-muted);
}

/* The collapse toggle is a button for keyboard + screen-reader reach, but reads
   as the heading it replaces. */
.wff-section-toggle[b-vnaukooryn] {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    text-align: left;
    cursor: pointer;
}

.wff-section-toggle:hover .wff-section-title[b-vnaukooryn] {
    text-decoration: underline;
}

.wff-section-toggle:focus-visible[b-vnaukooryn] {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

.wff-section-toggle .bi[b-vnaukooryn] {
    font-size: 11px;
    color: var(--color-text-muted);
}

.wff-steps[b-vnaukooryn] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    flex-wrap: wrap;
    margin-top: 14px;
    padding-top: 10px;
    border-top: 1px solid var(--color-border);
}

.wff-steps-progress[b-vnaukooryn] {
    font-size: 11px;
    color: var(--color-text-muted);
}

.wff-steps-nav[b-vnaukooryn] {
    display: inline-flex;
    gap: 6px;
}
/* /Components/Shared/GuideFeedbackWidget.razor.rz.scp.css */
/* Product guide Pack 3 — "Was this page helpful?" at the end of a guide page
   (GuideFeedbackWidget.razor). A rule above it like "More in this category"
   below (ProductGuidePageView.razor.css), same tokens; no background of its
   own. */

.guide-feedback[b-kd3px12a12] {
    margin-block: var(--space-4);
    padding-block-start: var(--space-3);
    border-block-start: 1px solid var(--portal-line, var(--color-border));
}

.guide-feedback-recipient[b-kd3px12a12] {
    color: var(--portal-ink-soft, var(--color-text-muted));
}

@media print {
    .guide-feedback[b-kd3px12a12] {
        display: none;
    }
}
/* /Components/Shared/GuideNoteCallout.razor.rz.scp.css */
/* Product guide Pack 3 — the organization's note above a guide page
   (GuideNoteCallout.razor), in the portal and operator shells alike. No
   background of its own, so the text keeps the surface it sits on and the
   contrast the body has in every theme; the guide line is the muted ink pair
   KbTableOfContents.razor.css uses (portal token, app token fallback).
   Logical properties (dir="rtl"). */

.guide-note[b-e4hsu2h49y] {
    padding-block: var(--space-2);
    padding-inline-start: var(--space-3);
    border-inline-start: 4px solid var(--portal-ink-soft, var(--color-text-muted));
}

.guide-note-head[b-e4hsu2h49y] {
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-semibold);
}

.guide-note-body[b-e4hsu2h49y]  .markdown-body > :last-child {
    margin-block-end: 0;
}

.guide-note-preview[b-e4hsu2h49y] {
    padding: var(--space-2) var(--space-3);
    border: 1px dashed var(--portal-line-strong, var(--color-border-strong));
    border-radius: var(--radius-md, 6px);
}

@media print {
    .guide-note-editor[b-e4hsu2h49y],
    .guide-note button[b-e4hsu2h49y] {
        display: none;
    }
}
/* /Components/Shared/KbPrintBrand.razor.rz.scp.css */
/* KB theme (Pack T) — the print header. Hidden on screen; on paper a logo and
   the organisation's name above the article, separated by a rule. Literal
   paper colours: #000000 text and a #6b6b6b rule on white (21:1 and 5.33:1). */
.kb-print-brand[b-7zq93zm2nn] {
    display: none;
}

@media print {
    .kb-print-brand[b-7zq93zm2nn] {
        display: flex;
        align-items: center;
        gap: 12px;
        margin: 0 0 16px;
        padding-bottom: 8px;
        border-bottom: 1px solid #6b6b6b;
        color: #000000;
        font-weight: 600;
        break-after: avoid;
    }

    .kb-print-brand-logo[b-7zq93zm2nn] {
        max-height: 40px;
        max-width: 200px;
        width: auto;
        height: auto;
    }
}
/* /Components/Shared/KbTableOfContents.razor.rz.scp.css */
/* KB Markdown plan P2 — the table of contents' own rules (until P2 the .kb-toc*
   classes had none, and the indent was an inline physical padding-left).
   Logical properties throughout: the app emits dir="rtl" for Arabic and
   Hebrew, and a sub-section indents from the side the text starts on.

   The guide line is the muted ink of whichever shell the TOC is in — the
   portal palette inside .portal-shell, the app tokens elsewhere — the same
   boundary colour MarkdownView.razor.css uses, computed in
   KbMarkdownThemeContrastTests (>= 4.76:1 against the surface in every theme
   and shell). Links keep
   the app's own link colour. */
.kb-toc[b-zsydylumxx] {
    padding-inline-start: var(--space-3);
    border-inline-start: 2px solid var(--portal-ink-soft, var(--color-text-muted));
    font-size: var(--font-size-sm);
}

.kb-toc-title[b-zsydylumxx] {
    margin: 0 0 var(--space-2);
    font-weight: var(--font-weight-semibold);
}

.kb-toc-list[b-zsydylumxx] {
    margin: 0;
    padding: 0;
    list-style: none;
}

.kb-toc-item[b-zsydylumxx] {
    margin-block: var(--space-1);
}

/* ## is the top level; each deeper heading indents one step. */
.kb-toc-level-3[b-zsydylumxx] { padding-inline-start: var(--space-4); }
.kb-toc-level-4[b-zsydylumxx] { padding-inline-start: calc(var(--space-4) * 2); }
.kb-toc-level-5[b-zsydylumxx] { padding-inline-start: calc(var(--space-4) * 3); }
.kb-toc-level-6[b-zsydylumxx] { padding-inline-start: calc(var(--space-4) * 4); }

.kb-toc-link[b-zsydylumxx] {
    text-decoration: none;
}

.kb-toc-link:hover[b-zsydylumxx],
.kb-toc-link:focus-visible[b-zsydylumxx] {
    text-decoration: underline;
}

/* Paper is white whatever the theme: literal colours, as in every print block. */
@media print {
    .kb-toc[b-zsydylumxx] {
        border-inline-start-color: #6b6b6b;
    }

    .kb-toc-link[b-zsydylumxx] {
        color: #000000;
    }
}
/* /Components/Shared/KbVersionDiff.razor.rz.scp.css */
/* KB version diff (moved here from KnowledgeBaseView's inline <style>).

   The diff used to hard-code #e6ffed / #ffeef0 with no `color`, so in dark mode
   it painted near-white text on a pale-green wash — unreadable. Every surface
   below is a token wash paired with --color-text, never with its own hue token
   (the hue tokens fail on their own washes in at least one theme), and the
   left accent survives a forced-colours mode where background-color is
   overridden. */

.kb-diff-lines[b-ba8w4bh09h] {
    font-family: var(--font-family-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
    font-size: .8rem;
    max-height: 360px;
    overflow: auto;
}

.kb-diff-line[b-ba8w4bh09h] {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    color: var(--color-text);
    border-left: 3px solid transparent;
    padding-left: .35rem;
}

.kb-diff-line.kb-diff-add[b-ba8w4bh09h] {
    background: var(--color-success-bg);
    border-left-color: var(--color-success);
}

.kb-diff-line.kb-diff-del[b-ba8w4bh09h] {
    background: var(--color-danger-bg);
    border-left-color: var(--color-danger);
}

/* KB Markdown plan P7 — the changed words inside a changed line. A STRONGER
   wash of the row's own state (the -bg-strong tokens, computed at >= 4.5:1
   against --color-text in light, dark and operator), plus a non-colour cue:
   struck through when removed, underlined when added, so the mark survives
   colour-blindness and forced colours. The spans are built in code, so they
   carry no scope attribute: ::deep from the row, which does. */
.kb-diff-line[b-ba8w4bh09h]  .kb-diff-word {
    color: var(--color-text);
    border-radius: 2px;
}

.kb-diff-line[b-ba8w4bh09h]  .kb-diff-word-del {
    background: var(--color-danger-bg-strong);
    text-decoration: line-through;
}

.kb-diff-line[b-ba8w4bh09h]  .kb-diff-word-add {
    background: var(--color-success-bg-strong);
    text-decoration: underline;
}
/* /Components/Shared/MarkdownEditor.razor.rz.scp.css */
/* The textarea and the preview — moved here from an inline <style> (the
   anti-pattern layout-50 retires) in KB Markdown plan P4. */
.markdown-textarea[b-sm75i1xnj8] {
    font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
    font-size: 0.875rem;
    line-height: 1.45;
}

.markdown-preview[b-sm75i1xnj8] {
    min-height: 12rem;
    background-color: var(--color-bg-card);
}

/* Rendered Markdown arrives as a MarkupString, without the scope attribute,
   so a player is reached through ::deep from the preview, which has it. */
.markdown-preview[b-sm75i1xnj8]  .kb-video-embed iframe,
.markdown-preview[b-sm75i1xnj8]  .kb-video-embed video {
    width: 100%;
    border: 0;
}

/* P4 — small screens and touch. iOS Safari zooms into a field under 16px on
   focus and does not zoom back out, so the textarea and the editor's own
   fields are at least 16px there. */
@media (max-width: 767.98px), (pointer: coarse) {
    .markdown-textarea[b-sm75i1xnj8],
    .markdown-editor input.form-control[b-sm75i1xnj8] {
        font-size: max(16px, 1rem);
    }
}

/* P4 — Split stacks below 768px (col-md-6); the preview then gets a bounded
   height and its own scrollbar, so the text box above it stays in reach
   instead of sitting on top of an article-length preview. */
@media (max-width: 767.98px) {
    .markdown-split .markdown-preview[b-sm75i1xnj8] {
        max-height: 50vh;
        overflow: auto;
    }
}

/* KB Markdown plan, Pack A — the editor's image chrome. Tokens only: every
   colour below re-points per theme in app.css, and each pairing was measured in
   light, dark AND operator (the PR carries the table). --color-primary is NOT
   used for the drop highlight or the focus ring: on the dark theme's card it
   measures 2.83:1, under the 3:1 a UI boundary needs; --color-info is
   ≥ 4.61:1 against both the card and the page canvas in all three themes. */

/* The textarea's wrapper; markdown-editor.js adds .is-drop-target while files
   are dragged over it. */
.markdown-input[b-sm75i1xnj8] {
    border-radius: var(--radius-md);
}

.markdown-input.is-drop-target[b-sm75i1xnj8] {
    outline: 2px dashed var(--color-info);
    outline-offset: 2px;
}

.kb-image-rows[b-sm75i1xnj8] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

/* Each staged image is its own bordered row; --color-text-muted is the lightest
   token that clears 3:1 against the card in every theme (4.76 / 5.71 / 7.12). */
.kb-image-row[b-sm75i1xnj8] {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-2);
    border: 1px solid var(--color-text-muted);
    border-radius: var(--radius-md);
}

.kb-image-thumb[b-sm75i1xnj8] {
    flex: none;
    width: 4rem;
    height: 4rem;
    object-fit: contain;
    border-radius: var(--radius-sm);
    /* A transparent diagram drawn in black would vanish on the dark themes. */
    background-color: var(--color-media-backdrop);
}

.kb-image-thumb-none[b-sm75i1xnj8] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--color-text-muted);
    background-color: transparent;
    font-size: var(--font-size-xl);
}

.kb-image-fields[b-sm75i1xnj8] {
    flex: 1 1 auto;
    min-width: 0;
}

.kb-image-name[b-sm75i1xnj8] {
    color: var(--color-text);
    font-weight: var(--font-weight-medium);
    overflow-wrap: anywhere;
}

.kb-image-note[b-sm75i1xnj8] {
    color: var(--color-text-muted);
    font-weight: var(--font-weight-normal);
}

.kb-image-alt:focus-visible[b-sm75i1xnj8],
.kb-image-remove:focus-visible[b-sm75i1xnj8] {
    outline: 2px solid var(--color-info);
    outline-offset: 1px;
}

.kb-image-remove[b-sm75i1xnj8] {
    flex: none;
}

/* KB Markdown plan P4 — the formatting toolbar, its count and the link
   prompt. Tokens only, measured in light, dark and operator (the PR carries
   the table): icons are --color-text (≥ 11.9:1 on the card and the canvas in
   every theme), the hover wash pairs --color-bg-subtle with that same ink, and
   the focus ring is --color-info, Pack A's ring above. A tool has no border:
   its icon is the control's whole visual identity, and it clears 3:1 alone. */
.md-toolbar-row[b-sm75i1xnj8] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

.md-toolbar[b-sm75i1xnj8] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
}

.md-tool[b-sm75i1xnj8] {
    min-width: 2rem;
    color: var(--color-text);
    background-color: transparent;
    border-color: transparent;
}

.md-tool:hover:not(:disabled)[b-sm75i1xnj8] {
    color: var(--color-text);
    background-color: var(--color-bg-subtle);
    border-color: transparent;
}

.md-tool:focus-visible[b-sm75i1xnj8],
.md-link-prompt input:focus-visible[b-sm75i1xnj8] {
    outline: 2px solid var(--color-info);
    outline-offset: 1px;
    box-shadow: none;
}

.md-group-start[b-sm75i1xnj8] {
    margin-inline-start: var(--space-2);
}

/* --color-text, not --color-text-muted: the editor may sit on the page
   canvas, where muted measures 4.24:1 in light — under 4.5. */
.md-count[b-sm75i1xnj8] {
    margin-inline-start: auto;
    color: var(--color-text);
}

/* On the card colour, so its error text (--color-danger, 4.31:1 on the light
   canvas) is measured against the card (4.83:1). */
.md-link-prompt[b-sm75i1xnj8] {
    background-color: var(--color-bg-card);
    padding: var(--space-2);
    border: 1px solid var(--color-text-muted);
    border-radius: var(--radius-md);
}

.md-error[b-sm75i1xnj8] {
    color: var(--color-danger);
}

/* Over the limit (only an insert can get there): the words stay
   --color-text; the warning icon is --color-danger, which as a graphic needs
   3:1 and has ≥ 4.3:1 on the card and the canvas in every theme. */
.md-count-over[b-sm75i1xnj8] {
    font-weight: var(--font-weight-medium);
}

.md-count-warn[b-sm75i1xnj8] {
    color: var(--color-danger);
}
/* /Components/Shared/MarkdownEditorHelp.razor.rz.scp.css */
/* KB Markdown plan P4 — the Markdown help panel. Tokens only, measured in
   light, dark and operator (the PR carries the table): text is --color-text
   on the card; the syntax samples are --color-text on --color-bg-subtle
   (Bootstrap's pink <code> is not themed and fails on the dark cards); the
   panel's edge is --color-text-muted, ≥ 3:1 on the card in every theme. */
.md-help[b-gy7c81zyyy] {
    padding: var(--space-2) var(--space-3);
    color: var(--color-text);
    background-color: var(--color-bg-card);
    border: 1px solid var(--color-text-muted);
    border-radius: var(--radius-md);
}

.md-help-table[b-gy7c81zyyy] {
    --bs-table-bg: transparent;
    --bs-table-color: var(--color-text);
    color: var(--color-text);
}

.md-help-syntax[b-gy7c81zyyy] {
    white-space: nowrap;
}

.md-help-syntax code[b-gy7c81zyyy] {
    color: var(--color-text);
    background-color: var(--color-bg-subtle);
    padding: 0 var(--space-1);
    border-radius: var(--radius-sm);
}

/* Narrow screens: the samples may wrap rather than push the panel wide. */
@media (max-width: 575.98px) {
    .md-help-syntax[b-gy7c81zyyy] {
        white-space: normal;
    }
}

/* The style-guide link: --color-info, not the global link colour —
   --color-primary measures 2.83:1 on the dark card. Two classes deep so the
   global a:hover (0,1,1) cannot take the colour back on hover. */
.md-help .md-help-styleguide[b-gy7c81zyyy],
.md-help .md-help-styleguide:hover[b-gy7c81zyyy] {
    color: var(--color-info);
    text-decoration: underline;
}
/* /Components/Shared/MarkdownView.razor.rz.scp.css */
/* Rendered Markdown arrives as a MarkupString, so CSS isolation's scope
   attribute is never stamped on its elements — only on the .markdown-body
   element this component emits itself. Every rule here therefore starts from
   .markdown-body and reaches in with ::deep (KB Markdown plan §4). Tokens only. */

/* ── KB Markdown plan P2 — make rendered Markdown look like Markdown ───────────
   Colour comes from the local properties below and nowhere else. Outside the
   portal they are the app's tokens. Inside the portal shell they are the
   portal's own palette, which the TENANT's preset drives independently of the
   user's app theme: a dark-preset portal under the light app theme would
   otherwise get light code blocks on a dark page, and app.css's h2 colour
   (--color-text) on the dark portal surface measures 1.16:1.

   The pairing rule: a filled surface is a NEUTRAL wash with the ink of the
   same palette — never a hue token on its own wash, which is re-pointed per
   theme separately and does not move with it. Every line that marks a
   boundary uses the muted ink, the lightest role that clears 3:1 against every
   surface it can meet. Hue appears only as an alert's accent bar. The PR
   carries the computed table: three themes, both contrast modes, both shells.

   Print re-points the same properties to literal paper colours (the end of
   this file); nothing below needs a print variant of its own. */
.markdown-body[b-acuhtxscbg] {
    --md-ink: var(--portal-ink, var(--color-text));
    --md-line: var(--portal-ink-soft, var(--color-text-muted));
    --md-fill: var(--portal-subtle, var(--color-bg-subtle));
    --md-head-fill: var(--portal-subtle, var(--color-table-header));
    /* GitHub alert accents. There is no purple role for IMPORTANT, and
       --color-primary measures 2.83:1 on the dark card, so it takes the ink. */
    --md-note: var(--color-info);
    --md-tip: var(--color-success);
    --md-important: var(--md-ink);
    --md-warning: var(--color-warning);
    --md-caution: var(--color-danger);

    overflow-wrap: break-word;
}

/* One .markdown-body per article since P6 (KbArticleBodyRenderer renders the
   body as one document), so the first and last child are the article's own. */
.markdown-body[b-acuhtxscbg]  > :first-child {
    margin-top: 0;
}

.markdown-body[b-acuhtxscbg]  > :last-child {
    margin-bottom: 0;
}

/* A comfortable measure for running text. Tables, code and figures may use the
   whole column. */
.markdown-body[b-acuhtxscbg]  > :is(p, ul, ol, dl, blockquote, footer, .markdown-alert, h1, h2, h3, h4, h5, h6) {
    max-width: 75ch;
}

/* ── Headings ── */
.markdown-body[b-acuhtxscbg]  :is(h1, h2, h3, h4, h5, h6) {
    margin-top: var(--space-5);
    margin-bottom: var(--space-3);
    line-height: 1.3;
    /* app.css colours h1/h2 for the operator shell's card; in an article the
       heading follows the text around it, in either shell. */
    color: inherit;
}

.markdown-body[b-acuhtxscbg]  h1 { font-size: var(--font-size-2xl); }
.markdown-body[b-acuhtxscbg]  h2 { font-size: var(--font-size-xl); }
.markdown-body[b-acuhtxscbg]  h3 { font-size: var(--font-size-lg); }
.markdown-body[b-acuhtxscbg]  :is(h4, h5, h6) { font-size: var(--font-size-base); }

/* An in-page jump (TOC entry, footnote) lands below the sticky header rather
   than under it: the portal publishes its topbar height, and the operator
   shell's header bar is 3rem. */
.markdown-body[b-acuhtxscbg]  [id] {
    scroll-margin-top: calc(var(--portal-topbar-h, 3rem) + var(--space-3));
}

/* ── Lists ── Reboot indents with a physical padding-left; the app emits
   dir="rtl" for Arabic and Hebrew, so the indent follows the text direction. */
.markdown-body[b-acuhtxscbg]  :is(ul, ol) {
    padding-left: 0;
    padding-inline-start: var(--space-6);
}

.markdown-body[b-acuhtxscbg]  li + li {
    margin-top: var(--space-1);
}

/* Task lists: no bullet, and the checkbox hangs in the bullet's place so the
   text lines up with the other items. */
.markdown-body[b-acuhtxscbg]  .task-list-item {
    list-style: none;
}

.markdown-body[b-acuhtxscbg]  .task-list-item input[type="checkbox"] {
    margin-inline: -1.4em 0.4em;
    vertical-align: middle;
}

/* ── Definition lists ── */
.markdown-body[b-acuhtxscbg]  dt {
    font-weight: var(--font-weight-semibold);
}

.markdown-body[b-acuhtxscbg]  dd {
    margin-inline-start: var(--space-5);
    margin-bottom: var(--space-2);
}

/* ── Callouts ── Every seeded article opens with a > **Audience:** block, and
   the style guide tells authors to use > for warnings. A neutral wash and a
   muted bar; the GitHub alerts (> [!WARNING]) add their accent to the bar. */
.markdown-body[b-acuhtxscbg]  :is(blockquote, .markdown-alert) {
    margin: 0 0 var(--space-4);
    padding: var(--space-3) var(--space-4);
    border-inline-start: 4px solid var(--md-line);
    border-radius: var(--radius-sm);
    background-color: var(--md-fill);
    color: var(--md-ink);
}

.markdown-body[b-acuhtxscbg]  :is(blockquote, .markdown-alert) > :last-child {
    margin-bottom: 0;
}

.markdown-body[b-acuhtxscbg]  .markdown-alert-title {
    margin-bottom: var(--space-1);
    font-weight: var(--font-weight-semibold);
}

.markdown-body[b-acuhtxscbg]  .markdown-alert-note { border-inline-start-color: var(--md-note); }
.markdown-body[b-acuhtxscbg]  .markdown-alert-tip { border-inline-start-color: var(--md-tip); }
.markdown-body[b-acuhtxscbg]  .markdown-alert-important { border-inline-start-color: var(--md-important); }
.markdown-body[b-acuhtxscbg]  .markdown-alert-warning { border-inline-start-color: var(--md-warning); }
.markdown-body[b-acuhtxscbg]  .markdown-alert-caution { border-inline-start-color: var(--md-caution); }

/* ── Code ── Bootstrap colours inline code with --bs-code-color, a pink that
   measures 2.79:1 on the dark theme's wash (4.30:1 even on the light one); it
   takes the ink like every other fill. */
.markdown-body[b-acuhtxscbg]  code {
    padding: 0.1em 0.35em;
    border-radius: var(--radius-sm);
    background-color: var(--md-fill);
    color: var(--md-ink);
    font-size: 0.875em;
}

.markdown-body[b-acuhtxscbg]  pre {
    margin: 0 0 var(--space-4);
    padding: var(--space-3) var(--space-4);
    overflow-x: auto;
    border: 1px solid var(--md-line);
    border-radius: var(--radius-md);
    background-color: var(--md-fill);
    color: var(--md-ink);
    font-size: 0.875em;
    line-height: 1.5;
}

.markdown-body[b-acuhtxscbg]  pre code {
    padding: 0;
    border-radius: 0;
    background: none;
    color: inherit;
    font-size: inherit;
}

/* ── Tables ── The renderer wraps every table in .md-table-scroll: a table
   wider than the column scrolls in its own box, where the portal's
   overflow-x: clip used to cut it off. Reboot zeroes every cell border and
   Bootstrap only restores them for .table, so without this columns touched. */
.markdown-body[b-acuhtxscbg]  .md-table-scroll {
    max-width: 100%;
    margin: 0 0 var(--space-4);
    overflow-x: auto;
}

.markdown-body[b-acuhtxscbg]  table {
    margin: 0;
    border-collapse: collapse;
}

.markdown-body[b-acuhtxscbg]  :is(th, td) {
    padding: var(--density-cell);
    border: 1px solid var(--md-line);
    text-align: start;
    vertical-align: top;
}

.markdown-body[b-acuhtxscbg]  th {
    background-color: var(--md-head-fill);
    color: var(--md-ink);
    font-weight: var(--font-weight-semibold);
}

/* Pipe-table column alignment (|:-:|), which the renderer keeps as a class
   (P1 review F7). Physical, as the author drew it. */
.markdown-body[b-acuhtxscbg]  :is(th, td).md-align-left { text-align: left; }
.markdown-body[b-acuhtxscbg]  :is(th, td).md-align-center { text-align: center; }
.markdown-body[b-acuhtxscbg]  :is(th, td).md-align-right { text-align: right; }

/* ── Rules, figures, footnotes ── */
.markdown-body[b-acuhtxscbg]  hr {
    margin: var(--space-5) 0;
    border: 0;
    border-top: 1px solid var(--md-line);
    opacity: 1;
}

.markdown-body[b-acuhtxscbg]  figure {
    margin: 0 0 var(--space-4);
}

.markdown-body[b-acuhtxscbg]  :is(figcaption, footer) {
    margin-top: var(--space-2);
    font-size: var(--font-size-sm);
}

.markdown-body[b-acuhtxscbg]  .footnotes {
    margin-top: var(--space-6);
    font-size: var(--font-size-sm);
}

.markdown-body[b-acuhtxscbg]  .footnotes > hr {
    margin: 0 0 var(--space-3);
}

.markdown-body[b-acuhtxscbg]  .footnote-back-ref {
    margin-inline-start: var(--space-1);
    text-decoration: none;
}

/* KB Markdown plan, Pack A — inline images. Never wider than the column (a
   pasted screenshot otherwise blows out the layout everywhere but print), and
   on --color-media-backdrop: a transparent diagram drawn in black for a white
   page would otherwise vanish on the dark and operator themes. */
.markdown-body[b-acuhtxscbg]  img {
    max-width: 100%;
    height: auto;
    background-color: var(--color-media-backdrop);
    border-radius: var(--radius-sm);
}

/* ── KB theme (Pack T) ─────────────────────────────────────────────────────
   The tenant's article look. KbArticleBody → MarkdownView puts the class
   .kb-themed and an inline style on the body ONLY for a tenant that saved a
   theme, so every rule below is keyed on .kb-themed and nothing changes for
   anybody else. The inline style carries --kb-{token}-light / -dark (each
   value already through PortalTheme.IsValidColor and measured against every
   background of its polarity — KbTheme.Resolve) and --kb-font-body /
   --kb-font-heading (code constants, KbTheme.Fonts).

   Fonts follow the article everywhere, print and high contrast included. An
   unset font property is invalid at computed-value time, and font-family is
   inherited, so it simply keeps the surface's own font. */
.markdown-body.kb-themed[b-acuhtxscbg] {
    font-family: var(--kb-font-body);
}

.markdown-body.kb-themed[b-acuhtxscbg]  :is(h1, h2, h3, h4, h5, h6) {
    font-family: var(--kb-font-heading);
}

/* Colours are SCREEN-only and off under high contrast (the data-contrast
   override and the high-contrast theme): accessibility and paper beat
   branding, so those keep the rules above byte for byte.

   Step 1 picks the polarity: --kb-{token} aliases the light or the dark value.
   A value the tenant left blank leaves its alias unset, and every use in
   step 2 falls back to the colour that applies without a theme.

   Dark is the dark and Operator user themes, and — inside the portal — the
   portal's own dark palette: .portal-shell[data-portal-preset="dark"] is
   stamped from the TENANT's portal theme (PortalTheme.Resolved.Effective), and
   it wins over a light app theme there, exactly as PortalLayout.razor.css's
   palette does. A light preset does not win over a dark app theme, because
   the portal itself turns dark then (html[data-theme="dark"] .portal-shell).
   Specificity: the two html-keyed selectors tie (0,5,1), so dark comes later;
   the portal selector is (0,7,1). */
@media screen {
    html:not([data-contrast="high"]):not([data-theme="high-contrast"]) .markdown-body.kb-themed[b-acuhtxscbg] {
        --kb-accent: var(--kb-accent-light);
        --kb-heading: var(--kb-heading-light);
        --kb-note: var(--kb-note-light);
        --kb-tip: var(--kb-tip-light);
        --kb-important: var(--kb-important-light);
        --kb-warning: var(--kb-warning-light);
        --kb-caution: var(--kb-caution-light);
    }

    html:is([data-theme="dark"], [data-theme="operator"]):not([data-contrast="high"]) .markdown-body.kb-themed[b-acuhtxscbg],
    html:not([data-contrast="high"]):not([data-theme="high-contrast"]) .portal-shell[data-portal-preset="dark"] .markdown-body.kb-themed[b-acuhtxscbg] {
        --kb-accent: var(--kb-accent-dark);
        --kb-heading: var(--kb-heading-dark);
        --kb-note: var(--kb-note-dark);
        --kb-tip: var(--kb-tip-dark);
        --kb-important: var(--kb-important-dark);
        --kb-warning: var(--kb-warning-dark);
        --kb-caution: var(--kb-caution-dark);
    }

    /* Step 2. Links are body text (4.5:1): the accent, on hover too — the
       fallbacks are app.css's own a / a:hover colours, link token first (the
       dark theme's --color-primary is 2.83:1 on its card). */
    .markdown-body.kb-themed[b-acuhtxscbg]  a {
        color: var(--kb-accent, var(--color-link, var(--color-primary-ink)));
    }

    .markdown-body.kb-themed[b-acuhtxscbg]  a:hover {
        color: var(--kb-accent, var(--color-link-hover, var(--color-primary-ink-hover)));
    }

    /* currentColor on `color` is `inherit` — the heading rule above. */
    .markdown-body.kb-themed[b-acuhtxscbg]  :is(h1, h2, h3, h4) {
        color: var(--kb-heading, currentColor);
    }

    /* A plain quote's bar takes the accent; the alerts are div.markdown-alert
       and keep their own colours below. */
    .markdown-body.kb-themed[b-acuhtxscbg]  blockquote {
        border-inline-start-color: var(--kb-accent, var(--md-line));
    }

    .markdown-body.kb-themed[b-acuhtxscbg]  .markdown-alert-note { border-inline-start-color: var(--kb-note, var(--md-note)); }
    .markdown-body.kb-themed[b-acuhtxscbg]  .markdown-alert-tip { border-inline-start-color: var(--kb-tip, var(--md-tip)); }
    .markdown-body.kb-themed[b-acuhtxscbg]  .markdown-alert-important { border-inline-start-color: var(--kb-important, var(--md-important)); }
    .markdown-body.kb-themed[b-acuhtxscbg]  .markdown-alert-warning { border-inline-start-color: var(--kb-warning, var(--md-warning)); }
    .markdown-body.kb-themed[b-acuhtxscbg]  .markdown-alert-caution { border-inline-start-color: var(--kb-caution, var(--md-caution)); }

    /* The callout title is text on the callout's wash (4.5:1, measured
       against every fill of the polarity). */
    .markdown-body.kb-themed[b-acuhtxscbg]  .markdown-alert-note .markdown-alert-title { color: var(--kb-note, currentColor); }
    .markdown-body.kb-themed[b-acuhtxscbg]  .markdown-alert-tip .markdown-alert-title { color: var(--kb-tip, currentColor); }
    .markdown-body.kb-themed[b-acuhtxscbg]  .markdown-alert-important .markdown-alert-title { color: var(--kb-important, currentColor); }
    .markdown-body.kb-themed[b-acuhtxscbg]  .markdown-alert-warning .markdown-alert-title { color: var(--kb-warning, currentColor); }
    .markdown-body.kb-themed[b-acuhtxscbg]  .markdown-alert-caution .markdown-alert-title { color: var(--kb-caution, currentColor); }
}

/* ── Print ── Paper is white, whatever the theme: the tokens above follow the
   screen theme, so a dark-theme article printed light ink on white or dark
   fills on paper (Portal/HelpArticle.razor records the same lesson). Literal
   colours, re-pointing the same local properties; every pair clears 4.5:1
   (text) or 3:1 (lines) on white and on the fill. Paper does not scroll, so a
   wide table or code line is shown rather than kept in a scroll box. */
@media print {
    .markdown-body[b-acuhtxscbg] {
        --md-ink: #000000;
        --md-line: #6b6b6b;
        --md-fill: #f2f2f2;
        --md-head-fill: #e6e6e6;
        --md-note: #1d4ed8;
        --md-tip: #15803d;
        --md-important: #000000;
        --md-warning: #b45309;
        --md-caution: #b91c1c;
        color: #000000;
    }

    .markdown-body[b-acuhtxscbg]  a {
        color: #000000;
        text-decoration: underline;
    }

    .markdown-body[b-acuhtxscbg]  img {
        background-color: #ffffff;
    }

    .markdown-body[b-acuhtxscbg]  .md-table-scroll {
        overflow: visible;
    }

    .markdown-body[b-acuhtxscbg]  pre {
        overflow: visible;
        white-space: pre-wrap;
    }

    .markdown-body[b-acuhtxscbg]  :is(h1, h2, h3, h4, h5, h6) {
        break-after: avoid;
    }

    .markdown-body[b-acuhtxscbg]  :is(pre, blockquote, .markdown-alert, tr, img, figure) {
        break-inside: avoid;
    }
}
/* /Components/Shared/MetricCard.razor.rz.scp.css */
.metric[b-3wrn2ove2q] {
    background: var(--color-bg-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
    padding: 0.95rem 1rem 1rem;
}

.metric-top[b-3wrn2ove2q] {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 0.5rem;
}

.metric-icon[b-3wrn2ove2q] {
    width: 38px;
    height: 38px;
    border-radius: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.05rem;
    flex-shrink: 0;
}

.metric-spark[b-3wrn2ove2q] {
    display: flex;
    align-items: flex-end;
    gap: 2px;
    height: 30px;
}

.metric-spark span[b-3wrn2ove2q] {
    width: 5px;
    border-radius: 2px;
    opacity: 0.65;
}

.metric-value[b-3wrn2ove2q] {
    font-family: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
    font-feature-settings: "tnum";
    font-weight: 700;
    letter-spacing: -0.02em;
    font-size: 1.8rem;
    color: var(--color-text-dark);
    line-height: 1;
}

.metric-label[b-3wrn2ove2q] {
    font-size: 0.82rem;
    color: var(--color-text-muted);
    margin-top: 0.45rem;
    font-weight: 500;
}

.metric-sub[b-3wrn2ove2q] {
    font-size: 0.74rem;
    color: var(--color-text-muted);
    margin-top: 0.15rem;
}

/* Phone density. The KPI grid already fits two columns at 390px; this makes
   each tile shorter (155px -> ~115px) so the row costs a third less vertical
   space without shrinking anything below a readable size. */
@media (max-width: 640.98px) {
    .metric[b-3wrn2ove2q] {
        padding: 0.7rem 0.75rem 0.75rem;
    }
    .metric-top[b-3wrn2ove2q] {
        margin-bottom: 0.35rem;
    }
    .metric-icon[b-3wrn2ove2q] {
        width: 32px;
        height: 32px;
        border-radius: 9px;
        font-size: 0.9rem;
    }
    .metric-spark[b-3wrn2ove2q] {
        height: 22px;
    }
    .metric-value[b-3wrn2ove2q] {
        font-size: 1.45rem;
    }
    .metric-label[b-3wrn2ove2q] {
        font-size: 0.75rem;
        margin-top: 0.35rem;
    }
    .metric-sub[b-3wrn2ove2q] {
        font-size: 0.68rem;
    }
}
/* /Components/Shared/Pill.razor.rz.scp.css */
.pill[b-sw3etqwks4] {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 0.74rem;
    font-weight: 600;
    line-height: 1.5;
    padding: 0.18rem 0.62rem;
    border-radius: 999px;
    white-space: nowrap;
}

.pill-mono[b-sw3etqwks4] {
    font-family: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
    font-feature-settings: "tnum";
}

.pill .bi[b-sw3etqwks4] {
    font-size: 0.9em;
}
/* /Components/Shared/PortalAiChat.razor.rz.scp.css */
/* KB Markdown plan P7 — the assistant bubble's rendered Markdown.

   Scoped here rather than in the component's inline <style> block (plan §4
   retires inline styles; the older drawer rules still live there). The reply
   arrives as a MarkupString inside MarkdownView, so its elements carry no scope
   attribute of THIS component: every rule below reaches them with ::deep from
   the bubble, which does. */

/* Rendered Markdown: the HTML's own blocks carry the line breaks, and the
   bubble's pre-wrap (from .portal-ai-msg) would add the source's newlines on
   top of them. The scope attribute makes this outrank that rule. */
.portal-ai-msg-assistant[b-gb6fcwke44] {
    white-space: normal;
}

/* The bubble is a fixed light surface (#f1f5f9 / #1e293b) on every theme, so
   its content must not pick up theme colours meant for the page around it: a
   dark theme's light link colour, or Bootstrap's pink code text, would be
   unreadable here. Links inherit the bubble's ink (13.35:1) and are told apart
   by an underline and weight instead of a hue — only REAL links (an href that
   survived PortalLinksOnly); a refused link is plain text and must not look
   clickable. */
.portal-ai-msg-assistant[b-gb6fcwke44]  .markdown-body > :first-child {
    margin-top: 0;
}

.portal-ai-msg-assistant[b-gb6fcwke44]  .markdown-body > :last-child {
    margin-bottom: 0;
}

.portal-ai-msg-assistant[b-gb6fcwke44]  .markdown-body p,
.portal-ai-msg-assistant[b-gb6fcwke44]  .markdown-body ul,
.portal-ai-msg-assistant[b-gb6fcwke44]  .markdown-body ol {
    margin: 0 0 0.5rem;
}

.portal-ai-msg-assistant[b-gb6fcwke44]  .markdown-body ul,
.portal-ai-msg-assistant[b-gb6fcwke44]  .markdown-body ol {
    padding-left: 1.25rem;
}

.portal-ai-msg-assistant[b-gb6fcwke44]  .markdown-body a[href],
.portal-ai-msg-assistant[b-gb6fcwke44]  .markdown-body a[href]:hover {
    color: inherit;
    font-weight: 600;
    text-decoration: underline;
}

.portal-ai-msg-assistant[b-gb6fcwke44]  .markdown-body a:not([href]) {
    color: inherit;
    font-weight: inherit;
    text-decoration: none;
}

.portal-ai-msg-assistant[b-gb6fcwke44]  .markdown-body code {
    color: inherit;
}

/* app.css colours h1/h2 with theme tokens (light text on dark themes). */
.portal-ai-msg-assistant[b-gb6fcwke44]  .markdown-body :is(h1, h2, h3, h4, h5, h6) {
    color: inherit;
    font-size: 1rem;
    font-weight: 600;
    margin: 0 0 0.35rem;
}

.portal-ai-msg-assistant[b-gb6fcwke44]  .markdown-body pre {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* A wide table scrolls inside the bubble rather than widening the drawer. */
.portal-ai-msg-assistant[b-gb6fcwke44]  .markdown-body table {
    display: block;
    max-width: 100%;
    overflow-x: auto;
}
/* /Components/Shared/ProductGuideHome.razor.rz.scp.css */
/* The TrackYourIT guide's home (ProductGuideHome.razor). Shared by the portal and
   the operator shell, so every colour is the portal token with the app token as
   its fallback — the same pairs KbTableOfContents.razor.css uses, whose contrast
   KbMarkdownThemeContrastTests computes in every theme and shell. Links keep the
   shell's own link colour. Logical properties throughout (dir="rtl"). */

.guide-home-empty[b-cm3fyrxyed] {
    margin: 0;
    color: var(--portal-ink-soft, var(--color-text-muted));
}

.guide-home-index[b-cm3fyrxyed] {
    margin-block-end: var(--space-4);
}

.guide-home-index-list[b-cm3fyrxyed] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

.guide-home-index-link[b-cm3fyrxyed] {
    display: inline-block;
    padding: var(--space-1) var(--space-3);
    border: 1px solid var(--portal-line-strong, var(--color-border-strong));
    border-radius: var(--radius-pill);
    font-size: var(--font-size-sm);
    text-decoration: none;
}

.guide-home-index-link:hover[b-cm3fyrxyed],
.guide-home-index-link:focus-visible[b-cm3fyrxyed] {
    text-decoration: underline;
}

.guide-home-group[b-cm3fyrxyed] {
    margin-block-start: var(--space-5);
    scroll-margin-top: var(--space-6);
}

.guide-home-heading[b-cm3fyrxyed] {
    margin: 0 0 var(--space-2);
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-semibold);
}

.guide-home-subheading[b-cm3fyrxyed] {
    margin: var(--space-3) 0 var(--space-1);
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-semibold);
    color: var(--portal-ink-soft, var(--color-text-muted));
    scroll-margin-top: var(--space-6);
}

.guide-home-list[b-cm3fyrxyed] {
    margin: 0;
    padding: 0;
    list-style: none;
}

.guide-home-item[b-cm3fyrxyed] {
    border-block-end: 1px solid var(--portal-line, var(--color-border));
}

.guide-home-item:last-child[b-cm3fyrxyed] {
    border-block-end: 0;
}

.guide-home-link[b-cm3fyrxyed] {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: var(--space-2) 0;
    text-decoration: none;
}

.guide-home-title[b-cm3fyrxyed] {
    font-weight: var(--font-weight-medium);
}

.guide-home-link:hover .guide-home-title[b-cm3fyrxyed],
.guide-home-link:focus-visible .guide-home-title[b-cm3fyrxyed] {
    text-decoration: underline;
}

.guide-home-summary[b-cm3fyrxyed] {
    font-size: var(--font-size-sm);
    color: var(--portal-ink-soft, var(--color-text-muted));
}

/* Product guide Pack 2 — the search box above the listing. */
.guide-home-search[b-cm3fyrxyed] {
    margin-block-end: var(--space-4);
}

.guide-home-search-label[b-cm3fyrxyed] {
    display: block;
    margin-block-end: var(--space-1);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
}

.guide-home-search-shell[b-cm3fyrxyed] {
    position: relative;
}

.guide-home-search-icon[b-cm3fyrxyed] {
    position: absolute;
    inset-block-start: 50%;
    inset-inline-start: var(--space-3);
    transform: translateY(-50%);
    color: var(--portal-ink-soft, var(--color-text-muted));
    pointer-events: none;
}

.guide-home-search-input[b-cm3fyrxyed] {
    inline-size: 100%;
    padding-block: var(--space-2);
    padding-inline: calc(var(--space-3) * 2 + 1em) var(--space-3);
    border: 1px solid var(--portal-line-strong, var(--color-border-strong));
    border-radius: var(--radius-md);
    background: var(--portal-surface, var(--color-bg-card));
    color: inherit;
    font: inherit;
}

.guide-home-search-input:focus-visible[b-cm3fyrxyed] {
    outline: 2px solid var(--portal-accent, var(--color-primary));
    outline-offset: 2px;
}

.guide-home-search-status[b-cm3fyrxyed] {
    min-block-size: 1.25em;
    margin: var(--space-1) 0 0;
    font-size: var(--font-size-sm);
    color: var(--portal-ink-soft, var(--color-text-muted));
}

.guide-home-search-none[b-cm3fyrxyed] {
    margin: 0;
    color: var(--portal-ink-soft, var(--color-text-muted));
}
/* /Components/Shared/ProductGuidePageView.razor.rz.scp.css */
/* One TrackYourIT guide page (ProductGuidePageView.razor), in the portal shell and
   the operator shell alike: portal tokens with the app tokens as fallbacks, the
   pairs KbTableOfContents.razor.css already uses. The body itself is styled by
   MarkdownView (.markdown-body), exactly like a tenant article. */

.guide-page[b-3rl7ezjyto] {
    max-width: 78ch;
}

.guide-crumbs[b-3rl7ezjyto] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-2);
    margin-block-end: var(--space-3);
    font-size: var(--font-size-sm);
}

.guide-crumb[b-3rl7ezjyto] {
    text-decoration: none;
}

.guide-crumb:hover[b-3rl7ezjyto],
.guide-crumb:focus-visible[b-3rl7ezjyto] {
    text-decoration: underline;
}

.guide-crumb-sep[b-3rl7ezjyto] {
    color: var(--portal-ink-soft, var(--color-text-muted));
}

.guide-head[b-3rl7ezjyto] {
    margin-block-end: var(--space-4);
}

.guide-title[b-3rl7ezjyto] {
    margin: 0 0 var(--space-2);
    font-size: var(--font-size-2xl);
    font-weight: var(--font-weight-semibold);
}

.guide-summary[b-3rl7ezjyto] {
    margin: 0 0 var(--space-2);
    font-size: var(--font-size-lg);
    color: var(--portal-ink-soft, var(--color-text-muted));
}

.guide-badge[b-3rl7ezjyto] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    margin: 0;
    padding: 2px var(--space-2);
    border: 1px solid var(--portal-line-strong, var(--color-border-strong));
    border-radius: var(--radius-pill);
    font-size: var(--font-size-xs);
    color: var(--portal-ink-soft, var(--color-text-muted));
}

.guide-page[b-3rl7ezjyto]  .guide-toc {
    margin-block-end: var(--space-4);
}

.guide-body[b-3rl7ezjyto] {
    margin-block-end: var(--space-5);
}

.guide-more[b-3rl7ezjyto] {
    padding-block-start: var(--space-3);
    border-block-start: 1px solid var(--portal-line, var(--color-border));
}

.guide-more-heading[b-3rl7ezjyto] {
    margin: 0 0 var(--space-2);
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-semibold);
}

.guide-more-list[b-3rl7ezjyto] {
    margin: 0;
    padding: 0;
    list-style: none;
}

.guide-more-item[b-3rl7ezjyto] {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding-block: var(--space-2);
}

.guide-more-link[b-3rl7ezjyto] {
    font-weight: var(--font-weight-medium);
}

.guide-more-summary[b-3rl7ezjyto] {
    font-size: var(--font-size-sm);
    color: var(--portal-ink-soft, var(--color-text-muted));
}

/* Paper is white whatever the theme: literal colours, as in every print block. */
@media print {
    .guide-crumbs[b-3rl7ezjyto],
    .guide-more[b-3rl7ezjyto] {
        display: none;
    }

    .guide-summary[b-3rl7ezjyto],
    .guide-badge[b-3rl7ezjyto] {
        color: #444444;
    }
}
/* /Components/Shared/SlaClockManager.razor.rz.scp.css */
/* SD round-2 #12/#13 — SlaClockManager scoped styles. Defined design tokens
   only (--color-text-muted / --color-bg-card / --color-bg-subtle /
   --color-border / --radius-*); the SlaCountdown child styles itself. */

.sla-clock-leg[b-0hw1np0tzk] {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    border-top: 1px solid var(--color-border);
    padding-top: 0.25rem;
    margin-top: 0.25rem;
}

.sla-clock-leg-body[b-0hw1np0tzk] {
    flex: 1 1 auto;
    min-width: 0;
}

.sla-clock-leg-side[b-0hw1np0tzk] {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.25rem;
    padding-top: 0.5rem;
    flex: 0 0 auto;
}

.sla-clock-kind[b-0hw1np0tzk] {
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-text-muted);
    background: var(--color-bg-subtle);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
    padding: 0.05rem 0.5rem;
    white-space: nowrap;
}

.sla-clock-actions[b-0hw1np0tzk] {
    display: flex;
    gap: 0.25rem;
}

.sla-clock-confirm[b-0hw1np0tzk] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.8rem;
    color: var(--color-text-muted);
    background: var(--color-bg-subtle);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: 0.4rem 0.6rem;
    margin: 0.25rem 0;
}

.sla-clock-empty[b-0hw1np0tzk] {
    font-size: 0.8rem;
    color: var(--color-text-muted);
    border-top: 1px solid var(--color-border);
    padding-top: 0.5rem;
    margin-top: 0.25rem;
}

.sla-clock-add-buttons[b-0hw1np0tzk] {
    display: flex;
    gap: 0.5rem;
    border-top: 1px solid var(--color-border);
    padding-top: 0.6rem;
    margin-top: 0.5rem;
}

.sla-clock-add-form[b-0hw1np0tzk] {
    background: var(--color-bg-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: 0.6rem 0.75rem;
    margin-top: 0.5rem;
}

.sla-clock-add-title[b-0hw1np0tzk] {
    font-size: 0.8rem;
    font-weight: 600;
    margin-bottom: 0.4rem;
}

.sla-clock-add-actions[b-0hw1np0tzk] {
    display: flex;
    gap: 0.5rem;
    margin-top: 0.6rem;
}
