/* /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;
}

.app-brand-icon[b-ln6b6nx6u0] {
    font-size: 1.25rem;
    color: var(--color-primary, #60a5fa);
}

.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;
    /* 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 colours are stated. Three layers can restate them, weakest
       first:
         1. this rule                                        (built-in light)
         2. .portal-shell[data-portal-preset="dark"] below   (the dark preset)
         3. the inline style PortalLayout renders            (admin overrides)
       An inline declaration outranks any author rule, which is exactly how
       --portal-accent has always picked up the tenant's brand colour.

       NOTE for anyone tempted to write `--portal-canvas: var(--portal-canvas,
       #f6f7fb)` here so the "override" is visible in this file: a custom
       property that references ITSELF is a cycle and resolves to the
       guaranteed-invalid value, taking the token out entirely. The cascade
       above is the mechanism; these are its base values.

       --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 preset pins them
       to literals instead, because the shared scale is following the OPERATOR
       app's theme, not the tenant's portal choice. */
    --portal-canvas: #f6f7fb;
    --portal-surface: var(--color-bg-card, #ffffff);
    --portal-surface-elevated: rgba(255, 255, 255, 0.78);
    --portal-ink: var(--color-text-dark, #0f172a);
    --portal-ink-soft: var(--color-text-muted, #475569);
    --portal-ink-faint: #94a3b8;
    --portal-line: 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 preset ────────────────────────────────────────────────────
   Selected by data-portal-preset on the shell, which PortalLayout stamps from
   the tenant's stored theme. The attribute is ABSENT for a tenant that never
   configured one, so this block cannot affect anybody who did not opt in.

   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] {
    --portal-canvas: #0b1220;
    --portal-surface: #131c2e;
    --portal-surface-elevated: rgba(23, 33, 53, 0.78);
    --portal-ink: #e6edf7;
    --portal-ink-soft: #9fb0c9;
    --portal-ink-faint: #6b7d99;
    --portal-line: 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;

    /* 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;
}

/* 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, #6164ee);
    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;
    background: linear-gradient(135deg,
        var(--portal-accent),
        color-mix(in oklab, var(--portal-accent) 60%, #1e1b4b));
    color: white;
    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);
    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, #6164ee);
}
.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);
}

/* 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;
}
.portal-content[b-2hk7lilw2e] {
    animation: portal-page-in-b-2hk7lilw2e 380ms cubic-bezier(0.22, 1, 0.36, 1) both;
}
@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, #6164ee);
    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, #6164ee)) 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, #6164ee);
    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, #6164ee);
}
[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, #6164ee);
    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, #6164ee);
    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); }
[b-2hk7lilw2e] .portal-btn-primary {
    color: white;
    background: linear-gradient(135deg,
        var(--portal-accent, #6164ee),
        color-mix(in oklab, var(--portal-accent, #6164ee) 60%, #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;
    }
}

/* ── 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; }
}
/* /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, #94a3b8);
}
/* 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, #6164ee);
}

.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, #94a3b8);
    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, #6164ee);
}
/* 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-primary, #60a5fa);
}

.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-primary, #60a5fa);
}

.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-primary, #60a5fa);
}

/* 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. */
.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);
}

.vendor-brand-icon[b-4doyjmsto0] {
    color: var(--portal-accent, #6164ee);
}
/* /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;
}
/* /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);
}

.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);
}

/* ── 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;
}

/* ── 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] {
    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);
    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);
}

.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-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);
}

/* ── 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/Pages/Workflows/WorkflowFormBuilder.razor.rz.scp.css */
/* WF-200 B2 — form-mode builder: palette | live preview | inspector. */

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

.wfb-palette[b-xy13k5sjlk],
.wfb-inspector[b-xy13k5sjlk] {
    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-xy13k5sjlk],
.wfb-inspector-title[b-xy13k5sjlk] {
    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-xy13k5sjlk] {
    font-size: 13px;
    text-transform: none;
    letter-spacing: 0;
    color: var(--color-text, #111827);
}

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

.wfb-palette-item[b-xy13k5sjlk] {
    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-xy13k5sjlk] {
    background: var(--color-bg-subtle, #f3f4f6);
    border-color: var(--color-primary, var(--color-primary));
}

.wfb-palette-note[b-xy13k5sjlk] {
    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-xy13k5sjlk] {
    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-xy13k5sjlk] {
    text-align: center;
    color: var(--color-text-muted, #9ca3af);
    padding: 4rem 1rem;
}

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

.wfb-control[b-xy13k5sjlk] {
    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-xy13k5sjlk] {
    border-color: var(--color-primary, var(--color-primary));
    box-shadow: 0 0 0 1px var(--color-primary, var(--color-primary));
}

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

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

.wfb-control-tools button[b-xy13k5sjlk] {
    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-xy13k5sjlk] {
    background: var(--color-bg-subtle, #f3f4f6);
    color: var(--color-text, #111827);
}

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

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

.wfb-drag-handle[b-xy13k5sjlk] {
    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-xy13k5sjlk] {
    cursor: grabbing;
}

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

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

.wfb-drop-indicator[b-xy13k5sjlk] {
    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-xy13k5sjlk] {
    display: block;
}

.wfb-label[b-xy13k5sjlk] {
    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-xy13k5sjlk] {
    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-xy13k5sjlk] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 4px;
}

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

.wfb-column-remove[b-xy13k5sjlk] {
    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-xy13k5sjlk] {
    background: var(--color-bg-subtle, #f3f4f6);
    color: var(--color-danger, #dc2626);
}
/* /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/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/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;
}
