/* AppPlatform base styles — consumed by app-* projects */

/* ThemeProvider — primary token injection point (AC-18) */
.ap-theme-root {
    font-family: inherit;
    color: var(--ap-text-primary);
    background-color: var(--ap-bg-page);
}

*, *::before, *::after {
    box-sizing: border-box;
}

html {
    max-width: 100%;
}

body {
    margin: 0;
    font-family: var(--rz-body-font-family, system-ui, sans-serif);
    color: var(--ap-text-primary);
    background-color: var(--ap-bg-page);
    max-width: 100%;
    overflow-x: clip;
}

img,
svg,
canvas,
video,
iframe {
    max-width: 100%;
}

/* Layout */
.ap-layout {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    min-width: 0;
    max-width: 100%;
    overflow-x: clip;
}

/* App switcher */
.ap-app-switcher {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    flex: 0 0 auto;
    min-width: 0;
    gap: var(--ap-space-2);
    padding: var(--ap-space-2);
}

/* Theme toggle (Light <-> Dark) */
.ap-theme-toggle {
    background: none;
    border: none;
    cursor: pointer;
    padding: var(--ap-space-2);
    min-width: 44px;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--ap-text-primary);
    border-radius: var(--ap-radius-sm);
}

.ap-theme-toggle .rzi {
    color: var(--ap-text-primary);
}

.ap-theme-toggle:hover {
    background-color: var(--ap-surface);
}

.ap-theme-toggle:focus-visible {
    outline: var(--ap-focus-ring-width) solid var(--ap-focus-ring-color);
    outline-offset: var(--ap-focus-ring-offset);
}

.ap-app-switcher--loading {
    pointer-events: none;
}

/* App-switcher island slot (1.5.1): on static-SSR hosts the switcher is an
   InteractiveServer island rendered with prerender:false, so this slot holds only
   Blazor marker comments (:empty) until the circuit connects and the island
   hydrates already-wired. Reserve the trigger's footprint (a 44px control inside
   the .ap-app-switcher padding) so hydration causes NO layout shift, and — while
   :empty — paint a subtle, non-interactive placeholder so the pre-hydration state
   reads as "a control will appear here", never as a clickable button. Once the
   island renders content (its own RadzenSkeleton while loading, then the trigger)
   the slot is no longer :empty and the placeholder disappears. Deliberately not
   animated: in the rare settled-empty case (registry down → the component renders
   nothing) a static block is honest, whereas an infinite pulse would imply loading
   that never resolves. */
.ap-app-switcher-slot {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: calc(44px + 2 * var(--ap-space-2));
    min-height: calc(44px + 2 * var(--ap-space-2));
}

.ap-app-switcher-slot:empty {
    padding: var(--ap-space-2);
}

.ap-app-switcher-slot:empty::before {
    content: "";
    width: 44px;
    height: 44px;
    border-radius: var(--ap-radius-sm);
    background-color: var(--ap-surface);
    opacity: 0.5;
    pointer-events: none;
}

.ap-app-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--ap-space-1);
    padding: var(--ap-space-2);
    border: 1px solid var(--ap-border-default);
    border-radius: var(--ap-radius-md);
    background: none;
    cursor: pointer;
    font-family: inherit;
    font-size: var(--ap-text-xs);
    color: var(--ap-text-primary);
    overflow-wrap: anywhere;
    min-width: 0;
    max-width: 100%;
    transition: background-color var(--ap-motion-duration-fast) var(--ap-motion-ease-standard);
}

.ap-app-tile:hover {
    background-color: var(--ap-surface);
}

.ap-app-icon {
    width: 40px;
    height: 40px;
    flex-shrink: 0;
}

.ap-app-icon--image {
    object-fit: contain;
}

.ap-app-icon--text {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: var(--ap-text-sm);
    font-weight: 700;
    line-height: 1;
    letter-spacing: 0;
    color: var(--ap-primary);
    background-color: var(--ap-primary-subtle);
    border: 1px solid var(--ap-border-default);
    border-radius: var(--ap-radius-sm);
}

/* Breadcrumbs */
.ap-breadcrumbs ol {
    display: flex;
    flex-wrap: wrap;
    list-style: none;
    margin: 0;
    padding: 0;
    gap: var(--ap-space-1);
}

.ap-breadcrumbs li + li::before {
    content: '/';
    margin-right: var(--ap-space-1);
    color: var(--ap-border-default);
}

/* Layout header (used by RCL MainLayout) */
.ap-layout-header {
    position: sticky;
    top: 0;
    z-index: 100;
    background-color: var(--ap-bg-page);
    border-bottom: 1px solid var(--ap-border-default);
    padding: 0 var(--ap-space-4);
    min-width: 0;
    max-width: 100%;
}

.ap-header-nav {
    display: flex;
    align-items: center;
    gap: var(--ap-space-4);
    height: 56px;
    max-width: 1200px;
    min-width: 0;
    width: 100%;
    margin: 0 auto;
}

.ap-header-brand {
    font-family: inherit;
    font-weight: 600;
    font-size: var(--ap-text-lg);
    color: var(--ap-primary);
    text-decoration: none;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ap-layout-content {
    flex: 1;
    max-width: 1200px;
    min-width: 0;
    margin: 0 auto;
    padding: var(--ap-space-6) var(--ap-space-4);
    width: 100%;
    overflow-wrap: anywhere;
}

.ap-layout-content > * {
    min-width: 0;
    max-width: 100%;
}

.ap-error {
    padding: var(--ap-space-4);
    border: 1px solid var(--ap-border-default);
    border-radius: var(--ap-radius-md);
    color: var(--ap-text-primary);
    background-color: var(--ap-surface);
}

/* App switcher trigger + dropdown */
.ap-app-switcher-trigger {
    background: none;
    border: none;
    cursor: pointer;
    padding: var(--ap-space-2);
    min-width: 44px;
    min-height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--ap-text-primary);
    border-radius: var(--ap-radius-sm);
}

