/* Portal-local design tokens. Kept here (not in the shared theme.css) because
   they're only used by Portal pages. Promote to the RCL tokens if Admin grows
   the same need. */
:root {
    --border-radius-pill: 9999px;
    /* Matches xterm.js's default theme background so the wrapper padding gap
       around the terminal canvas isn't a different color. */
    --color-terminal-bg: #000;
    --color-terminal-fg-rgb: 255, 255, 255;

    /* Channel rail palette — deterministic per-channel accents picked by the
       ChannelRail component via djb2(slug) % 10. Stays here (Portal-local) until
       channel colors get a first-class admin affordance. */
    --portal-channel-color-0: #2C7BE5;
    --portal-channel-color-1: #5B5BD6;
    --portal-channel-color-2: #1F8A5B;
    --portal-channel-color-3: #E07A17;
    --portal-channel-color-4: #9333EA;
    --portal-channel-color-5: #0E9384;
    --portal-channel-color-6: #D946A4;
    --portal-channel-color-7: #475569;
    --portal-channel-color-8: #DC2A56;
    --portal-channel-color-9: #B45309;
}


/* ── Page shell background ──────────────────────────────────────────── */

/* Layered on top of the shared .app-shell to give Portal pages the branded
   workspace background. Shell layout (column flex, viewport height) lives in
   components.css; this class only contributes the background image. */
.portal-shell {
    background:
        url('/images/background.png') center / cover no-repeat fixed,
        var(--color-background);
}

/* Asset URL swap (STYLEGUIDE §6.7.2). The two background images live in this
   project, so there's no shared token in theme.css to flip — only asset URL
   swaps may use [data-theme="dark"] in project CSS. */
[data-theme="dark"] .portal-shell {
    background:
        url('/images/background-dark.jpg') center / cover no-repeat fixed,
        var(--color-background);
}

.portal-kicker {
    display: block;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

/* ── Right-click context menu ───────────────────────────────────────── */

.ctx-target {
    display: contents;
}

.portal-ctx-menu__backdrop {
    position: fixed;
    inset: 0;
    z-index: 300;
    cursor: default;
}

.portal-ctx-menu {
    position: fixed;
    z-index: 301;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--border-radius-md);
    box-shadow: var(--shadow-md);
    padding: var(--spacing-xs) 0;
    list-style: none;
    margin: 0;
    min-width: 180px;
    max-width: 260px;
}

.portal-ctx-menu__item {
    display: block;
    padding: var(--spacing-xs) var(--spacing-md);
    color: var(--color-text-primary);
    text-decoration: none;
    font-size: var(--font-size-base);
    white-space: nowrap;
}

.portal-ctx-menu__item:hover,
.portal-ctx-menu__item:focus {
    background: var(--color-surface-hover);
    color: var(--color-text-primary);
    outline: none;
}

.portal-ctx-menu__sep {
    height: 1px;
    background: var(--color-border);
    margin: var(--spacing-xs) 0;
}

/* Radzen Dialog.Confirm button styling per STYLEGUIDE §3.4.2. ConfirmOptions
   has no per-button style prop, so callers tag the dialog via CssClass and
   we restyle the primary button. Untagged confirms keep the default primary. */
.rz-dialog-confirm.confirm-danger .rz-button.rz-primary {
    background-color: var(--rz-danger) !important;
    color: #fff !important;
}
.rz-dialog-confirm.confirm-danger .rz-button.rz-primary:hover,
.rz-dialog-confirm.confirm-danger .rz-button.rz-primary:focus {
    background-color: var(--rz-danger-dark) !important;
}
.rz-dialog-confirm.confirm-danger .rz-button.rz-primary:focus-visible {
    outline-color: var(--rz-danger) !important;
}

/* ── Main + card container ──────────────────────────────────────────── */

/* Centered max-width column for Portal pages. Sits inside .app-shell__main,
   which already supplies the scroll/padding chrome — this just constrains the
   content width so workspace pages don't sprawl on wide screens. */
.portal-main {
    width: 100%;
    max-width: 1200px;
    margin: 0 auto;
}

.workspace-shell {
    display: grid;
    gap: var(--spacing-md);
}

/* ── Workspaces overview ───────────────────────────────────────────────── */

.workspace-page__header {
    margin: 0 0 var(--spacing-2xl);
}

.workspace-page__title {
    margin: 0 0 var(--spacing-xs);
    font-size: var(--font-size-2xl);
    font-weight: var(--font-weight-semibold);
    color: var(--color-text-primary);
}

.workspace-page__subtitle {
    margin: 0;
    font-size: var(--font-size-base);
    color: var(--color-text-secondary);
}

/* Vertical stack of workspace rows on the picker page. Sits inside
   .portal-main, which already constrains overall width; the cap here keeps
   each row from getting unreadably wide on large displays. */
.workspace-list {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-md);
    max-width: 960px;
}

/* Workspace row — destination, not feature description. Whole row is the
   click target. Three columns: 56 px icon tile, flexible body, trailing
   aside (Open → on hover). min-height locks the row so sparse content
   (no summary, no apps) doesn't render a half-height row next to a full one. */
.workspace-tile {
    display: grid;
    grid-template-columns: 56px 1fr auto;
    align-items: center;
    gap: var(--spacing-lg);
    min-height: 112px;
    padding: var(--spacing-lg) var(--spacing-xl);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--border-radius-md);
    box-shadow: var(--shadow-sm);
    color: inherit;
    text-decoration: none;
    transition:
        border-color var(--transition-fast),
        box-shadow var(--transition-fast),
        transform var(--transition-fast);
}

.workspace-tile:hover,
.workspace-tile:focus-visible {
    border-color: var(--color-primary);
    box-shadow: var(--shadow-md);
    color: inherit;
    text-decoration: none;
    outline: none;
    transform: translateY(-1px);
}

.workspace-tile:hover .workspace-tile__open,
.workspace-tile:focus-visible .workspace-tile__open {
    opacity: 1;
    transform: translateX(0);
}

/* 56 px icon tile — fixed-size left column. Holds the FA glyph, the
   workspace's uploaded logo, or its background image (with optional logo
   overlay). Sized identically across all tiles so the left edge aligns
   row-to-row regardless of which branding assets a workspace has. */
.workspace-tile__icon-tile {
    position: relative;
    display: grid;
    place-items: center;
    width: 56px;
    height: 56px;
    border-radius: var(--border-radius-md);
    background:
        linear-gradient(135deg,
            rgba(var(--color-primary-rgb), 0.10) 0%,
            rgba(var(--color-primary-rgb), 0.20) 100%);
    color: var(--color-primary);
    overflow: hidden;
}

.workspace-tile__icon-tile--branded {
    background-size: cover;
    background-position: center;
}

/* Scrim above a branded background image so an overlaid logo stays legible
   regardless of the image's contrast. */
.workspace-tile__icon-tile--branded::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg,
        rgba(0, 0, 0, 0) 30%,
        rgba(0, 0, 0, 0.25));
}

