/* 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;
}


/* ── 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);
}

/* Workspace tile grid on the root list page. Capped width so a single workspace
   doesn't float in a sea of background — three 320px columns plus gutter fit
   inside this max. CSS Grid (not Bootstrap .row.g-4) because the row gutter's
   negative margin-top trick collides with sibling spacing. */
.workspace-card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: var(--spacing-2xl);
    max-width: 960px;
}

/* Workspace tile — destination, not feature description. Whole tile is the
   click target (no inner footer link). Three rows: heading (icon + name +
   optional summary), app icon preview, and a metadata line with the app count. */
.workspace-tile {
    display: grid;
    grid-template-rows: auto 1fr auto;
    gap: var(--spacing-lg);
    min-height: 200px;
    padding: 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__head {
    display: flex;
    align-items: flex-start;
    gap: var(--spacing-md);
}

.workspace-tile__icon {
    flex-shrink: 0;
    margin-top: var(--spacing-xs);
    font-size: var(--font-size-3xl);
    line-height: 1;
    color: var(--color-primary);
}

/* Image variant — used when a workspace uploads its own logo. The fa-cubes
   glyph next to it is `font-size-3xl × line-height: 1` (~32px tall). We cap the
   image at the same height; max-width keeps wide wordmark logos from blowing
   out the tile grid while still letting taller-than-wide logos use the full 32px. */
.workspace-tile__icon--image {
    width: auto;
    height: 32px;
    max-width: 64px;
    object-fit: contain;
    border-radius: var(--border-radius-sm);
}

/* Branded tiles have a workspace-uploaded background image inlined via style.
   The inline layer = linear-gradient(--color-overlay, --color-overlay) over the
   image, darkening it; text gets light treatment + shadow so it reads against
   any underlying image. */
.workspace-tile--branded,
.workspace-tile--branded .workspace-tile__name,
.workspace-tile--branded .workspace-tile__summary,
.workspace-tile--branded .workspace-tile__meta {
    color: var(--color-text-inverse);
}

.workspace-tile--branded .workspace-tile__name,
.workspace-tile--branded .workspace-tile__summary,
.workspace-tile--branded .workspace-tile__meta {
    text-shadow: 0 1px 2px var(--color-shadow-dark);
}

/* On hover, the bg image is already there — soften the surface-color border
   transition since there is no surface to fade against. */
.workspace-tile--branded:hover,
.workspace-tile--branded:focus-visible {
    border-color: var(--color-text-inverse);
}

.workspace-tile__title-block {
    min-width: 0;
}

.workspace-tile__name {
    margin: 0;
    font-size: var(--font-size-xl);
    font-weight: var(--font-weight-semibold);
    color: var(--color-text-primary);
}

/* Two-line clamp keeps long descriptions from pushing the apps row out of
   alignment across tiles in the same row. */
.workspace-tile__summary {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    margin: var(--spacing-xs) 0 0;
    font-size: var(--font-size-sm);
    color: var(--color-text-secondary);
}

.workspace-tile__apps {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--spacing-sm);
}

.workspace-tile__app-icon {
    width: 32px;
    height: 32px;
    object-fit: contain;
    border-radius: var(--border-radius-sm);
}

.workspace-tile__app-more {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 32px;
    height: 32px;
    padding: 0 var(--spacing-xs);
    background: var(--color-surface-hover);
    border-radius: var(--border-radius-sm);
    font-size: var(--font-size-sm);
    color: var(--color-text-secondary);
}

.workspace-tile__meta {
    font-size: var(--font-size-sm);
    color: var(--color-text-secondary);
}

/* 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 {
    padding: var(--spacing-md);
    border-radius: var(--border-radius-md);
    border: 1px solid var(--color-border);
    background: var(--color-terminal-bg);
    overflow: hidden;
}

/* 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);
}

/* ── 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);
}