.ap-app-switcher-trigger:hover {
    background-color: var(--ap-surface);
}

.ap-app-switcher-trigger:focus-visible {
    outline: var(--ap-focus-ring-width) solid var(--ap-focus-ring-color);
    outline-offset: var(--ap-focus-ring-offset);
}

.ap-app-switcher-glyph {
    width: 20px;
    height: 20px;
    display: block;
    fill: currentColor;
    flex: 0 0 auto;
}

.ap-app-switcher-dropdown {
    position: absolute;
    top: 100%;
    /* Anchor to the right of the trigger — the trigger sits at the right edge of the
       header, so left: 0 made the dropdown overflow off-screen and trigger a horizontal
       page scrollbar (violating css-conformity-gate AC-09). */
    right: 0;
    z-index: 200;
    background-color: var(--ap-bg-page);
    border: 1px solid var(--ap-border-default);
    border-radius: var(--ap-radius-md);
    padding: var(--ap-space-2);
    display: flex;
    flex-wrap: wrap;
    gap: var(--ap-space-2);
    min-width: min(240px, calc(100vw - var(--ap-space-8, 2rem)));
    max-width: calc(100vw - var(--ap-space-8, 2rem));
    overflow-x: hidden;
}

.ap-app-switcher-tile-slot {
    display: flex;
    min-width: 0;
    max-width: 100%;
}

.ap-app-switcher-tile-slot .ap-app-tile {
    min-width: 0;
    max-width: 100%;
}

.ap-app-switcher-tile-slot .rz-button-box,
.ap-app-tile .rz-button-box {
    min-width: 0;
    max-width: 100%;
    white-space: normal;
}

/* Status badge */
.ap-status-badge {
    display: inline-block;
    padding: 2px var(--ap-space-2);
    border-radius: var(--ap-radius-sm);
    font-size: var(--ap-text-xs);
    font-weight: 600;
}

.ap-status-badge--live {
    color: var(--ap-primary);
}

.ap-status-badge--comingsoon {
    color: var(--ap-text-primary);
    opacity: var(--ap-state-disabled-opacity);
}

/* Notification host */
.ap-notification-host {
    position: fixed;
    bottom: var(--ap-space-4);
    right: var(--ap-space-4);
    z-index: 9999;
    display: flex;
    flex-direction: column;
    gap: var(--ap-space-2);
    max-width: calc(100vw - var(--ap-space-8, 2rem));
}

/* Toast notifications */
.ap-toast {
    display: flex;
    align-items: center;
    gap: var(--ap-space-2);
    padding: var(--ap-space-3) var(--ap-space-4);
    background-color: var(--ap-bg-page);
    border: 1px solid var(--ap-border-default);
    border-radius: var(--ap-radius-md);
    box-shadow: var(--ap-shadow-sm);
    min-width: min(240px, 100%);
    max-width: min(400px, 100%);
}

.ap-toast--info    { border-left: 3px solid var(--ap-info); }
.ap-toast--success { border-left: 3px solid var(--ap-success); }
.ap-toast--warning { border-left: 3px solid var(--ap-warning); }
.ap-toast--error   { border-left: 3px solid var(--ap-error); }

.ap-toast-icon {
    font-size: var(--ap-text-base);
    flex-shrink: 0;
}

.ap-toast-message {
    flex: 1;
    color: var(--ap-text-primary);
    font-family: inherit;
    font-size: var(--ap-text-sm);
}

.ap-toast-dismiss {
    background: none;
    border: none;
    cursor: pointer;
    color: var(--ap-text-primary);
    font-size: var(--ap-text-base);
    min-width: 44px;
    min-height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--ap-radius-sm);
    padding: 0;
}

.ap-toast-dismiss:hover {
    background-color: var(--ap-surface);
}

@media (max-width: 40rem) {
    .ap-layout-header {
        padding-inline: var(--ap-space-2);
    }

    .ap-header-nav {
        gap: var(--ap-space-2);
    }

    .ap-header-brand {
        flex: 1 1 auto;
        max-width: 100%;
    }

    .ap-layout-content {
        padding-inline: var(--ap-space-3);
    }

    .ap-app-switcher-dropdown {
        right: 0;
        min-width: 0;
        width: min(240px, calc(100vw - var(--ap-space-4, 1rem)));
        max-width: calc(100vw - var(--ap-space-4, 1rem));
        overflow-x: hidden;
    }

    .ap-app-switcher-tile-slot,
    .ap-app-switcher-tile-slot .ap-app-tile {
        width: 100%;
    }
}

/* === Shared WODVTT trait control (TraitRating) ===========================
   Compact 5+5 grouped, numberless marks. Visible mark is drawn on ::before so
   the button stays a larger tappable target (C2/mobile). The control fits its
   slot (width:100%, min-width:0, wraps) and never forces the parent wider (C1).
   All color/shadow/gradient/radius come from --ap-wodvtt-* tokens (C5); the
   parchment variant is supplied by the host re-binding those tokens under its
   own theme scope (no theme selector baked in here). */
.trait-rating {
    --wodvtt-mark-size: 20px;       /* standard glyph inside the target */
    --wodvtt-within-gap: 2px;       /* between marks inside a group */
    --wodvtt-group-gap: 7px;        /* between 5-mark groups */
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    column-gap: var(--wodvtt-group-gap);
    row-gap: var(--ap-space-2);
    min-width: 0;
    max-width: 100%;
    line-height: 1;
}