.workspace-tile__icon-glyph {
    font-size: var(--font-size-2xl);
    line-height: 1;
}

.workspace-tile__icon-logo {
    position: relative;
    z-index: 1;
    max-width: 70%;
    max-height: 70%;
    object-fit: contain;
}

.workspace-tile__body {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: var(--spacing-xs);
}

.workspace-tile__name {
    margin: 0;
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-semibold);
    line-height: 1.3;
    color: var(--color-text-primary);
}

/* Single-line clamp on the summary — long descriptions ellipsize rather than
   wrapping and pushing the apps row downward, so rows stay aligned in the
   stack. */
.workspace-tile__summary {
    margin: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    font-size: var(--font-size-sm);
    color: var(--color-text-secondary);
}

.workspace-tile__apps {
    display: flex;
    align-items: center;
    gap: var(--spacing-md);
    margin-top: var(--spacing-xs);
}

.workspace-tile__app-icons {
    display: flex;
    align-items: center;
    gap: var(--spacing-xs);
    flex-wrap: nowrap;
    flex-shrink: 0;
}

.workspace-tile__app-icon {
    width: 26px;
    height: 26px;
    object-fit: contain;
    border-radius: var(--border-radius-sm);
    background: var(--color-surface-hover);
    border: 1px solid var(--color-border);
}

.workspace-tile__app-more {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 26px;
    height: 26px;
    padding: 0 var(--spacing-xs);
    border: 1px dashed var(--color-border-dark);
    border-radius: var(--border-radius-sm);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    color: var(--color-text-secondary);
    white-space: nowrap;
    line-height: 1;
}

.workspace-tile__app-count {
    font-size: var(--font-size-sm);
    color: var(--color-text-secondary);
    font-variant-numeric: tabular-nums;
}

.workspace-tile__app-count strong {
    color: var(--color-text-primary);
    font-weight: var(--font-weight-semibold);
}

.workspace-tile__aside {
    display: flex;
    align-items: center;
    justify-self: end;
}

/* "Open →" affordance — hidden until the row is hovered or focused, then
   slides in from the left. */
.workspace-tile__open {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-xs);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
    color: var(--color-link);
    opacity: 0;
    transform: translateX(-4px);
    transition:
        opacity var(--transition-fast),
        transform var(--transition-fast);
}

@media (max-width: 720px) {
    .workspace-tile {
        grid-template-columns: 56px 1fr;
        gap: var(--spacing-md);
        padding: var(--spacing-md);
    }
    .workspace-tile__aside {
        display: none;
    }
}

/* Bootstrap's .card already handles surface background, border, and radius.
   The modifiers below extend it with Portal-specific layout and visual variants. */

/* Fill-height variant — card grows to fill most of the viewport rather than
   shrinking to content size, so single-card pages (Applications, Files, Links)
   don't leave a large gap of empty watermark below sparse content. */
.card--fill {
    min-height: calc(100vh - 220px);
}

/* Tall variant — enough room for ~2 rows of tiles (142px icon tile × 2 +
   60px chrome = 344px). Keeps sparse Home apps/files sections substantial. */
.card--tall {
    min-height: 344px;
}

/* Narrow variant — centered, max-width reading column. */
.card--narrow {
    max-width: 48rem;
    margin-left: auto;
    margin-right: auto;
}

.card + .card {
    margin-top: var(--spacing-lg);
}

/* Hero variant — primary-tinted gradient wash over the surface. */
.card--hero {
    background:
        linear-gradient(135deg, rgba(var(--color-primary-rgb), 0.08), transparent 40%),
        var(--color-surface);
}

/* Subtle variant: translucent surface, no border, no shadow. The panel reads
   as a bounded container but the watermark shows through, keeping it quieter
   than the opaque card it sits next to. Used on WorkspaceHome's apps section
   to differentiate from the solid files section below it. */
.card--subtle {
    background: color-mix(in srgb, var(--color-surface) 40%, transparent);
    border-color: transparent;
    box-shadow: none;
}

.portal-copy,
.portal-note {
    color: var(--color-text-secondary);
}

/* ── Tile grid ──────────────────────────────────────────────────────── */

.portal-grid {
    display: grid;
    /* Cap tile width near the natural content height (icon + label + padding ≈ 110px)
       so tiles read as compact squares instead of wide rectangles. */
    grid-template-columns: repeat(auto-fill, minmax(110px, 130px));
    gap: var(--spacing-lg);
    margin: var(--spacing-md) 0 0;
    justify-content: start;
}

.portal-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    text-align: center;
    border: 1px solid transparent;
    border-radius: var(--border-radius-md);
    padding: var(--spacing-lg) var(--spacing-sm);
    color: inherit;
    text-decoration: none;
    transition: border-color 0.15s ease, background 0.15s ease;
}

.portal-tile h3 {
    margin: 0;
    font-size: var(--font-size-base);
    font-weight: 500;
    color: var(--color-text-primary);
}

.portal-tile p {
    margin: var(--spacing-xs) 0 0;
    font-size: var(--font-size-sm);
    color: var(--color-text-secondary);
}

a.portal-tile {
    cursor: pointer;
}

a.portal-tile:hover,
a.portal-tile:focus {
    border-color: var(--color-border);
    background: var(--color-surface-hover);
    outline: none;
}

/* ── Tile icons ─────────────────────────────────────────────────────── */

.portal-workspace-tile__icon {
    display: block;
    font-size: var(--font-size-4xl);
    color: var(--color-text-tertiary);
    margin-bottom: var(--spacing-sm);
    line-height: 1;
}

.portal-app-tile__icon {
    display: block;
    width: 3rem;
    height: 3rem;
    object-fit: contain;
    margin-bottom: var(--spacing-sm);
}

.portal-app-tile__icon-fallback {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 3rem;
    height: 3rem;
    margin-bottom: var(--spacing-sm);
    font-size: 2rem;
    color: var(--color-text-tertiary);
    line-height: 1;
}

/* ── Link list ──────────────────────────────────────────────────────── */

.portal-link-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--spacing-xs);
}

/* Tile-style row: 60px tall, icon + title, border on hover (matches legacy
   `.dashboard-item-tile`). */
.portal-link-list__item {
    display: flex;
    align-items: center;
    gap: var(--spacing-sm);
    padding: var(--spacing-sm);
    height: 60px;
    border: 1px solid transparent;
    border-radius: var(--border-radius-sm);
}

.portal-link-list__item:hover {
    border-color: var(--color-border);
    background: var(--color-surface-hover);
}

.portal-link-list__icon {
    width: 40px;
    height: 40px;
    object-fit: contain;
    flex-shrink: 0;
}