.trait-rating.trait-rating--compact {
    --wodvtt-mark-size: 16px;
    --wodvtt-within-gap: 1px;
    --wodvtt-group-gap: 6px;
}

.trait-rating .tr-group {
    display: flex;
    align-items: center;
    column-gap: var(--wodvtt-within-gap);
}

/* Each mark uses the platform touch-target minimum. The smaller visible glyph
   remains on ::before, preserving the grouped trait vocabulary without a
   precision-tapping target. Reset the user-agent button box model so buttons
   and readonly spans remain aligned. */
.trait-rating .tr-item {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    width: var(--ap-touch-target-min);
    height: var(--ap-touch-target-min);
    padding: 0;
    margin: 0;
    border: 0;
    background: transparent;
    font: inherit;
    cursor: default;
}

.trait-rating .tr-interactive { cursor: pointer; }

.trait-rating .tr-item::before {
    content: "";
    width: var(--wodvtt-mark-size);
    height: var(--wodvtt-mark-size);
    box-sizing: border-box;
}

.trait-rating .tr-dot::before { border-radius: var(--ap-wodvtt-mark-radius-dot); }
.trait-rating .tr-box::before { border-radius: var(--ap-wodvtt-mark-radius-box); }

.trait-rating .tr-dot.off::before {
    background-color: var(--ap-wodvtt-mark-empty-bg);
    background-image: var(--ap-wodvtt-dot-empty-image);
    border: .6px solid var(--ap-wodvtt-mark-empty-border);
    box-shadow: var(--ap-wodvtt-dot-empty-shadow);
}

.trait-rating .tr-dot.on::before {
    background-color: transparent;
    background-image: var(--ap-wodvtt-dot-filled-image);
    border: .6px solid var(--ap-wodvtt-mark-filled-border);
    box-shadow: var(--ap-wodvtt-dot-filled-shadow);
}

.trait-rating .tr-box.off::before {
    background: var(--ap-wodvtt-mark-empty-bg);
    border: .7px solid var(--ap-wodvtt-mark-empty-border);
    box-shadow: var(--ap-wodvtt-box-empty-shadow);
}

.trait-rating .tr-box.on::before {
    background-image: var(--ap-wodvtt-box-filled-image);
    border: .7px solid var(--ap-wodvtt-mark-filled-border);
    box-shadow: var(--ap-wodvtt-box-filled-shadow);
}

/* Keyboard focus ring hugs the rendered mark (C6 a11y preserved). */
.trait-rating .tr-interactive:focus-visible { outline: none; }
.trait-rating .tr-interactive:focus-visible::before {
    outline: var(--ap-focus-ring-width) solid var(--ap-focus-ring-color);
    outline-offset: var(--ap-focus-ring-offset);
}

/* === Shared WODVTT box track (BoxTrack) ==================================
   Willpower / Humanity / Blood damage tracks. Wraps and fits its slot so even
   Blood (Max=100) never overflows (C1/C2); boxes group in fives. Optional
   numeric meter header (ShowValue). Tokenized via --ap-wodvtt-* (C5). */
.box-track {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    min-width: 0;
    max-width: 100%;
    column-gap: var(--ap-space-2);
    row-gap: var(--ap-space-1);
}

.box-track .bt-meter {
    font-size: var(--ap-text-xs);
    color: var(--ap-text-secondary);
    white-space: nowrap;
}

/* Same mark size + 5-grouping as TraitRating, so a damage track and a trait box
   read as the same control family. Wrapping only happens between groups. */
.box-track .bt-boxes {
    --wodvtt-mark-size: 18px;
    --wodvtt-within-gap: 2px;
    --wodvtt-group-gap: 7px;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    column-gap: var(--wodvtt-group-gap);
    row-gap: var(--ap-space-1);
    min-width: 0;
    max-width: 100%;
}

.box-track--compact .bt-boxes {
    --wodvtt-mark-size: 14px;
    --wodvtt-within-gap: 1px;
    --wodvtt-group-gap: 6px;
}

.box-track .bt-group {
    display: flex;
    align-items: center;
    column-gap: var(--wodvtt-within-gap);
}

.box-track .bt-box {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    width: var(--ap-touch-target-min);
    height: var(--ap-touch-target-min);
    margin: 0;
    padding: 0;
    border: 0;
    background: transparent;
    font: inherit;
    cursor: pointer;
}

.box-track .bt-box::before {
    content: "";
    box-sizing: border-box;
    width: var(--wodvtt-mark-size);
    height: var(--wodvtt-mark-size);
    border: .7px solid var(--ap-wodvtt-mark-empty-border);
    border-radius: var(--ap-wodvtt-mark-radius-box);
    background: var(--ap-wodvtt-mark-empty-bg);
    box-shadow: var(--ap-wodvtt-box-empty-shadow);
}

.box-track .bt-box.active:not(.cross)::before {
    border-color: var(--ap-wodvtt-mark-filled-border);
    background-image: var(--ap-wodvtt-box-filled-image);
    box-shadow: var(--ap-wodvtt-box-filled-shadow);
}

/* Cross mode → engraved well stays; ink X is drawn on top (damage track idiom). */
.box-track .bt-box.cross.active::before {
    border-color: var(--ap-wodvtt-mark-filled-border);
    background: var(--ap-wodvtt-mark-empty-bg);
}

.box-track .bt-box.cross.active::after {
    content: "";
    position: absolute;
    width: calc(var(--wodvtt-mark-size) * .64);
    height: calc(var(--wodvtt-mark-size) * .64);
    background:
        linear-gradient(to bottom right, transparent calc(50% - 1px), var(--ap-wodvtt-cross-ink) calc(50% - 1px), var(--ap-wodvtt-cross-ink) calc(50% + 1px), transparent calc(50% + 1px)),
        linear-gradient(to bottom left, transparent calc(50% - 1px), var(--ap-wodvtt-cross-ink) calc(50% - 1px), var(--ap-wodvtt-cross-ink) calc(50% + 1px), transparent calc(50% + 1px));
}

.box-track .bt-box:disabled { cursor: default; }

.box-track:focus-visible,
.box-track .bt-box:focus-visible {
    outline: var(--ap-focus-ring-width) solid var(--ap-focus-ring-color);
    outline-offset: var(--ap-focus-ring-offset);
}

/* === Shared WODVTT health chart (HealthTrack) ============================
   Vertical wound-level chart: each row is a named level (label + penalty +
   damage boxes). A 3-column grid aligns label / penalty / boxes across rows.
   Boxes reuse the same --ap-wodvtt-* box visual as BoxTrack, so a health box
   matches a trait box. */
.health-track {
    --wodvtt-mark-size: 18px;
    display: grid;
    grid-template-columns: 1fr auto auto;   /* label | penalty | boxes */
    align-items: center;
    column-gap: var(--ap-space-3);
    row-gap: var(--ap-space-1);
    min-width: 0;
    max-width: 100%;
}

.health-track--compact { --wodvtt-mark-size: 14px; }

.health-track .health-level-label {
    color: var(--ap-text-primary);
    font-size: var(--ap-text-sm);
    white-space: nowrap;
}

.health-track .health-level-penalty {
    color: var(--ap-text-secondary);
    font-size: var(--ap-text-sm);
    text-align: right;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.health-track .health-level-boxes {
    display: flex;
    align-items: center;
    column-gap: 2px;
}

.health-track .health-box {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    width: var(--ap-touch-target-min);
    height: var(--ap-touch-target-min);
    margin: 0;
    padding: 0;
    border: 0;
    background: transparent;
    font: inherit;
    cursor: pointer;
}

.health-track .health-box::before {
    content: "";
    box-sizing: border-box;
    width: var(--wodvtt-mark-size);
    height: var(--wodvtt-mark-size);
    border: .7px solid var(--ap-wodvtt-mark-empty-border);
    border-radius: var(--ap-wodvtt-mark-radius-box);
    background: var(--ap-wodvtt-mark-empty-bg);
    box-shadow: var(--ap-wodvtt-box-empty-shadow);
}

/* Damaged box → ink X (same idiom as BoxTrack Cross mode). Normal damage uses the
   trait ink; aggravated damage uses the error/danger ink. */
.health-track .health-box.cross { --hb-ink: var(--ap-wodvtt-cross-ink); }
.health-track .health-box.normal.cross::before { border-color: var(--ap-wodvtt-mark-filled-border); }
.health-track .health-box.aggravated.cross { --hb-ink: var(--ap-semantic-error); }
.health-track .health-box.aggravated.cross::before { border-color: var(--ap-semantic-error); }

.health-track .health-box.cross::after {
    content: "";
    position: absolute;
    width: calc(var(--wodvtt-mark-size) * .64);
    height: calc(var(--wodvtt-mark-size) * .64);
    background:
        linear-gradient(to bottom right, transparent calc(50% - 1px), var(--hb-ink) calc(50% - 1px), var(--hb-ink) calc(50% + 1px), transparent calc(50% + 1px)),
        linear-gradient(to bottom left, transparent calc(50% - 1px), var(--hb-ink) calc(50% - 1px), var(--hb-ink) calc(50% + 1px), transparent calc(50% + 1px));
}

.health-track .health-box:disabled { cursor: default; }

.health-track .health-box:focus-visible {
    outline: var(--ap-focus-ring-width) solid var(--ap-focus-ring-color);
    outline-offset: var(--ap-focus-ring-offset);
}

/* PlatformShellLayout — NAV-03 hosted-app shell, built on Radzen primitives
   (RadzenSidebar / RadzenPanelMenu / RadzenPanelMenuItem / RadzenHeader / RadzenLink).
   One shell nav container: a platform section (always rendered first, never hidden)
   plus one bounded app-local section below it. Desktop uses a persistent left side-rail
   plus a top bar; mobile mirrors the same order inside a hamburger-triggered drawer
   that pushes content (no overlay, no bottom nav). The version + changelog link is
   pinned to the bottom of the rail / drawer. The drawer disclosure is CSS-only (a
   hidden checkbox + <label> hamburger + :checked sibling selector) so the shell works
   under static SSR as well as InteractiveServer. */
.ap-hosted-shell {
    display: flex;
    min-height: 100vh;
}

/* Hidden state holder for the CSS-only mobile drawer. */
.ap-hosted-shell-drawer-toggle {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}

/* Persistent dark side-rail. The Radzen sidebar element carries both .rz-sidebar and
   this class; override the Radzen defaults so the rail is in-flow and always visible on
   desktop. */
.ap-hosted-shell-nav.rz-sidebar,
.ap-hosted-shell-nav {
    display: none;
    position: static;
    inset: auto;
    transform: none;
    flex-direction: column;
    width: 260px;
    flex-shrink: 0;
    height: auto;
    min-height: 100vh;
    padding: var(--ap-space-3);
    gap: var(--ap-space-3);
    border: none;
    border-right: 1px solid var(--ap-border-default);
    background-color: var(--ap-bg-elevated);
    color: var(--ap-text-primary);
}

/* Brand tile + wordmark at the very top of the rail. */
.ap-hosted-shell-brand {
    display: flex;
    align-items: center;
    gap: var(--ap-space-2);
    padding: var(--ap-space-2);
    font-weight: 600;
    color: var(--ap-text-primary);
}

.ap-hosted-shell-brand-tile {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    flex-shrink: 0;
    border-radius: var(--ap-radius-sm);
    background-color: var(--ap-action-primary-bg, var(--ap-action-primary));
    color: var(--ap-action-primary-text, var(--ap-text-on-accent));
}

.ap-hosted-shell-brand-text {
    font-size: var(--ap-text-md);
}

/* One Radzen panel menu per nav section (a valid <ul> of RadzenPanelMenuItem rows).
   Strip the default Radzen chrome/margin so the section heading sits directly above a
   tight list of item rows and the two sections stack cleanly. */
.ap-hosted-shell-panel-menu.rz-panel-menu,
.ap-hosted-shell-panel-menu {
    background: none;
    border: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

/* Each nav section: heading + its own panel menu, stacked. Section-to-section spacing
   comes from the rail / drawer flex container gap. */
.ap-hosted-shell-nav-section {
    display: flex;
    flex-direction: column;
    gap: var(--ap-space-1);
}

.ap-hosted-shell-nav-heading {
    padding: 0 var(--ap-space-2);
    font-size: var(--ap-text-xs);
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--ap-text-secondary);
}

.ap-hosted-shell-nav-divider {
    height: 1px;
    margin: var(--ap-space-1) 0;
    background-color: var(--ap-border-default);
}

/* Radzen renders each RadzenPanelMenuItem as an <li><a> row — give the anchors the
   icon+label appearance and an active/current highlight consistent with the approved
   mockup. */
.ap-hosted-shell-nav .rz-navigation-item-link,
.ap-hosted-shell-mobile-nav .rz-navigation-item-link {
    display: flex;
    align-items: center;
    gap: var(--ap-space-2);
    min-height: var(--ap-touch-target-min);
    padding: var(--ap-space-2);
    border-inline-start: var(--ap-focus-ring-width) solid transparent;
    border-radius: var(--ap-radius-sm);
    background-image: none;
    color: var(--ap-text-primary);
    text-decoration: none;
}

.ap-hosted-shell-mobile-nav .rz-navigation-item-link,
.ap-hosted-shell-nav .rz-navigation-item-link:not(.rz-state-disabled)::before,
.ap-hosted-shell-mobile-nav .rz-navigation-item-link:not(.rz-state-disabled)::before {
    background-image: none;
}

.ap-hosted-shell-nav .rz-navigation-item-link .rzi,
.ap-hosted-shell-mobile-nav .rz-navigation-item-link .rzi,
.ap-hosted-shell-nav .rz-navigation-item-link .rz-navigation-item-icon,
.ap-hosted-shell-mobile-nav .rz-navigation-item-link .rz-navigation-item-icon {
    color: var(--ap-text-primary) !important;
    -webkit-text-fill-color: var(--ap-text-primary) !important;
}

/* Radzen's desktop PanelMenu icon rule is more specific than the link colour;
   keep this override scoped to the hosted shell so dark rail icons stay legible. */
.ap-hosted-shell-nav:is(#ap-hosted-shell-nav-icon-contrast, .ap-hosted-shell-nav) .ap-hosted-shell-panel-menu.rz-panel-menu .rz-navigation-item-wrapper .rz-navigation-item-link .rz-navigation-item-icon {
    color: var(--ap-text-primary) !important;
    -webkit-text-fill-color: var(--ap-text-primary) !important;
}

.ap-hosted-shell-nav .rz-navigation-item-link:hover,
.ap-hosted-shell-mobile-nav .rz-navigation-item-link:hover {
    background-color: var(--ap-bg-surface);
}

.ap-hosted-shell-nav .rz-navigation-item-link:focus-visible,
.ap-hosted-shell-mobile-nav .rz-navigation-item-link:focus-visible {
    outline: var(--ap-focus-ring-width) solid var(--ap-focus-ring-color);
    outline-offset: var(--ap-focus-ring-offset);
}

.ap-hosted-shell-nav .rz-navigation-item-wrapper-active > .rz-navigation-item-link,
.ap-hosted-shell-mobile-nav .rz-navigation-item-wrapper-active > .rz-navigation-item-link,
.ap-hosted-shell-nav .rz-navigation-item-link.active,
.ap-hosted-shell-mobile-nav .rz-navigation-item-link.active,
.ap-hosted-shell-nav .rz-navigation-item-link[aria-current="page"],
.ap-hosted-shell-mobile-nav .rz-navigation-item-link[aria-current="page"] {
    background-color: var(--ap-action-primary-subtle);
    color: var(--ap-text-primary);
    font-weight: 600;
    border-inline-start-color: var(--ap-action-primary);
}

/* Version + changelog link pinned to the very bottom of the rail. */
.ap-hosted-shell-version {
    margin-top: auto;
    padding: var(--ap-space-2);
    border-top: 1px solid var(--ap-border-default);
}

.ap-hosted-shell-version--mobile {
    margin-top: var(--ap-space-2);
}

.ap-hosted-shell-version-link.rz-link,
.ap-hosted-shell-version-link {
    display: inline-flex;
    align-items: center;
    gap: var(--ap-space-1);
    font-family: var(--ap-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
    font-size: var(--ap-text-xs);
    color: var(--ap-text-secondary);
    text-decoration: none;
}

.ap-hosted-shell-main {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-width: 0;
}

/* Top bar. The Radzen header element carries both .rz-header and this class.
   Radzen's base .rz-header is position:fixed, which pulls the bar out of normal flow so page
   content underlaps it — the first heading of every shell page was occluded by the bar.
   Pin it with position:sticky instead: it stays in normal flow (reserving its own height,
   so content starts below it) AND remains visible on scroll. The two-class selector shares
   the specificity of the background/border overrides above, and this sheet loads after
   Radzen's theme, so it wins the position declaration too. */
.ap-hosted-shell-topbar.rz-header,
.ap-hosted-shell-topbar {
    position: sticky;
    top: 0;
    z-index: 100;
    display: flex;
    align-items: center;
    gap: var(--ap-space-3);
    min-height: var(--ap-header-height, 56px);
    padding: var(--ap-space-2) var(--ap-space-3);
    border-bottom: 1px solid var(--ap-border-default);
    background-color: var(--ap-bg-surface);
}

/* Right-aligned: app switcher first, then the app's own top-bar controls. */
.ap-hosted-shell-topbar-content {
    display: flex;
    align-items: center;
    gap: var(--ap-space-2);
    margin-left: auto;
    min-width: 0;
    max-width: 100%;
    flex-wrap: nowrap;
}

/* Global fallback for the platform's authenticated header island. These rules
   intentionally mirror AppHeader.razor.css so the shell stays coherent even when
   the interactive island hydrates later than the static shell or component-scoped
   CSS is not yet applied. */
.ap-hosted-shell-topbar-content .ap-header-actions {
    display: flex;
    align-items: center;
    gap: var(--ap-space-3);
    min-width: 0;
    flex: 0 1 auto;
    flex-wrap: nowrap;
}

.ap-hosted-shell-topbar-content .ap-language-switcher {
    display: inline-flex;
    align-items: center;
    gap: var(--ap-space-1);
    flex: 0 0 auto;
}

.ap-hosted-shell-topbar-content .ap-lang-form {
    display: inline-flex;
    margin: 0;
}

.ap-hosted-shell-topbar-content .ap-lang-btn[aria-pressed="true"] {
    background: var(--ap-action-primary-bg, var(--ap-primary));
    color: var(--ap-action-primary-text, var(--ap-color-on-accent));
    border-color: var(--ap-action-primary-bg, var(--ap-primary));
    font-weight: 700;
}

.ap-hosted-shell-topbar-content .ap-user-menu {
    flex: 0 0 auto;
}

/* Hamburger is a <label> for the CSS-only drawer toggle. */
.ap-hosted-shell-hamburger {
    display: inline-flex;
    flex-direction: column;
    justify-content: center;
    gap: 4px;
    width: var(--ap-touch-target-min);
    height: var(--ap-touch-target-min);
    background: none;
    border: none;
    cursor: pointer;
    border-radius: var(--ap-radius-sm);
}

.ap-hosted-shell-hamburger:hover {
    background-color: var(--ap-bg-elevated);
}

.ap-hosted-shell-drawer-toggle:focus-visible + .ap-hosted-shell-nav ~ .ap-hosted-shell-main .ap-hosted-shell-hamburger,
.ap-hosted-shell-hamburger:focus-visible {
    outline: var(--ap-focus-ring-width) solid var(--ap-focus-ring-color);
    outline-offset: var(--ap-focus-ring-offset);
}

.ap-hosted-shell-hamburger-line {
    display: block;
    width: 20px;
    height: 2px;
    margin: 0 auto;
    background-color: var(--ap-text-primary);
}

/* Mobile drawer: rendered in-flow (not absolutely positioned) so it pushes content
   rather than overlaying it — no bottom nav is ever part of this shell. Hidden until
   the CSS-only toggle is checked. */
.ap-hosted-shell-mobile-nav {
    display: none;
    flex-direction: column;
    gap: var(--ap-space-3);
    padding: var(--ap-space-3);
    border-bottom: 1px solid var(--ap-border-default);
    background-color: var(--ap-bg-elevated);
}

.ap-hosted-shell-drawer-toggle:checked ~ .ap-hosted-shell-main .ap-hosted-shell-mobile-nav {
    display: flex;
}

.ap-hosted-shell-content {
    flex: 1;
    padding: var(--ap-space-3);
    min-width: 0;
}

@media (min-width: 768px) {
    .ap-hosted-shell-nav.rz-sidebar,
    .ap-hosted-shell-nav {
        display: flex;
    }

    .ap-hosted-shell-hamburger {
        display: none;
    }

    .ap-hosted-shell-mobile-nav,
    .ap-hosted-shell-drawer-toggle:checked ~ .ap-hosted-shell-main .ap-hosted-shell-mobile-nav {
        display: none !important;
    }
}

/* ---------------------------------------------------------------------------
   Ops design-system components (agent-operations-interface KC-01..KC-03)
   Candidate lifecycle — staging-only until contract approval.
   --------------------------------------------------------------------------- */

/* Visually hidden (screen-reader-only) utility */
.ap-visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* KPI tile (kpi-tile) */
.ap-kpi-tile {
    display: flex;
    flex-direction: column;
    gap: var(--ap-space-2);
    min-width: 0;
    min-height: 132px;
    padding: var(--ap-space-4);
    background-color: var(--ap-bg-surface);
    border: 1px solid var(--ap-border-default);
    border-radius: var(--ap-radius-md);
}

.ap-kpi-tile-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--ap-space-2);
}