.portal-link-list__anchor {
    color: var(--color-text-primary);
    text-decoration: none;
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.portal-link-list__anchor:hover {
    color: var(--color-primary);
    text-decoration: underline;
}

/* ── Actions / banners ──────────────────────────────────────────────── */

.portal-actions {
    display: flex;
    gap: var(--spacing-md);
    flex-wrap: wrap;
}

.portal-actions--top-spaced {
    margin-top: var(--spacing-lg);
}

.portal-banner {
    margin-top: var(--spacing-md);
    padding: var(--spacing-sm) var(--spacing-md);
    border-radius: var(--border-radius-md);
    background: rgba(var(--color-primary-rgb), 0.12);
    color: var(--color-primary);
}

/* ── Status / badges / timeline ─────────────────────────────────────── */

.portal-status-row {
    display: flex;
    gap: var(--spacing-md);
    align-items: center;
    flex-wrap: wrap;
    margin: var(--spacing-lg) 0;
}

.portal-status-badge {
    display: inline-flex;
    align-items: center;
    min-height: 2rem;
    padding: 0 var(--spacing-md);
    border-radius: var(--border-radius-pill);
    font-weight: 600;
    background: rgba(var(--color-primary-rgb), 0.12);
    color: var(--color-primary);
}

.portal-status-badge--accent {
    background: rgba(var(--color-primary-rgb), 0.12);
    color: var(--color-primary);
}

.portal-status-badge--success {
    background: rgba(var(--color-success-rgb), 0.12);
    color: var(--color-success);
}

.portal-status-badge--warning {
    background: rgba(var(--color-warning-rgb), 0.16);
    color: var(--color-warning);
}

.portal-status-badge--danger {
    background: rgba(var(--color-error-rgb), 0.12);
    color: var(--color-error);
}

.portal-status-badge--muted {
    background: var(--color-surface-hover);
    color: var(--color-text-secondary);
}

.portal-timeline {
    display: grid;
    gap: var(--spacing-md);
    margin-top: var(--spacing-lg);
}

.portal-timeline__item {
    border: 1px solid var(--color-border);
    border-radius: var(--border-radius-md);
    padding: var(--spacing-md);
    background: var(--color-surface);
}

.portal-timeline__header {
    display: flex;
    justify-content: space-between;
    gap: var(--spacing-md);
    align-items: center;
    margin-bottom: var(--spacing-sm);
}

/* ── Session panel ──────────────────────────────────────────────────── */

.portal-session-panel {
    position: fixed;
    right: var(--spacing-xl);
    bottom: var(--spacing-xl);
    width: min(48rem, calc(100vw - 22rem));
    max-height: min(70vh, 42rem);
    display: grid;
    grid-template-rows: auto 1fr auto;
    gap: var(--spacing-sm);
    padding: var(--spacing-lg);
    border: 1px solid var(--color-border);
    border-radius: var(--border-radius-lg);
    background: var(--color-surface);
    box-shadow: var(--shadow-lg);
    z-index: 50;
}

.portal-session-panel--page {
    position: static;
    width: 100%;
    min-width: 0;
    max-height: none;
    height: calc(100vh - 8rem);
    box-shadow: none;
    border-radius: var(--border-radius-md);
}

.portal-session-panel__header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--spacing-md);
}

.portal-session-panel__title {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.portal-session-panel__actions {
    display: flex;
    align-items: center;
    gap: var(--spacing-sm);
    flex-wrap: wrap;
    justify-content: end;
}

.portal-session-panel__meta {
    color: var(--color-text-secondary);
    font-size: var(--font-size-base);
}

/* Flex wrapper that sits in the 1fr grid row, holding either the terminal surface
   or the RDP-handoff panel. */
.portal-session-panel__content {
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;
    /* min-width:0 lets flex children shrink past their content size — without it,
       a wide xterm row or long unbroken status line would push the column wider
       than the panel and trigger a page-level horizontal scrollbar. */
    min-width: 0;
    overflow: hidden;
}

.portal-session-panel__content .portal-terminal-surface {
    flex: 1;
    min-height: 0;
    min-width: 0;
}

.portal-terminal-surface {
    /* position:relative scopes the loading overlay's position:absolute box to
       the terminal surface, so the overlay fills the same rectangle xterm
       draws into and not the page. */
    position: relative;
    padding: var(--spacing-md);
    border-radius: var(--border-radius-md);
    border: 1px solid var(--color-border);
    background: var(--color-terminal-bg);
    overflow: hidden;
}

/* Pre-connect loading state inside the terminal surface. */
.portal-terminal-loading {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--color-terminal-bg);
    border-radius: var(--border-radius-md);
    z-index: 1;
}

.portal-terminal-loading__card {
    width: min(28rem, calc(100% - 2 * var(--spacing-xl)));
    text-align: center;
    color: rgba(var(--color-terminal-fg-rgb), 0.92);
}

.portal-terminal-loading__progress {
    width: 100%;
    height: 4px;
    background: rgba(var(--color-terminal-fg-rgb), 0.08);
    border-radius: var(--border-radius-pill);
    overflow: hidden;
    margin-bottom: var(--spacing-lg);
}

.portal-terminal-loading__progress-bar {
    height: 100%;
    width: 30%;
    background: linear-gradient(
        90deg,
        rgba(var(--color-primary-rgb), 0)   0%,
        rgba(var(--color-primary-rgb), 1)  50%,
        rgba(var(--color-primary-rgb), 0) 100%
    );
    border-radius: var(--border-radius-pill);
    animation: portal-terminal-loading-shimmer 1.8s ease-in-out infinite;
}

@keyframes portal-terminal-loading-shimmer {
    0%   { transform: translateX(-110%); }
    100% { transform: translateX(440%); }
}

.portal-terminal-loading__title {
    font-size: var(--font-size-xl);
    font-weight: var(--font-weight-semibold);
    margin: 0 0 var(--spacing-sm);
    color: rgba(var(--color-terminal-fg-rgb), 0.96);
    animation: portal-terminal-loading-pulse 2.4s ease-in-out infinite;
}

.portal-terminal-loading__subtitle {
    font-size: var(--font-size-base);
    color: rgba(var(--color-terminal-fg-rgb), 0.62);
    margin: 0;
}

@keyframes portal-terminal-loading-pulse {
    0%, 100% { opacity: 0.92; }
    50%      { opacity: 0.72; }
}

.portal-terminal-loading--error .portal-terminal-loading__progress-bar {
    animation: none;
    width: 100%;
    background: rgba(var(--color-error-rgb), 0.55);
}

.portal-terminal-loading--error .portal-terminal-loading__title {
    animation: none;
    color: rgba(var(--color-error-rgb), 1);
}

@media (prefers-reduced-motion: reduce) {
    .portal-terminal-loading__progress-bar {
        animation: none;
        width: 100%;
        opacity: 0.6;
    }
    .portal-terminal-loading__title {
        animation: none;
    }
}

/* Remote-Desktop tab body — sits below the tab strip when active. Padding above
   matches the tab bar's bottom; flex:1 fills the same row the terminal would,
   so switching tabs doesn't change the panel's vertical real estate. */