.ap-kpi-tile-label {
    min-width: 0;
    font-size: var(--ap-text-sm);
    color: var(--ap-text-secondary);
    overflow-wrap: anywhere;
}

.ap-kpi-tile-state-icon {
    color: var(--ap-text-primary);
}

.ap-kpi-tile-value {
    font-size: var(--ap-text-2xl);
    font-weight: 600;
    color: var(--ap-text-primary);
}

.ap-kpi-tile-value-muted {
    color: var(--ap-text-primary);
}

.ap-kpi-tile-unit {
    margin-left: var(--ap-space-1);
    font-size: var(--ap-text-sm);
    font-weight: 400;
    color: var(--ap-text-secondary);
}

.ap-kpi-tile-state-text {
    font-size: var(--ap-text-sm);
    color: var(--ap-text-secondary);
}

.ap-kpi-tile-state-degraded {
    color: var(--ap-text-primary);
    font-weight: 600;
}

.ap-kpi-tile-skeleton {
    display: flex;
    flex-direction: column;
    gap: var(--ap-space-2);
}

.ap-kpi-tile-skeleton-bar {
    border-radius: var(--ap-radius-sm);
    background-color: var(--ap-bg-elevated);
}

.ap-kpi-tile-skeleton-value {
    width: 60%;
    height: var(--ap-space-6);
}

.ap-kpi-tile-skeleton-trend {
    width: 100%;
    height: var(--ap-space-4);
}

.ap-kpi-tile-drill {
    align-self: flex-end;
    margin-top: auto;
    padding: 0;
    border: 0;
    background: none;
    font-size: var(--ap-text-xs);
    color: var(--ap-text-primary);
    font-weight: 600;
    text-decoration: none;
    cursor: pointer;
}

.ap-kpi-tile-drill:hover {
    text-decoration: underline;
}

.ap-kpi-tile-drill:focus-visible {
    outline: var(--ap-focus-ring-width) solid var(--ap-focus-ring-color);
    outline-offset: var(--ap-focus-ring-offset);
}

/* KPI trend sparkline (kpi-trend-chart) */
.ap-kpi-trend {
    display: block;
    width: 100%;
    height: 28px;
}

.ap-kpi-trend-svg {
    display: block;
    width: 100%;
    height: 28px;
}

.ap-kpi-trend-line {
    fill: none;
    stroke: var(--ap-action-primary);
    stroke-width: 2px;
    stroke-linejoin: round;
    stroke-linecap: round;
}

.ap-kpi-trend-empty {
    display: block;
    height: 28px;
    font-size: var(--ap-text-xs);
    color: var(--ap-text-secondary);
    overflow-wrap: anywhere;
}