.portal-rdp-handoff {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-md);
    flex: 1;
    min-height: 0;
    min-width: 0;
    padding: var(--spacing-md) 0 0;
    overflow-y: auto;
}

.portal-rxp-frame {
    flex: 1;
    min-height: 24rem;
    width: 100%;
    border: 1px solid var(--color-border);
    border-radius: var(--border-radius-md);
    background: #333;
}

.portal-rdp-fallback {
    flex: 0 0 auto;
    padding: 0 var(--spacing-xs) var(--spacing-xs);
    color: var(--color-text-secondary);
}

.portal-rdp-fallback summary {
    cursor: pointer;
    font-weight: var(--font-weight-semibold);
    color: var(--color-text-primary);
}

.portal-rdp-fallback[open] {
    padding: var(--spacing-md);
    border: 1px solid var(--color-border);
    border-radius: var(--border-radius-md);
}

.portal-rdp-fallback[open] summary {
    margin-bottom: var(--spacing-md);
}

.portal-diagnostics-surface {
    flex: 1;
    min-height: 0;
    min-width: 0;
    padding-top: var(--spacing-md);
}

.portal-diagnostics {
    display: grid;
    grid-template-rows: auto 1fr;
    gap: var(--spacing-sm);
    min-height: 0;
    height: 100%;
}

.portal-diagnostics__toolbar {
    display: flex;
    align-items: center;
    gap: var(--spacing-sm);
    flex-wrap: wrap;
}

.portal-diagnostics__filter {
    width: auto;
    min-width: 8rem;
}

.portal-diagnostics__search {
    flex: 1;
    min-width: 12rem;
}

.portal-diagnostics__count {
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

.portal-diagnostics__stream {
    min-height: 0;
    overflow: auto;
    border: 1px solid var(--color-border);
    border-radius: var(--border-radius-md);
    background: var(--color-surface);
}

.portal-diagnostics__empty {
    padding: var(--spacing-lg);
    color: var(--color-text-secondary);
}

.portal-diagnostics__row {
    display: grid;
    grid-template-columns: 4.5rem 4.5rem minmax(8rem, 12rem) minmax(0, 1fr);
    gap: var(--spacing-sm);
    align-items: baseline;
    padding: var(--spacing-sm) var(--spacing-md);
    border-bottom: 1px solid var(--color-border);
    font-size: var(--font-size-sm);
}

.portal-diagnostics__row:last-child {
    border-bottom: 0;
}

.portal-diagnostics__time,
.portal-diagnostics__source {
    color: var(--color-text-secondary);
}

.portal-diagnostics__time,
.portal-diagnostics__source,
.portal-diagnostics__message {
    min-width: 0;
}

.portal-diagnostics__source,
.portal-diagnostics__message span {
    overflow-wrap: anywhere;
}

.portal-diagnostics__level {
    font-weight: var(--font-weight-semibold);
}

.portal-diagnostics__level--error {
    color: var(--color-error);
}

.portal-diagnostics__level--warning {
    color: var(--color-warning);
}

.portal-diagnostics__level--info {
    color: var(--color-info);
}

.portal-diagnostics__message {
    display: grid;
    gap: var(--spacing-xs);
}

.portal-diagnostics__message strong {
    color: var(--color-text-primary);
}

.portal-terminal-surface .xterm {
    padding: var(--spacing-md);
}

.portal-session-chip {
    position: fixed;
    right: var(--spacing-xl);
    bottom: var(--spacing-xl);
    border: 1px solid rgba(var(--color-primary-rgb), 0.24);
    border-radius: var(--border-radius-pill);
    background: var(--color-surface);
    color: var(--color-primary);
    font: inherit;
    padding: var(--spacing-sm) var(--spacing-md);
    box-shadow: var(--shadow-md);
    z-index: 50;
    cursor: pointer;
}

@media (max-width: 900px) {
    .portal-session-panel {
        left: var(--spacing-md);
        right: var(--spacing-md);
        bottom: var(--spacing-md);
        width: auto;
        max-height: 60vh;
    }

    .portal-session-chip {
        right: var(--spacing-md);
        bottom: var(--spacing-md);
    }

    .portal-diagnostics__row {
        grid-template-columns: 4.5rem 4rem minmax(0, 1fr);
    }

    .portal-diagnostics__source {
        display: none;
    }
}

.portal-facts {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: var(--spacing-md) var(--spacing-lg);
    margin: 0;
}

.portal-facts dt {
    font-size: var(--font-size-sm);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--color-text-secondary);
}

.portal-facts dd {
    margin: var(--spacing-xs) 0 0;
}

/* ── Login / settings ───────────────────────────────────────────────── */

.login-shell {
    min-height: 100vh;
    display: grid;
    place-items: center;
    padding: var(--spacing-xl);
    background: var(--color-background);
}

.login-main {
    width: min(100%, 48rem);
}

/* ── File browser shell ─────────────────────────────────────────────── */

/* Card flips out of Bootstrap's default `.card-body` padding so the breadcrumb
   bar, toolbar, and list can each own their own gutters and bottom borders. */
.portal-files {
    padding: 0;
    overflow: hidden;
}

.portal-files__head {
    position: relative;
    padding: var(--spacing-md) var(--spacing-xl);
    border-bottom: 1px solid var(--color-border);
}

/* Top indeterminate progress bar — sits flush on the breadcrumb header's
   bottom edge so it feels like the divider itself is animating. Toggled by
   `is-on` so transitions can fade it in/out without the slide animation
   restarting. */
.portal-files__progress {
    position: absolute;
    left: 0;
    right: 0;
    bottom: -1px;
    height: 2px;
    overflow: hidden;
    pointer-events: none;
    opacity: 0;
    transition: opacity var(--transition-fast);
}

.portal-files__progress.is-on {
    opacity: 1;
}

.portal-files__progress-fill {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 40%;
    background: linear-gradient(
        90deg,
        transparent,
        var(--color-primary) 30%,
        var(--color-primary-light) 50%,
        var(--color-primary) 70%,
        transparent);
    border-radius: 2px;
    animation: portal-files-progress-slide 1.4s cubic-bezier(0.4, 0, 0.2, 1) infinite;
}

@keyframes portal-files-progress-slide {
    0%   { left: -40%; }
    100% { left: 100%; }
}

@media (prefers-reduced-motion: reduce) {
    .portal-files__progress-fill { animation: none; left: 0; width: 100%; opacity: 0.4; }
}

.portal-files__breadcrumb {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--spacing-xs);
    font-size: var(--font-size-base);
    color: var(--color-text-secondary);
}

.portal-files__bc-link {
    display: inline-flex;
    align-items: center;
    padding: var(--spacing-xs) var(--spacing-sm);
    border-radius: var(--border-radius-sm);
    font: inherit;
    color: var(--color-text-secondary);
    text-decoration: none;
    transition: background var(--transition-fast), color var(--transition-fast);
}