/* Approval decision card (approval-card) */
.ap-approval-card {
    display: flex;
    flex-direction: column;
    gap: var(--ap-space-3);
    padding: var(--ap-space-4);
    background-color: var(--ap-bg-surface);
    border: 1px solid var(--ap-border-default);
    border-radius: var(--ap-radius-md);
    box-shadow: var(--ap-shadow-sm);
}

.ap-approval-card-header {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--ap-space-2);
}

.ap-approval-card-risk {
    display: inline-flex;
    align-items: center;
    gap: var(--ap-space-1);
    padding: 2px var(--ap-space-2);
    border-radius: var(--ap-radius-sm);
    border: 1px solid var(--ap-border-default);
    font-size: var(--ap-text-xs);
    font-weight: 600;
    text-transform: uppercase;
    color: var(--ap-text-primary);
}

.ap-approval-card-risk-high .ap-approval-card-risk-icon {
    color: var(--ap-text-primary);
}

.ap-approval-card-risk-medium .ap-approval-card-risk-icon {
    color: var(--ap-semantic-warning);
}

.ap-approval-card-risk-low .ap-approval-card-risk-icon {
    color: var(--ap-semantic-info);
}

.ap-approval-card-title {
    font-size: var(--ap-text-base);
    font-weight: 600;
    color: var(--ap-text-primary);
    overflow-wrap: anywhere;
}

.ap-approval-card-facts {
    display: flex;
    flex-direction: column;
    gap: var(--ap-space-1);
    margin: 0;
}

.ap-approval-card-fact {
    display: flex;
    gap: var(--ap-space-2);
    min-width: 0;
    font-size: var(--ap-text-sm);
}

.ap-approval-card-fact dt {
    min-width: 88px;
    color: var(--ap-text-secondary);
}

.ap-approval-card-fact dd {
    min-width: 0;
    margin: 0;
    color: var(--ap-text-primary);
    overflow-wrap: anywhere;
}

.ap-approval-card-identity-class,
.ap-approval-card-target-resource {
    color: var(--ap-text-primary);
}

.ap-approval-card-args summary {
    cursor: pointer;
    font-size: var(--ap-text-sm);
    color: var(--ap-text-secondary);
}

.ap-approval-card-args summary:focus-visible {
    outline: var(--ap-focus-ring-width) solid var(--ap-focus-ring-color);
    outline-offset: var(--ap-focus-ring-offset);
}

.ap-approval-card-args-json {
    margin: var(--ap-space-2) 0 0;
    padding: var(--ap-space-2);
    background-color: var(--ap-bg-elevated);
    border-radius: var(--ap-radius-sm);
    font-size: var(--ap-text-xs);
    box-sizing: border-box;
    max-width: 100%;
    overflow-x: hidden;
    overflow-wrap: anywhere;
    white-space: normal;
    word-break: break-all;
}

.ap-approval-card-status {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--ap-space-2);
    margin: 0;
    font-size: var(--ap-text-sm);
    color: var(--ap-text-primary);
}

.ap-approval-card-state-approved .ap-approval-card-status-icon {
    color: var(--ap-semantic-success);
}

.ap-approval-card-state-rejected .ap-approval-card-status-icon {
    color: var(--ap-text-primary);
}

.ap-approval-card-outcome,
.ap-approval-card-reason {
    color: var(--ap-text-primary);
}

.ap-approval-card-busy {
    width: var(--ap-space-3);
    height: var(--ap-space-3);
    border: 2px solid var(--ap-border-default);
    border-top-color: var(--ap-action-primary);
    border-radius: var(--ap-radius-full);
    animation: ap-approval-card-spin 0.9s linear infinite;
}

@keyframes ap-approval-card-spin {
    to {
        transform: rotate(360deg);
    }
}

.ap-approval-card-actions {
    display: flex;
    align-items: stretch;
    flex-wrap: wrap;
    gap: var(--ap-space-2);
    justify-content: flex-end;
}

.ap-approval-card-action-slot {
    display: flex;
    flex: 1 1 0;
    min-width: 0;
}

.ap-approval-card-btn {
    width: 100%;
    min-height: var(--ap-touch-target-min);
    padding: var(--ap-space-2) var(--ap-space-4);
    border: 1px solid var(--ap-border-default);
    border-radius: var(--ap-radius-md);
    font-size: var(--ap-text-sm);
    font-weight: 600;
    cursor: pointer;
    transition: opacity var(--ap-motion-duration-fast) var(--ap-motion-ease-standard);
}

.ap-approval-card-btn:hover:not(:disabled) {
    opacity: var(--ap-state-hover-opacity);
}

.ap-approval-card-btn:focus-visible {
    outline: var(--ap-focus-ring-width) solid var(--ap-focus-ring-color);
    outline-offset: var(--ap-focus-ring-offset);
}

.ap-approval-card-btn:disabled {
    opacity: var(--ap-state-disabled-opacity);
    cursor: not-allowed;
}

.ap-approval-card-btn-approve {
    background-color: var(--ap-action-primary-bg);
    border-color: var(--ap-action-primary-bg);
    color: var(--ap-action-primary-text);
}

.ap-approval-card-btn-reject {
    background-color: var(--ap-bg-surface);
    color: var(--ap-text-primary);
}

@media (min-width: 48em) {
    .ap-approval-card-actions {
        justify-content: flex-end;
    }

    .ap-approval-card-btn {
        width: auto;
    }

    .ap-approval-card-action-slot {
        flex: 0 0 auto;
        width: auto;
    }
}

@media (max-width: 40rem) {
    .ap-approval-card-actions {
        justify-content: stretch;
    }

    .ap-approval-card-fact {
        flex-direction: column;
        gap: var(--ap-space-1);
    }

    .ap-approval-card-fact dt {
        min-width: 0;
    }
}

/* Show-once token reveal (token-once-dialog) */
.ap-token-once {
    display: flex;
    flex-direction: column;
    gap: var(--ap-space-3);
    max-width: 35em;
    padding: var(--ap-space-4);
    background-color: var(--ap-bg-surface);
    border: 1px solid var(--ap-border-default);
    border-radius: var(--ap-radius-md);
}

.ap-token-once-warning {
    display: flex;
    gap: var(--ap-space-2);
    padding: var(--ap-space-3);
    background-color: var(--ap-bg-elevated);
    border-left: 3px solid var(--ap-semantic-warning);
    border-radius: var(--ap-radius-sm);
}

.ap-token-once-warning-icon {
    color: var(--ap-warning-text, var(--ap-text-primary));
    flex: 0 0 auto;
}

.ap-token-once-warning-body p {
    margin: var(--ap-space-1) 0 0;
    font-size: var(--ap-text-sm);
    color: var(--ap-text-secondary);
}

.ap-token-once-token-label {
    font-size: var(--ap-text-sm);
    color: var(--ap-text-secondary);
}

.ap-token-once-token-row {
    display: flex;
    align-items: stretch;
    flex-wrap: wrap;
    gap: var(--ap-space-2);
}

.ap-token-once-token {
    flex: 1;
    padding: var(--ap-space-2) var(--ap-space-3);
    background-color: var(--ap-bg-elevated);
    border: 1px solid var(--ap-border-default);
    border-radius: var(--ap-radius-sm);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: var(--ap-text-sm);
    color: var(--ap-text-primary);
    overflow-wrap: anywhere;
    user-select: all;
}

.ap-token-once-copied {
    display: flex;
    align-items: center;
    gap: var(--ap-space-1);
    min-height: var(--ap-space-4);
    margin: 0;
    font-size: var(--ap-text-sm);
    color: var(--ap-text-primary);
}

.ap-token-once-copied-icon {
    color: var(--ap-semantic-success);
}

.ap-token-once-hint {
    margin: 0;
    font-size: var(--ap-text-sm);
    color: var(--ap-text-secondary);
}

.ap-token-once-path {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    color: var(--ap-text-primary);
    overflow-wrap: anywhere;
}

.ap-token-once-ack {
    display: flex;
    align-items: center;
    gap: var(--ap-space-2);
    font-size: var(--ap-text-sm);
    color: var(--ap-text-primary);
    cursor: pointer;
}

.ap-token-once-ack input:focus-visible {
    outline: var(--ap-focus-ring-width) solid var(--ap-focus-ring-color);
    outline-offset: var(--ap-focus-ring-offset);
}

.ap-token-once-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: var(--ap-space-2);
}

.ap-token-once-btn {
    min-height: var(--ap-touch-target-min);
    max-width: 100%;
    padding: var(--ap-space-2) var(--ap-space-4);
    border: 1px solid var(--ap-border-default);
    border-radius: var(--ap-radius-md);
    font-size: var(--ap-text-sm);
    font-weight: 600;
    cursor: pointer;
    transition: opacity var(--ap-motion-duration-fast) var(--ap-motion-ease-standard);
    white-space: normal;
}

.ap-token-once-btn:hover:not(:disabled) {
    opacity: var(--ap-state-hover-opacity);
}

.ap-token-once-btn:focus-visible {
    outline: var(--ap-focus-ring-width) solid var(--ap-focus-ring-color);
    outline-offset: var(--ap-focus-ring-offset);
}

.ap-token-once-btn:disabled {
    opacity: var(--ap-state-disabled-opacity);
    cursor: not-allowed;
}

.ap-token-once-btn-copy {
    background-color: var(--ap-bg-surface);
    color: var(--ap-text-primary);
}

.ap-token-once-btn-close {
    background-color: var(--ap-action-primary-bg);
    border-color: var(--ap-action-primary-bg);
    color: var(--ap-action-primary-text);
}