.portal-files__bc-link:hover,
.portal-files__bc-link:focus-visible {
    background: var(--color-surface-hover);
    color: var(--color-text-primary);
    outline: none;
}

.portal-files__bc-sep {
    color: var(--color-text-tertiary);
}

.portal-files__bc-current {
    padding: var(--spacing-xs) var(--spacing-sm);
    color: var(--color-text-primary);
    font-weight: var(--font-weight-semibold);
}

/* ── Toolbar ────────────────────────────────────────────────────────── */

.portal-files__toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-md);
    padding: var(--spacing-md) var(--spacing-xl);
    border-bottom: 1px solid var(--color-border);
    flex-wrap: wrap;
}

.portal-files__toolbar-left,
.portal-files__toolbar-right {
    display: flex;
    align-items: center;
    gap: var(--spacing-sm);
}

.portal-files__search {
    display: flex;
    align-items: center;
    gap: var(--spacing-sm);
    width: 320px;
    height: 34px;
    padding: 0 var(--spacing-md);
    background: var(--color-surface-hover);
    border: 1px solid var(--color-border);
    border-radius: var(--border-radius-md);
    color: var(--color-text-secondary);
    transition: background var(--transition-fast), border-color var(--transition-fast), box-shadow var(--transition-fast);
    cursor: text;
}

.portal-files__search:focus-within {
    background: var(--color-surface);
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px rgba(var(--color-primary-rgb), 0.15);
}

.portal-files__search input {
    flex: 1;
    min-width: 0;
    background: transparent;
    border: 0;
    outline: 0;
    font: inherit;
    font-size: var(--font-size-base);
    color: var(--color-text-primary);
}

.portal-files__search input::placeholder {
    color: var(--color-text-tertiary);
}

.portal-files__search-clear {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    padding: 0;
    background: transparent;
    border: 0;
    border-radius: 50%;
    color: var(--color-text-secondary);
    cursor: pointer;
}

.portal-files__search-clear:hover {
    background: var(--color-border);
    color: var(--color-text-primary);
}

.portal-files__new-folder-input {
    width: 14rem;
    height: 28px;
    padding: 0 var(--spacing-sm);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--border-radius-sm);
    font: inherit;
    font-size: var(--font-size-base);
    color: var(--color-text-primary);
    outline: 0;
}

.portal-files__new-folder-input:focus {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px rgba(var(--color-primary-rgb), 0.15);
}

.portal-files__bulk-bar {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-sm);
    height: 34px;
    padding: 0 var(--spacing-sm) 0 var(--spacing-md);
    background: rgba(var(--color-primary-rgb), 0.08);
    border: 1px solid rgba(var(--color-primary-rgb), 0.3);
    border-radius: var(--border-radius-md);
}

.portal-files__bulk-count {
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-semibold);
    color: var(--color-primary);
    margin-right: var(--spacing-xs);
}

/* Ghost button used inside the bulk bar. We don't reuse Bootstrap's
   .btn-outline-secondary because its muted neutral border + transparent
   background fade away against the bar's primary-tinted backdrop, and the
   "ghost" buttons in the design need to read as raised, opaque surfaces. */
.portal-files__bulk-btn {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-xs);
    height: 28px;
    padding: 0 var(--spacing-md);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--border-radius-sm);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
    color: var(--color-text-primary);
    cursor: pointer;
    transition: background var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
    white-space: nowrap;
}

.portal-files__bulk-btn:hover:not(:disabled) {
    background: var(--color-surface-hover);
    border-color: var(--color-border-dark);
}

.portal-files__bulk-btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.portal-files__bulk-btn--danger {
    color: var(--color-error);
}

.portal-files__bulk-btn--danger:hover:not(:disabled) {
    background: rgba(var(--color-error-rgb), 0.08);
    border-color: rgba(var(--color-error-rgb), 0.4);
    color: var(--color-error);
}

.portal-files__bulk-close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    margin-left: var(--spacing-xs);
    padding: 0;
    background: transparent;
    border: 0;
    border-radius: var(--border-radius-sm);
    color: var(--color-primary);
    cursor: pointer;
    transition: background var(--transition-fast);
}

.portal-files__bulk-close:hover,
.portal-files__bulk-close:focus-visible {
    background: rgba(var(--color-primary-rgb), 0.15);
    outline: none;
}

.portal-files__view-toggle {
    display: inline-flex;
    padding: 2px;
    background: var(--color-surface-hover);
    border: 1px solid var(--color-border);
    border-radius: var(--border-radius-md);
}

.portal-files__view-toggle-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    background: transparent;
    border: 0;
    border-radius: var(--border-radius-sm);
    color: var(--color-text-secondary);
    cursor: pointer;
    transition: background var(--transition-fast), color var(--transition-fast), box-shadow var(--transition-fast);
}

.portal-files__view-toggle-btn:hover {
    color: var(--color-text-primary);
}

.portal-files__view-toggle-btn.is-active {
    background: var(--color-surface);
    color: var(--color-text-primary);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
}

/* ── Body / banner ──────────────────────────────────────────────────── */

.portal-files__body {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

.portal-files__loading {
    margin: 0;
    padding: var(--spacing-xl);
    color: var(--color-text-secondary);
}

.portal-files__banner {
    margin: 0;
    padding: var(--spacing-sm) var(--spacing-xl);
    border-bottom: 1px solid rgba(var(--color-info-rgb), 0.2);
    background: rgba(var(--color-info-rgb), 0.07);
    font-size: var(--font-size-base);
    color: var(--color-text-primary);
}

.portal-files__empty-pad {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--spacing-3xl) var(--spacing-xl);
}

/* ── Provider/scope cards ───────────────────────────────────────────── */

.portal-files__providers {
    padding: var(--spacing-3xl);
}

.portal-files__providers-head {
    max-width: 600px;
    margin-bottom: var(--spacing-2xl);
}

.portal-files__providers-head h2 {
    margin: 0 0 var(--spacing-xs);
    font-size: var(--font-size-xl);
    font-weight: var(--font-weight-semibold);
    color: var(--color-text-primary);
}

.portal-files__providers-head p {
    margin: 0;
    font-size: var(--font-size-base);
    color: var(--color-text-secondary);
}

.portal-files__providers-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: var(--spacing-md);
}

.portal-files__provider-card {
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    gap: var(--spacing-lg);
    padding: var(--spacing-lg);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--border-radius-md);
    color: inherit;
    text-decoration: none;
    transition: border-color var(--transition-fast), box-shadow var(--transition-fast), transform var(--transition-fast);
}

.portal-files__provider-card:hover,
.portal-files__provider-card:focus-visible {
    border-color: var(--color-border-dark);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
    transform: translateY(-1px);
    outline: none;
}

.portal-files__provider-mark {
    display: grid;
    place-items: center;
    flex-shrink: 0;
    width: 56px;
    height: 56px;
    background: var(--color-surface-hover);
    border-radius: var(--border-radius-md);
    font-size: 1.5rem;
    color: var(--color-primary);
}

.portal-files__provider-meta {
    min-width: 0;
}

.portal-files__provider-name {
    margin-bottom: 2px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-semibold);
    color: var(--color-text-primary);
}

.portal-files__provider-tag {
    font-size: var(--font-size-sm);
    color: var(--color-text-secondary);
}

.portal-files__provider-stats {
    display: flex;
    align-items: center;
    gap: var(--spacing-xs);
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

/* ── List view ──────────────────────────────────────────────────────── */

.portal-files__list {
    flex: 1;
    display: flex;
    flex-direction: column;
}

.portal-files__list-head,
.portal-files__list-row {
    display: grid;
    grid-template-columns: 36px 1fr 160px 110px 140px;
    align-items: center;
    gap: var(--spacing-md);
    padding: 0 var(--spacing-xl);
}

.portal-files__col-check {
    display: grid;
    place-items: center;
}

.portal-files__col-check input {
    width: 15px;
    height: 15px;
    accent-color: var(--color-primary);
    cursor: pointer;
}

/* Hide the per-row checkbox until the row is hovered or selected; the
   header checkbox stays visible at all times. */
.portal-files__list-row .portal-files__col-check input {
    opacity: 0;
    transition: opacity var(--transition-fast);
}

.portal-files__list-row:hover .portal-files__col-check input,
.portal-files__list-row:focus-within .portal-files__col-check input,
.portal-files__list-row.is-selected .portal-files__col-check input {
    opacity: 1;
}

.portal-files__list-head {
    height: 36px;
    background: var(--color-surface-hover);
    border-bottom: 1px solid var(--color-border);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-text-tertiary);
}

.portal-files__list-row {
    height: 44px;
    border-bottom: 1px solid var(--color-border);
    cursor: default;
    transition: background var(--transition-fast);
    user-select: none;
}

.portal-files__list-row:last-child {
    border-bottom: 0;
}

.portal-files__list-row:hover {
    background: var(--color-surface-hover);
}

.portal-files__list-row.is-selected {
    background: rgba(var(--color-primary-rgb), 0.08);
}

.portal-files__list-row.is-selected:hover {
    background: rgba(var(--color-primary-rgb), 0.12);
}

.portal-files__col-name {
    display: flex;
    align-items: center;
    gap: var(--spacing-md);
    min-width: 0;
}

.portal-files__name-icon {
    display: grid;
    place-items: center;
    flex-shrink: 0;
    width: 28px;
    font-size: var(--font-size-lg);
    color: var(--color-text-tertiary);
    line-height: 1;
}

/* Folder yellow — the warning token's hue is the same warm yellow used for
   folders in every consumer file browser, so we reuse it instead of a literal. */
.portal-files__name-icon--folder {
    color: var(--color-warning);
}

.portal-files__name-link,
.portal-files__name-text {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--font-size-base);
    color: var(--color-text-primary);
    text-decoration: none;
}

.portal-files__list-row.is-folder .portal-files__name-link {
    font-weight: var(--font-weight-medium);
}

.portal-files__list-row.is-file .portal-files__name-link:hover {
    color: var(--color-link);
    text-decoration: underline;
}

.portal-files__col-modified,
.portal-files__col-size {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--font-size-sm);
    color: var(--color-text-secondary);
}

.portal-files__col-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--spacing-xs);
    opacity: 0;
    transition: opacity var(--transition-fast);
}

.portal-files__list-row:hover .portal-files__col-actions,
.portal-files__list-row:focus-within .portal-files__col-actions {
    opacity: 1;
}

.portal-files__row-act {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--border-radius-sm);
    color: var(--color-text-secondary);
    cursor: pointer;
    transition: background var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
}

.portal-files__row-act:hover:not(:disabled) {
    background: var(--color-surface-hover);
    border-color: var(--color-border-dark);
    color: var(--color-text-primary);
}

.portal-files__row-act:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

.portal-files__row-act--danger:hover:not(:disabled) {
    background: rgba(var(--color-error-rgb), 0.08);
    border-color: rgba(var(--color-error-rgb), 0.4);
    color: var(--color-error);
}

.portal-files__rename-input {
    flex: 1;
    min-width: 0;
    height: 28px;
    padding: 0 var(--spacing-sm);
    background: var(--color-surface);
    border: 1px solid var(--color-primary);
    border-radius: var(--border-radius-sm);
    box-shadow: 0 0 0 3px rgba(var(--color-primary-rgb), 0.15);
    font: inherit;
    font-size: var(--font-size-base);
    color: var(--color-text-primary);
    outline: 0;
}

.portal-files__inline-confirm {
    display: flex;
    align-items: center;
    gap: var(--spacing-sm);
    white-space: nowrap;
    font-size: var(--font-size-base);
    color: var(--color-text-secondary);
}

/* ── Grid view ──────────────────────────────────────────────────────── */

.portal-files__grid {
    flex: 1;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
    gap: var(--spacing-sm);
    padding: var(--spacing-xl);
    align-content: start;
}

.portal-files__tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--spacing-sm);
    padding: var(--spacing-md) var(--spacing-sm);
    border: 1px solid transparent;
    border-radius: var(--border-radius-md);
    color: inherit;
    cursor: default;
    text-align: center;
    text-decoration: none;
    user-select: none;
    transition: background var(--transition-fast), border-color var(--transition-fast);
}

.portal-files__tile:hover,
.portal-files__tile:focus-visible {
    background: var(--color-surface-hover);
    outline: none;
}

.portal-files__tile.is-selected {
    background: rgba(var(--color-primary-rgb), 0.10);
    border-color: rgba(var(--color-primary-rgb), 0.35);
}

/* ── Skeletons (cold-load placeholders) ─────────────────────────────── */

@keyframes portal-files-sk-pulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.55; }
}

@keyframes portal-files-sk-shimmer {
    0%   { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}

.portal-files__list-row--skeleton,
.portal-files__tile--skeleton {
    cursor: default;
    pointer-events: none;
    animation: portal-files-sk-pulse 1.4s ease-in-out infinite;
}

.portal-files__list-row--skeleton:hover,
.portal-files__tile--skeleton:hover {
    background: transparent;
}

.portal-files__sk-thumb,
.portal-files__sk-thumb-lg,
.portal-files__sk-line {
    display: inline-block;
    background: linear-gradient(
        90deg,
        var(--color-border) 0%,
        var(--color-surface-hover) 50%,
        var(--color-border) 100%);
    background-size: 200% 100%;
    animation: portal-files-sk-shimmer 1.6s ease-in-out infinite;
}

.portal-files__sk-thumb {
    flex-shrink: 0;
    width: 24px;
    height: 24px;
    border-radius: var(--border-radius-sm);
}

.portal-files__sk-thumb-lg {
    width: 56px;
    height: 48px;
    border-radius: var(--border-radius-md);
}

.portal-files__sk-line {
    width: 50%;
    max-width: 320px;
    height: 10px;
    border-radius: 5px;
}

.portal-files__sk-line--short   { max-width: 90px; }
.portal-files__sk-line--shorter { max-width: 60px; }
.portal-files__sk-line--tile    { height: 9px; }

@media (prefers-reduced-motion: reduce) {
    .portal-files__list-row--skeleton,
    .portal-files__tile--skeleton,
    .portal-files__sk-thumb,
    .portal-files__sk-thumb-lg,
    .portal-files__sk-line {
        animation: none;
    }
}

.portal-files__tile-icon {
    display: grid;
    place-items: center;
    height: 64px;
    font-size: 2.75rem;
    color: var(--color-text-tertiary);
    line-height: 1;
}

.portal-files__tile-icon--folder {
    color: var(--color-warning);
}

.portal-files__tile-name {
    display: -webkit-box;
    overflow: hidden;
    width: 100%;
    font-size: var(--font-size-sm);
    color: var(--color-text-primary);
    line-height: 1.3;
    word-break: break-word;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}

.portal-files__tile.is-folder .portal-files__tile-name {
    font-weight: var(--font-weight-medium);
}

/* ── Tile launch overlay ────────────────────────────────────────────── */

/* Anchor for the launch + dropdown buttons in the top-right of each file tile.
   Position absolute over the tile (which has implicit position from the parent
   grid layout — set explicit relative on the tile so the absolute pin works). */
.portal-files__tile { position: relative; }

.portal-files__tile-launch {
    position: absolute;
    top: var(--spacing-xs);
    right: var(--spacing-xs);
    display: flex;
    gap: 2px;
    z-index: 1;
    /* Hover-to-reveal: hidden at rest to keep tile aesthetic clean, then fades in
       when the user mouses over the tile. Keyboard focus + selected state also
       reveal it for non-mouse paths. */
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--transition-fast);
}

.portal-files__tile:hover .portal-files__tile-launch,
.portal-files__tile:focus-within .portal-files__tile-launch,
.portal-files__tile.is-selected .portal-files__tile-launch {
    opacity: 1;
    pointer-events: auto;
}

.portal-files__tile-launch-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border: 1px solid rgba(var(--color-primary-rgb), 0.45);
    border-radius: var(--border-radius-sm);
    /* Solid primary fill so the button reads as a strong call-to-action against
       the tile's icon-and-name body. Matches the "default opener" hint colour. */
    background: var(--color-primary);
    color: var(--color-on-primary, #fff);
    cursor: pointer;
    font-size: var(--font-size-md);
    line-height: 1;
    text-decoration: none;
    padding: 0;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
    transition: filter var(--transition-fast), transform var(--transition-fast);
}

.portal-files__tile-launch-btn:hover {
    filter: brightness(1.08);
    transform: scale(1.05);
}

.portal-files__tile-launch-more {
    /* Slightly narrower chevron button to visually distinguish from the primary. */
    width: 22px;
}

/* ── Responsive ─────────────────────────────────────────────────────── */

@media (max-width: 768px) {
    .portal-files__list-head,
    .portal-files__list-row {
        grid-template-columns: 36px 1fr 90px 100px;
    }
    .portal-files__list-head .portal-files__col-modified,
    .portal-files__list-row .portal-files__col-modified {
        display: none;
    }
    .portal-files__search {
        width: 200px;
    }
    .portal-files__providers {
        padding: var(--spacing-xl);
    }
}

/* ── Session expiry banner ──────────────────────────────────────────── */

.portal-session-expiry-banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-lg);
    padding: var(--spacing-sm) var(--spacing-xl);
    border-bottom: 1px solid rgba(var(--color-warning-rgb), 0.3);
    background: rgba(var(--color-warning-rgb), 0.1);
    font-size: var(--font-size-base);
}

/* ── Announcement banner ────────────────────────────────────────────── */

.portal-announcement {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--spacing-lg);
    padding: var(--spacing-md) var(--spacing-xl);
    border-bottom: 1px solid rgba(var(--color-info-rgb), 0.2);
    background: rgba(var(--color-info-rgb), 0.07);
}

.portal-announcement__body {
    display: flex;
    align-items: flex-start;
    gap: var(--spacing-md);
    min-width: 0;
}

.portal-announcement__icon {
    width: 24px;
    height: 24px;
    flex-shrink: 0;
    border-radius: var(--border-radius-sm);
}

.portal-announcement__content {
    min-width: 0;
}

.portal-announcement__title {
    display: block;
    font-size: var(--font-size-base);
    font-weight: 600;
}

.portal-announcement__description {
    margin: var(--spacing-xs) 0 0;
    font-size: var(--font-size-base);
    color: var(--color-text-secondary);
    white-space: pre-wrap;
}

.portal-announcement__dismiss {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 28px;
    height: 28px;
    appearance: none;
    border: none;
    border-radius: var(--border-radius-sm);
    background: transparent;
    color: var(--color-text-secondary);
    font-size: var(--font-size-base);
    cursor: pointer;
    transition: background var(--transition-fast), color var(--transition-fast);
}

.portal-announcement__dismiss:hover {
    background: var(--color-surface-hover);
    color: var(--color-text-primary);
}

.portal-announcement__dismiss:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 1px;
}

/* ── Download banner ────────────────────────────────────────────────── */

/* Persistent banner shown above the workspace dashboard when the admin enables
   "Show client download banner" in /admin/domain/portal. Same horizontal shape
   as the announcement banner so the two stack cleanly when both are visible. */
.portal-download-banner {
    display: flex;
    align-items: center;
    gap: var(--spacing-md);
    padding: var(--spacing-sm) var(--spacing-xl);
    border-bottom: 1px solid rgba(var(--color-primary-rgb), 0.2);
    background: rgba(var(--color-primary-rgb), 0.06);
}

.portal-download-banner__icon {
    flex-shrink: 0;
    font-size: var(--font-size-lg);
    color: var(--color-primary);
}

.portal-download-banner__content {
    flex: 1;
    min-width: 0;
    font-size: var(--font-size-base);
    color: var(--color-text-primary);
}

/* Inherits Bootstrap's .btn-close (X glyph + reset). Just sized down and given
   a subtle hover/focus to match the banner's quiet primary tint. */
.portal-download-banner__close {
    flex-shrink: 0;
    width: 0.85rem;
    height: 0.85rem;
    opacity: 0.55;
    transition: opacity var(--transition-fast);
}

.portal-download-banner__close:hover,
.portal-download-banner__close:focus-visible {
    opacity: 1;
    outline: none;
}

/* ── Notice and consent dialog ───────────────────────────────────────── */

/* Inner wrapper for the post-login Notice and Consent acknowledgment dialog.
   Radzen owns the modal chrome; we only style the scrollable markdown body.
   Buttons use stock Bootstrap (.form-actions / .btn) — see CreateFormActions
   in Turbo.Admin for the canonical pattern. */
.notice-dialog__body {
    max-height: 60vh;
    overflow-y: auto;
    color: var(--color-text-primary);
    line-height: 1.55;
}

.notice-dialog__body h1,
.notice-dialog__body h2,
.notice-dialog__body h3 {
    margin: var(--spacing-lg) 0 var(--spacing-sm);
    font-weight: 600;
}

.notice-dialog__body p,
.notice-dialog__body ul,
.notice-dialog__body ol {
    margin: var(--spacing-sm) 0;
}

.notice-dialog__body ul,
.notice-dialog__body ol {
    padding-left: var(--spacing-2xl);
}

.notice-dialog__body a {
    color: var(--color-primary);
    text-decoration: underline;
}

.login-box__sso-divider {
    display: flex;
    align-items: center;
    gap: var(--spacing-sm);
    margin: var(--spacing-md) 0;
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

.login-box__sso-divider::before,
.login-box__sso-divider::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--color-border);
}


/* ── Workspace rail + channels panel (Slack-style two-sidebar layout) ──
   Rails are position:fixed at top:0 so they span the full viewport height —
   the topbar in turn sits *to the right* of them (margin-left, not behind).
   Mount/unmount is driven by Razor @if in MainLayout; the only :has() rules
   below are geometric shifts keyed off rail/panel presence. *@
*/

.app-shell:has(.portal-wsrail) .app-shell__topbar {
    margin-left: 68px;
}
.app-shell:has(.portal-wsrail) .app-shell__body {
    margin-left: 68px;
}
.app-shell:has(.portal-wsrail):has(.portal-chans) .app-shell__topbar {
    margin-left: calc(68px + 220px);
}
.app-shell:has(.portal-wsrail):has(.portal-chans) .app-shell__body {
    margin-left: calc(68px + 220px);
}

/* Workspace rail (far left, 68px, full viewport height) */
.portal-wsrail {
    position: fixed;
    left: 0;
    top: 0;
    bottom: 0;
    width: 68px;
    background: var(--color-surface-hover);
    border-right: 1px solid var(--color-border);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0;
    z-index: 6;
}

.portal-wsrail__logo {
    width: 100%;
    /* Matches .portal-chans__header so the logo + workspace name sit on the
       same baseline across the two rails — and aligns with the topbar's
       bottom edge to the right. */
    height: 58px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    margin-bottom: 14px;
}

.portal-wsrail__item + .portal-wsrail__item {
    margin-top: var(--spacing-sm);
}

.portal-wsrail__item {
    position: relative;
    width: 44px;
    height: 44px;
    border-radius: 11px;
    border: none;
    background: var(--portal-workspace-swatch, var(--color-text-secondary));
    color: var(--color-text-inverse);
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-bold);
    letter-spacing: -.02em;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    text-decoration: none;
    transition: border-radius .15s, box-shadow var(--transition-fast);
    flex-shrink: 0;
}

.portal-wsrail__item:hover {
    border-radius: 15px;
    text-decoration: none;
    color: var(--color-text-inverse);
}

.portal-wsrail__item--active {
    border-radius: 13px;
    box-shadow: 0 0 0 2px var(--color-surface-hover),
                0 0 0 4px var(--color-text-primary);
}

.portal-wsrail__item--active::before {
    content: "";
    position: absolute;
    left: -12px;
    top: 8px;
    bottom: 8px;
    width: 4px;
    border-radius: 0 4px 4px 0;
    background: var(--color-text-primary);
}

/* Logo-tile variant: drop the colored background and let the workspace's uploaded
   logo image fill the rounded square. */
.portal-wsrail__item--logo {
    background: var(--color-surface);
    overflow: hidden;
}

.portal-wsrail__item--logo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: inherit;
}

/* Channels panel (inner sidebar). Full viewport height — its 58px header sits
   where the topbar's left section would be. Channel list inside uses the
   standard portal .app-sidenav / .nav-section__items vocabulary; only the
   header zone is panel-specific. */
.portal-chans {
    position: fixed;
    left: 68px;
    top: 0;
    bottom: 0;
    width: 220px;
    background: var(--color-surface);
    border-right: 1px solid var(--color-border);
    display: flex;
    flex-direction: column;
    z-index: 5;
}

.portal-chans__header {
    /* Matched to .portal-wsrail__logo (58px). */
    height: 58px;
    padding: 0 var(--spacing-md) 0 14px;
    display: flex;
    align-items: center;
    gap: 10px;
    box-sizing: border-box;
}

.portal-chans__crest {
    width: 32px;
    height: 32px;
    border-radius: var(--border-radius-md);
    background: var(--portal-workspace-swatch, var(--color-primary));
    color: var(--color-text-inverse);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
    letter-spacing: -.02em;
    flex-shrink: 0;
}

.portal-chans__crest--logo {
    background: var(--color-surface);
    overflow: hidden;
}

.portal-chans__crest--logo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: inherit;
}

.portal-chans__title {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.portal-chans__name {
    font-size: 13.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--color-text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.portal-chans__sub {
    font-size: var(--font-size-xs);
    color: var(--color-text-tertiary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.portal-chans__collapse {
    width: 26px;
    height: 26px;
    border: none;
    background: transparent;
    border-radius: var(--border-radius-sm);
    color: var(--color-text-secondary);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    flex-shrink: 0;
}

.portal-chans__collapse:hover {
    background: var(--color-surface-hover);
    color: var(--color-text-primary);
}

/* Channels-list-specific tweaks that layer on top of .app-sidenav / .nav-section__items.
   The "All channels" row uses the .portal-chans__item--all modifier for bold weight; the
   default .nav-section__items a styling provides padding/colors/active-state. */
.portal-chans .portal-chans__item--all {
    font-weight: var(--font-weight-semibold);
}

/* The colored dot before a channel name. Placed inline because .nav-section__items a
   is display:block; we use inline-block on the dot and reserve a tight gap. */
.portal-chans__dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    margin-right: var(--spacing-sm);
    vertical-align: middle;
    /* nudge to optical-center against the line-height baseline */
    margin-top: -2px;
    flex-shrink: 0;
}

/* Font Awesome icon for the "All channels" item. Matches the dot's inline layout
   so the labels line up across rows. */
.portal-chans__icon {
    display: inline-block;
    width: 14px;
    margin-right: 6px;
    text-align: center;
    vertical-align: middle;
    margin-top: -2px;
    opacity: .7;
    flex-shrink: 0;
    font-size: 12px;
}

/* Expander tab — shown by MainLayout when the panel is collapsed. */
.portal-chans__expander {
    position: fixed;
    left: 68px;
    top: calc(50% + 28px);
    transform: translateY(-50%);
    width: 18px;
    height: 60px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-left: none;
    border-radius: 0 var(--border-radius-md) var(--border-radius-md) 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--color-text-secondary);
    cursor: pointer;
    z-index: 7;
    transition: background-color var(--transition-fast), color var(--transition-fast);
}

.portal-chans__expander:hover {
    background: var(--color-surface-hover);
    color: var(--color-text-primary);
}
