/** {*/
/*    outline: 1px solid #f00 !important;*/
/*}*/

:root {
    /* Canonical cross-platform monospace stack — keep in sync with TcaFonts.Monospace (C#).
       Bare Consolas is Windows-only; this carries a full fallback chain for Linux/macOS. */
    --tca-font-mono: ui-monospace, "Cascadia Mono", "Cascadia Code", "SF Mono", Menlo, Monaco, Consolas, "DejaVu Sans Mono", "Liberation Mono", monospace;
}

/* Generic monospace utility for verbatim machine text (endpoint URIs, ids, paths) rendered inside
   MudBlazor components, which have no monospace typography option of their own. */
.tca-monospace {
    font-family: var(--tca-font-mono);
}

html, body {
    /*overflow: hidden;*/
}

h1:focus {
    outline: none;
}

#blazor-error-ui {
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: 0.75rem;
    top: 0.5rem;
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

.blazor-error-boundary::after {
    content: "An error has occurred."
}

.mud-expand-panel.minimal-header .mud-expand-panel-header {
    padding: 0 16px;
}

.monaco-editor-container { height: 100%; }

.fill-height {
    display: flex;
    flex-direction: column;
    min-height: 100%;
}

.img-bg {
    z-index: -10;
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;

    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;

    /* Mask: fully opaque until --fade-stop%, then fade to transparent over --fade-softness% */
    -webkit-mask-image: linear-gradient(
            to bottom,
            rgba(0, 0, 0, 1) calc(var(--fade-stop) * 1%),
            rgba(0, 0, 0, 0) calc((var(--fade-stop) + var(--fade-softness)) * 1%)
    );
    -webkit-mask-size: 100% 100%;
    -webkit-mask-repeat: no-repeat;
    -webkit-mask-position: top;

    mask-image: linear-gradient(
            to bottom,
            rgba(0, 0, 0, 1) calc(var(--fade-stop) * 1%),
            rgba(0, 0, 0, 0) calc((var(--fade-stop) + var(--fade-softness)) * 1%)
    );
    mask-size: 100% 100%;
    mask-repeat: no-repeat;
    mask-position: top;
    box-shadow: 0 20px 50px rgba(2, 6, 23, 0.12);
    filter: brightness(calc(1 - var(--darken)));

    overflow: hidden;
}

/* ===================================================================
   AUTH LAYOUT - FULLSCREEN BACKGROUND
   =================================================================== */

.auth-fullscreen {
    position: fixed;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: auto;
}

.auth-bg-image {
    position: absolute;
    inset: 0;
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    z-index: 0;
}

.auth-bg-overlay {
    position: absolute;
    inset: 0;
    background: var(--mud-palette-background);
    z-index: 1;
}

.auth-content {
    position: relative;
    z-index: 2;
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 100%;
    max-width: 420px;
    padding: 24px 16px;
    gap: 24px;
}

.auth-footer {
    opacity: 0.5;
    color: #fff;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}

.auth-theme-toggle {
    position: fixed;
    top: 16px;
    right: 16px;
    z-index: 3;
}

.auth-theme-toggle .mud-icon-button {
    color: var(--mud-palette-text-primary);
    background: rgba(var(--mud-palette-surface-rgb), 0.55);
    backdrop-filter: blur(12px) saturate(1.4);
    -webkit-backdrop-filter: blur(12px) saturate(1.4);
    border: 1px solid rgba(255, 255, 255, 0.08);
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
}

/* ===================================================================
   LOGIN - GLASS CARD
   =================================================================== */

.login-glass-card {
    width: 100%;
    padding: 40px 32px;
    border-radius: 16px;
    background: rgba(var(--mud-palette-surface-rgb), 0.55);
    backdrop-filter: blur(24px) saturate(1.4);
    -webkit-backdrop-filter: blur(24px) saturate(1.4);
    border: 1px solid rgba(255, 255, 255, 0.08);
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.25),
                0 0 0 1px rgba(255, 255, 255, 0.04) inset;
}

@media (max-width: 480px) {
    .login-glass-card {
        padding: 32px 20px;
        border-radius: 12px;
    }
}

/* -- Branding -- */

.login-brand {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    margin-bottom: 4px;
}

.login-logo {
    border-radius: 10px;
}

.login-brand-title {
    font-weight: 700;
    letter-spacing: -0.3px;
}

.login-subtitle {
    margin-bottom: 8px;
}

/* -- Alert -- */

.login-alert {
    border-radius: 8px;
}

/* -- Form fields -- */

.login-field .mud-input-outlined-border {
    border-radius: 10px;
    border-color: rgba(255, 255, 255, 0.12);
    transition: border-color 0.2s ease;
}

.login-field .mud-input-root:hover .mud-input-outlined-border {
    border-color: rgba(var(--mud-palette-primary-rgb), 0.5);
}

.login-field .mud-input-root-outlined {
    background: rgba(var(--mud-palette-surface-rgb), 0.3);
    border-radius: 10px;
    transition: background 0.2s ease;
}

.login-field .mud-input-root-outlined.mud-input-root-focused {
    background: rgba(var(--mud-palette-surface-rgb), 0.45);
}

/* -- Submit button -- */

.login-submit-btn {
    height: 48px;
    font-weight: 600;
    font-size: 0.95rem;
    letter-spacing: 0.3px;
    border-radius: 10px !important;
    box-shadow: 0 4px 14px rgba(var(--mud-palette-primary-rgb), 0.35);
    transition: box-shadow 0.25s ease;
}

.login-submit-btn:hover {
    box-shadow: 0 6px 20px rgba(var(--mud-palette-primary-rgb), 0.5);
}

/* -- Forgot password -- */

.login-forgot-btn {
    text-transform: none;
    opacity: 0.7;
    transition: opacity 0.2s ease;
}

.login-forgot-btn:hover {
    opacity: 1;
}

/* -- Divider -- */

.login-divider {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 8px 0;
}

.login-divider-line {
    flex: 1;
    height: 1px;
    background: rgba(255, 255, 255, 0.1);
}

.login-divider-text {
    text-transform: lowercase;
    opacity: 0.6;
}

/* -- OAuth buttons -- */

.login-oauth-btn {
    border-radius: 10px !important;
    border-color: rgba(255, 255, 255, 0.1) !important;
    text-transform: none;
    font-weight: 500;
    background: rgba(var(--mud-palette-surface-rgb), 0.2);
    transition: background 0.2s ease, border-color 0.2s ease;
}

.login-oauth-btn:hover {
    background: rgba(var(--mud-palette-surface-rgb), 0.35);
    border-color: rgba(255, 255, 255, 0.2) !important;
}

/* ===================================================================
   ANIMATIONS
   =================================================================== */

@keyframes fadeIn {
    from {
        opacity: 0;
    }
    to {
        opacity: 1;
    }
}

.animate-fade-in {
    animation: fadeIn 0.5s ease-out;
}

.alert-container {
    animation: fadeIn 0.35s ease-out;
}

/* ===================================================================
   TCADMIN LOADING SCREEN STYLES
   =================================================================== */

.tcadmin-loading-overlay {
    /* Primary / progress bar colors */
    --primary-color: #00aaff;
    --primary-color-alt: #0088ff;
    --secondary-color: #00ccff;

    /* Background overlay color */
    --bg-dark: #0a0a0a;

    /* Glass card background */
    --loading-card-bg: rgba(30, 30, 40, 0.55);

    /* Text color (title & status) */
    --loading-text-color: #fff;

    /* Animation timing */
    --shimmer-duration: 2s;
    --pulse-duration: 1.5s;
}

/* Light-mode loading screen — applied by the theme-bootstrap script in App.razor when
   the user's stored (or system) preference is light. Any explicit LoadingScreenConfig
   colors still win via the inline style on #tcadmin-loading (inline-style specificity). */
html.loading-light .tcadmin-loading-overlay {
    --bg-dark: #eef1f6;
    --loading-card-bg: rgba(255, 255, 255, 0.65);
    --loading-text-color: #1f2430;
}

html.loading-light .loading-glass-card {
    border-color: rgba(0, 0, 0, 0.06);
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12),
                0 0 0 1px rgba(0, 0, 0, 0.03) inset;
}

html.loading-light .loading-progress-track {
    background: rgba(0, 0, 0, 0.10);
}

/* The stock background art (/img/background.png) is dark navy — part of the DARK look. In
   light mode it would bleed through the translucent overlay and keep the loader dark, so it
   is hidden (the solid --bg-dark base on the overlay root paints instead). Theme-configured
   images are branding and keep showing in both schemes (they don't carry this class). */
html.loading-light .loading-bg-image.loading-bg-default {
    display: none;
}

.tcadmin-loading-overlay {
    position: fixed;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
    z-index: 9999;
    transition: opacity 0.5s ease;
    /* Solid base under the bg-image/overlay layers: guarantees the loader tracks the color
       scheme (--bg-dark flips via html.loading-light) even when the image is hidden or a
       theme's gradients don't cover. In dark mode it sits invisibly under the full-cover art. */
    background: var(--bg-dark);
}

.tcadmin-loading-overlay.visible {
    opacity: 1;
    pointer-events: all;
}

.tcadmin-loading-overlay.hidden {
    opacity: 0;
    pointer-events: none;
}

/* -- Background (mirrors auth layout) -- */

.loading-bg-image {
    position: absolute;
    inset: 0;
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    z-index: 0;
}

.loading-bg-overlay {
    position: absolute;
    inset: 0;
    background: var(--bg-dark);
    opacity: 0.7;
    z-index: 1;
}

/* -- Glass card -- */

.loading-glass-card {
    position: relative;
    z-index: 2;
    width: 100%;
    max-width: 380px;
    padding: 40px 32px 32px;
    border-radius: 16px;
    background: var(--loading-card-bg);
    backdrop-filter: blur(24px) saturate(1.4);
    -webkit-backdrop-filter: blur(24px) saturate(1.4);
    border: 1px solid rgba(255, 255, 255, 0.08);
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.25),
                0 0 0 1px rgba(255, 255, 255, 0.04) inset;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 28px;
    animation: loadingCardFadeIn 0.5s ease-out;
}

@keyframes loadingCardFadeIn {
    from {
        opacity: 0;
        transform: translateY(12px) scale(0.98);
    }
    to {
        opacity: 1;
        transform: translateY(0) scale(1);
    }
}

@media (max-width: 480px) {
    .loading-glass-card {
        max-width: calc(100% - 32px);
        padding: 32px 20px 24px;
        border-radius: 12px;
    }
}

/* -- Branding (logo OR title, centered) -- */

.loading-logo {
    max-height: 64px;
    max-width: 100%;
    border-radius: 10px;
    object-fit: contain;
}

.loading-brand-title {
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: -0.3px;
    text-align: center;
    color: var(--loading-text-color);
}

/* -- Progress bar -- */

.loading-progress-wrapper {
    width: 100%;
}

.loading-progress-track {
    width: 100%;
    height: 6px;
    border-radius: 3px;
    background: rgba(255, 255, 255, 0.08);
    overflow: hidden;
    position: relative;
}

.loading-progress-fill {
    height: 100%;
    width: 0%;
    border-radius: 3px;
    background: linear-gradient(
        90deg,
        var(--primary-color) 0%,
        var(--primary-color-alt) 40%,
        var(--secondary-color) 100%
    );
    background-size: 200% 100%;
    animation: loading-gradient-shift var(--shimmer-duration) ease-in-out infinite;
    transition: width 0.4s cubic-bezier(0.4, 0, 0.2, 1);
    box-shadow: 0 0 12px rgba(0, 170, 255, 0.4),
                0 0 4px rgba(0, 170, 255, 0.2);
}

@keyframes loading-gradient-shift {
    0% {
        background-position: 0% 0;
    }
    50% {
        background-position: 100% 0;
    }
    100% {
        background-position: 0% 0;
    }
}

/* -- Status text -- */

.loading-status {
    font-size: 0.8125rem;
    font-weight: 400;
    letter-spacing: 0.04em;
    color: var(--loading-text-color);
    opacity: 0.5;
    text-align: center;
    min-height: 1.2em;
    animation: loading-pulse var(--pulse-duration) ease-in-out infinite;
}

@keyframes loading-pulse {
    0%, 100% {
        opacity: 0.45;
    }
    50% {
        opacity: 0.85;
    }
}

/* -- Performance -- */

.loading-progress-fill {
    will-change: width;
}

/* -- Accessibility -- */

@media (prefers-reduced-motion: reduce) {
    .loading-progress-fill,
    .loading-status {
        animation: none;
    }

    .loading-glass-card {
        animation: none;
    }
}

/* ===================================================================
   DATABASE PAGE STYLES
   =================================================================== */

.database-name-field .mud-input-adornment {
    margin-right: -8px;
}

.database-section-header {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 0;
}

/* Database cards */
.database-card {
    transition: all 0.3s ease;
    cursor: pointer;
    height: 100%;
}

.database-card:hover {
    transform: translateY(-4px);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
}

.database-card-selected {
    transition: all 0.3s ease;
    cursor: pointer;
    height: 100%;
    border: 2px solid var(--mud-palette-primary);
    box-shadow: 0 8px 24px rgba(var(--mud-palette-primary-rgb), 0.3);
}

.database-card-selected:hover {
    transform: translateY(-4px);
    box-shadow: 0 12px 32px rgba(var(--mud-palette-primary-rgb), 0.4);
}

/* Hover cards for action buttons */
.hover-card {
    transition: all 0.3s ease;
    cursor: pointer;
}

.hover-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
}

/* Responsive adjustments for database page */
@media (max-width: 960px) {
    .database-card:hover,
    .database-card-selected:hover {
        transform: none;
    }

    .hover-card:hover {
        transform: none;
    }
}

/* ===================================================================
   SUB USER PERMISSIONS PAGE STYLES
   =================================================================== */

/* Permission card base styles */
.permission-card {
    border: 1px solid var(--mud-palette-lines-default);
    background: var(--mud-palette-surface);
    transition: all 0.2s ease;
}

.permission-card:hover {
    border-color: var(--mud-palette-primary);
    background: rgba(var(--mud-palette-primary-rgb), 0.04);
}

/* Granted permission card */
.permission-card-granted {
    border-color: var(--mud-palette-primary);
    background: rgba(var(--mud-palette-primary-rgb), 0.08);
}

.permission-card-granted:hover {
    background: rgba(var(--mud-palette-primary-rgb), 0.12);
}

/* Cursor pointer utility */
.cursor-pointer {
    cursor: pointer;
}

/* Single-line truncation utility. Note the min-width:0 — without it a flex/stack
   child refuses to shrink below its content width and never ellipsizes. */
.tca-text-ellipsis {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

/* Background gray for select all section */
.mud-background-gray {
    background: rgba(var(--mud-palette-text-primary-rgb), 0.04);
}

/* ===================================================================
   PLUGIN CARD BACKGROUND IMAGE STYLES
   =================================================================== */

/* Manifest cards sit in a MudGrid row and stretch to the tallest sibling via
   mud-height-full. That stretches the CARD, but not its contents — so a card with
   no description ends up with its footer parked mid-card while a taller neighbour's
   sits lower, and the "View Details" buttons across a row don't line up.
   This chain (card → content → body stack) makes each level fill its parent, then
   .plugin-card-footer's margin-top:auto absorbs the slack so the footer lands on the
   bottom edge no matter how much content is above it. */
.plugin-card {
    display: flex;
    flex-direction: column;
}

.plugin-card > .mud-card-content {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
}

.plugin-card-body {
    flex: 1 1 auto;
}

.plugin-card-footer {
    margin-top: auto;
}

/* Plugin card with background image support */
.plugin-card-with-bg {
    position: relative;
    overflow: hidden;
}

/* Background image element - absolutely positioned behind content */
.plugin-card-bg-image {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    opacity: 0.12;
    z-index: 0;
    pointer-events: none;
    transition: opacity 0.3s ease;
}

/* Gradient overlay for text readability - sits on top of the image */
.plugin-card-bg-overlay {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: linear-gradient(
        to bottom,
        rgba(var(--mud-palette-surface-rgb), 0.65) 0%,
        rgba(var(--mud-palette-surface-rgb), 0.8) 35%,
        rgba(var(--mud-palette-surface-rgb), 0.92) 100%
    );
    z-index: 1;
    pointer-events: none;
}

/* Hover effect - slightly reveal more of the image */
.plugin-card-with-bg:hover .plugin-card-bg-image {
    opacity: 0.18;
}

/* "What's New" tiles are whole-card links — they need a hover affordance of their
   own, since most carry no background image to reveal. */
.whats-new-card {
    transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.whats-new-card:hover {
    border-color: var(--mud-palette-primary) !important;
    box-shadow: 0 2px 8px rgba(var(--mud-palette-primary-rgb), 0.18);
}

/* Ensure card header, content, and actions stay above the background layers */
.plugin-card-with-bg > .mud-card-header,
.plugin-card-with-bg > .mud-card-content,
.plugin-card-with-bg > .mud-card-actions {
    position: relative;
    z-index: 2;
}

/* ===================================================================
   PLUGIN PAGE BACKGROUND IMAGE STYLES
   =================================================================== */

/* Page container with background image support (similar to plugin-card-with-bg) */
.plugin-page-with-bg {
    position: relative;
    overflow: hidden;
    min-height: 100%;
}

/* Background image element for pages - absolutely positioned */
.plugin-page-bg-image {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 400px;
    background-size: cover;
    background-position: center top;
    background-repeat: no-repeat;
    opacity: 0.12;
    z-index: 0;
    pointer-events: none;
}

/* Gradient overlay for page background - ensures text readability */
.plugin-page-bg-overlay {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 400px;
    background: linear-gradient(
        to bottom,
        rgba(var(--mud-palette-surface-rgb), 0.55) 0%,
        rgba(var(--mud-palette-surface-rgb), 0.75) 50%,
        rgba(var(--mud-palette-background-rgb), 1) 100%
    );
    z-index: 1;
    pointer-events: none;
}

/* Content container - ensures all page content is above background */
.plugin-page-content {
    position: relative;
    z-index: 2;
}

/* List item styling for plugin manifest pages (replaces inline style) */
.plugin-page-content article > ul > li {
    margin-left: 35px;
}

/* Disconnect dialog - transparent paper for animated inner content */
.disconnect-dialog-transparent {
    background: transparent !important;
    box-shadow: none !important;
}

.disconnect-dialog-transparent .mud-dialog-content {
    padding: 0 !important;
}

/* ===================================================================
   API KEYS GLOBAL STYLES
   =================================================================== */

/* API Key monospace text */
.api-key-mono {
    font-family: var(--tca-font-mono);
    letter-spacing: 0.02em;
}

/* API Key status indicators */
.api-key-status-active {
    color: var(--mud-palette-success);
}

.api-key-status-expired {
    color: var(--mud-palette-warning);
}

.api-key-status-revoked {
    color: var(--mud-palette-error);
    text-decoration: line-through;
    opacity: 0.7;
}

/* API Key copy feedback animation */
@keyframes copyFlash {
    0% {
        background-color: transparent;
    }
    50% {
        background-color: rgba(var(--mud-palette-success-rgb), 0.2);
    }
    100% {
        background-color: transparent;
    }
}

.api-key-copy-flash {
    animation: copyFlash 0.5s ease-out;
}

/* Permission chip styles for API keys */
.api-key-permission-chip {
    font-size: 0.75rem;
    height: 24px;
    margin: 2px;
}

/* API Key warning banner */
.api-key-warning-banner {
    background: linear-gradient(135deg,
        rgba(var(--mud-palette-warning-rgb), 0.1) 0%,
        rgba(var(--mud-palette-warning-rgb), 0.2) 100%);
    border-left: 4px solid var(--mud-palette-warning);
    padding: 12px 16px;
    border-radius: 0 8px 8px 0;
}

/* Secure badge for API key display */
.api-key-secure-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 10px;
    background: rgba(var(--mud-palette-success-rgb), 0.1);
    border: 1px solid rgba(var(--mud-palette-success-rgb), 0.3);
    border-radius: 12px;
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--mud-palette-success);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

/* API Key Permissions Dialog Styles */
.api-key-permissions-dialog .mud-dialog-content {
    padding: 16px 24px;
}

.api-key-permissions-dialog .category-item {
    cursor: pointer;
    transition: background-color 0.15s ease;
    border-left: 3px solid transparent;
}

.api-key-permissions-dialog .category-item:hover:not(.category-item-selected) {
    background: var(--mud-palette-action-default-hover);
}

.api-key-permissions-dialog .category-item-selected {
    border-left-color: var(--mud-palette-primary-darken);
}

.api-key-permissions-dialog .permission-item-readonly {
    border-radius: 4px;
    transition: background-color 0.15s ease;
}

.api-key-permissions-dialog .permission-item-readonly:hover {
    background: var(--mud-palette-action-default-hover);
}

@media (prefers-reduced-motion: reduce) {
    .api-key-permissions-dialog .category-item,
    .api-key-permissions-dialog .permission-item-readonly {
        transition: none;
    }
}

/* ===================================================================
   DASHBOARD PACKERY GRID STYLES
   =================================================================== */

/* Initially hide the dashboard grid to prevent layout flash/jump */
.dashboard-grid.packery-initializing {
    opacity: 0;
    visibility: hidden;
}

/* Reveal the grid after Packery has calculated positions */
.dashboard-grid.packery-ready {
    opacity: 1;
    visibility: visible;
    transition: opacity 0.2s ease-out;
}

/* Reduce motion for accessibility */
@media (prefers-reduced-motion: reduce) {
    .dashboard-grid.packery-ready {
        transition: none;
    }
}

/* ===================================================================
   SYSTEM HEALTH PAGE STYLES
   =================================================================== */

.health-container {
    padding: 16px 0;
}

.health-header {
    border-radius: 16px;
    padding: 24px 32px;
    margin-bottom: 24px;
    position: relative;
    overflow: hidden;
}

.health-header::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    opacity: 0.1;
    background-image: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23ffffff' fill-opacity='0.4'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
}

.health-header-healthy {
    background: linear-gradient(135deg, var(--mud-palette-success) 0%, var(--mud-palette-success-darken) 100%);
}

.health-header-degraded {
    background: linear-gradient(135deg, var(--mud-palette-warning) 0%, var(--mud-palette-warning-darken) 100%);
}

.health-header-unhealthy {
    background: linear-gradient(135deg, var(--mud-palette-error) 0%, var(--mud-palette-error-darken) 100%);
}

.health-header-unknown {
    background: linear-gradient(135deg, var(--mud-palette-grey-default) 0%, var(--mud-palette-grey-darken-1) 100%);
}

.health-icon-container {
    width: 80px;
    height: 80px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.2);
    display: flex;
    align-items: center;
    justify-content: center;
    backdrop-filter: blur(8px);
}

.health-title {
    color: white;
    font-weight: 700;
    font-size: 1.75rem;
    text-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

.health-subtitle {
    color: rgba(255, 255, 255, 0.9);
    font-size: 1rem;
}

.health-card {
    border-radius: 12px;
    border: 2px solid transparent;
    transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
    background: var(--mud-palette-background-paper);
    overflow: hidden;
}

.health-card:hover {
    transform: translateY(-4px);
    box-shadow: 0 12px 32px rgba(0,0,0,0.12);
}

.health-card-healthy {
    border-color: var(--mud-palette-success);
}

.health-card-degraded {
    border-color: var(--mud-palette-warning);
}

.health-card-unhealthy {
    border-color: var(--mud-palette-error);
}

.health-card-header {
    padding: 16px 20px;
    border-bottom: 1px solid var(--mud-palette-divider);
}

.health-card-header-healthy {
    background: linear-gradient(to right, rgba(var(--mud-palette-success-rgb), 0.08) 0%, transparent 100%);
}

.health-card-header-degraded {
    background: linear-gradient(to right, rgba(var(--mud-palette-warning-rgb), 0.08) 0%, transparent 100%);
}

.health-card-header-unhealthy {
    background: linear-gradient(to right, rgba(var(--mud-palette-error-rgb), 0.08) 0%, transparent 100%);
}

.health-card-body {
    padding: 20px;
}

.status-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 12px;
    border-radius: 20px;
    font-weight: 600;
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.status-badge-healthy {
    background: rgba(var(--mud-palette-success-rgb), 0.15);
    color: var(--mud-palette-success);
}

.status-badge-degraded {
    background: rgba(var(--mud-palette-warning-rgb), 0.15);
    color: var(--mud-palette-warning);
}

.status-badge-unhealthy {
    background: rgba(var(--mud-palette-error-rgb), 0.15);
    color: var(--mud-palette-error);
}

.health-detail-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 8px 0;
    border-bottom: 1px dashed var(--mud-palette-divider);
}

.health-detail-row:last-child {
    border-bottom: none;
}

.health-detail-label {
    color: var(--mud-palette-text-secondary);
    font-size: 0.875rem;
}

.health-detail-value {
    font-weight: 500;
    font-size: 0.875rem;
}

.health-refresh-button {
    position: relative;
    z-index: 1;
}

.server-status-item {
    padding: 8px 12px;
    border-radius: 8px;
    margin-bottom: 8px;
    transition: all 0.2s ease;
}

.server-status-item:last-child {
    margin-bottom: 0;
}

.server-status-item-online {
    background: rgba(var(--mud-palette-success-rgb), 0.08);
    border: 1px solid rgba(var(--mud-palette-success-rgb), 0.2);
}

.server-status-item-offline {
    background: rgba(var(--mud-palette-error-rgb), 0.08);
    border: 1px solid rgba(var(--mud-palette-error-rgb), 0.2);
}

/* License usage bar */
.license-usage-bar {
    height: 8px;
    border-radius: 4px;
    background: var(--mud-palette-grey-lighter);
    overflow: hidden;
}

.license-usage-fill {
    height: 100%;
    border-radius: 4px;
    transition: width 0.3s ease;
}

.license-usage-fill-healthy {
    background: var(--mud-palette-success);
}

.license-usage-fill-warning {
    background: var(--mud-palette-warning);
}

.license-usage-fill-critical {
    background: var(--mud-palette-error);
}

/* License server item (similar to server-status-item) */
.license-server-item {
    padding: 8px 12px;
    border-radius: 8px;
    margin-bottom: 8px;
    transition: all 0.2s ease;
}

.license-server-item:last-child {
    margin-bottom: 0;
}

.license-server-item-valid {
    background: rgba(var(--mud-palette-success-rgb), 0.08);
    border: 1px solid rgba(var(--mud-palette-success-rgb), 0.2);
}

.license-server-item-invalid {
    background: rgba(var(--mud-palette-error-rgb), 0.08);
    border: 1px solid rgba(var(--mud-palette-error-rgb), 0.2);
}

.license-server-item-offline {
    background: rgba(var(--mud-palette-grey-rgb), 0.08);
    border: 1px solid rgba(var(--mud-palette-grey-rgb), 0.2);
}

/* ===================================================================
   SYSTEM PAGES — SHARED PRIMITIVES (System Update + System Health)
   A single visual language so the two "System" pages feel like a suite.
   All colour values are MudBlazor palette tokens => light/dark safe.
   =================================================================== */

.sys-page {
    padding: 16px 0;
}

/* --- Hero banner ------------------------------------------------- */
.sys-hero {
    position: relative;
    overflow: hidden;
    border-radius: 16px;
    padding: 26px 32px;
    color: #fff;
}

.sys-hero::before {
    content: '';
    position: absolute;
    inset: 0;
    opacity: 0.12;
    background-image: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23ffffff' fill-opacity='0.4'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
    pointer-events: none;
}

.sys-hero > * { position: relative; z-index: 1; }

.sys-hero-primary { background: linear-gradient(135deg, var(--mud-palette-primary) 0%, var(--mud-palette-primary-darken) 100%); }
.sys-hero-success { background: linear-gradient(135deg, var(--mud-palette-success) 0%, var(--mud-palette-success-darken) 100%); }
.sys-hero-warning { background: linear-gradient(135deg, var(--mud-palette-warning) 0%, var(--mud-palette-warning-darken) 100%); }
.sys-hero-error   { background: linear-gradient(135deg, var(--mud-palette-error) 0%, var(--mud-palette-error-darken) 100%); }
.sys-hero-info    { background: linear-gradient(135deg, var(--mud-palette-info) 0%, var(--mud-palette-info-darken) 100%); }
.sys-hero-neutral { background: linear-gradient(135deg, var(--mud-palette-grey-default) 0%, var(--mud-palette-grey-darken-1) 100%); }

.sys-hero-icon {
    width: 72px;
    height: 72px;
    border-radius: 20px;
    background: rgba(255, 255, 255, 0.18);
    backdrop-filter: blur(8px);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

.sys-hero-title {
    color: #fff;
    font-weight: 700;
    font-size: 1.6rem;
    line-height: 1.2;
    text-shadow: 0 2px 4px rgba(0, 0, 0, 0.12);
}

.sys-hero-sub {
    color: rgba(255, 255, 255, 0.92);
    font-size: 0.95rem;
}

.sys-hero-btn {
    background: rgba(255, 255, 255, 0.18) !important;
    color: #fff !important;
    backdrop-filter: blur(8px);
    border: 1px solid rgba(255, 255, 255, 0.25) !important;
}

.sys-hero-btn:hover { background: rgba(255, 255, 255, 0.30) !important; }

.sys-hero-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 12px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.18);
    color: #fff;
    font-size: 0.78rem;
    font-weight: 600;
    backdrop-filter: blur(8px);
}

/* --- Surface card (replaces flat MudPaper) ----------------------- */
.sys-card {
    border-radius: 14px;
    border: 1px solid var(--mud-palette-divider);
    background: var(--mud-palette-background-paper);
    overflow: hidden;
}

.sys-card-head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 14px 22px;
    border-bottom: 1px solid var(--mud-palette-divider);
}

.sys-card-head .mud-icon-root { color: var(--mud-palette-primary); }

.sys-card-title {
    font-weight: 600;
    font-size: 1rem;
}

.sys-card-body { padding: 18px 22px; }

/* --- Stat tiles (version / channel / latest) --------------------- */
.sys-stat {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    border-radius: 12px;
    border: 1px solid var(--mud-palette-divider);
    background: var(--mud-palette-surface);
    padding: 14px 16px;
    height: 100%;
    transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.sys-stat:hover {
    border-color: rgba(var(--mud-palette-primary-rgb), 0.35);
    box-shadow: 0 2px 10px rgba(var(--mud-palette-primary-rgb), 0.08);
}

/* Text column (label + value + optional link) — hugs the left of the tile. */
.sys-stat-main {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

/* Tinted icon medallion anchored to the right edge so the tile's width reads
   as intentional negative space rather than dead air. Default (no accent) is
   primary-tinted; the accent modifiers below recolor it to match the tile. */
.sys-stat-icon {
    flex-shrink: 0;
    display: grid;
    place-items: center;
    width: 42px;
    height: 42px;
    border-radius: 11px;
    background: rgba(var(--mud-palette-primary-rgb), 0.10);
    color: var(--mud-palette-primary);
}

.sys-stat-accent-success { border-left: 3px solid var(--mud-palette-success); }
.sys-stat-accent-warning { border-left: 3px solid var(--mud-palette-warning); }
.sys-stat-accent-info    { border-left: 3px solid var(--mud-palette-info); }

.sys-stat-accent-success .sys-stat-icon { background: rgba(var(--mud-palette-success-rgb), 0.14); color: var(--mud-palette-success); }
.sys-stat-accent-warning .sys-stat-icon { background: rgba(var(--mud-palette-warning-rgb), 0.14); color: var(--mud-palette-warning); }
.sys-stat-accent-info    .sys-stat-icon { background: rgba(var(--mud-palette-info-rgb),    0.14); color: var(--mud-palette-info); }

.sys-stat-label {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.6px;
    font-weight: 600;
    color: var(--mud-palette-text-secondary);
}

.sys-stat-value {
    font-size: 1.3rem;
    font-weight: 700;
    margin-top: 4px;
    line-height: 1.25;
    font-variant-numeric: tabular-nums;
}

.sys-stat-link {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    width: fit-content;
    margin-top: 8px;
    font-size: 0.78rem;
    font-weight: 600;
    text-underline-offset: 2px;
}

/* --- Monospace, tabular version text ----------------------------- */
.sys-ver {
    font-family: var(--tca-font-mono);
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    letter-spacing: -0.2px;
}

/* --- Live / pulsing dot ------------------------------------------ */
.sys-live-dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: #fff;
    display: inline-block;
    animation: sys-pulse 1.8s infinite;
}

@keyframes sys-pulse {
    0%   { box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.55); }
    70%  { box-shadow: 0 0 0 9px rgba(255, 255, 255, 0); }
    100% { box-shadow: 0 0 0 0 rgba(255, 255, 255, 0); }
}

/* --- Phase stepper (master -> remotes) --------------------------- */
.sys-steps {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.sys-step {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 6px 14px;
    border-radius: 999px;
    background: var(--mud-palette-action-default-hover);
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--mud-palette-text-secondary);
}

.sys-step-active { background: rgba(var(--mud-palette-info-rgb), 0.16); color: var(--mud-palette-info); }
.sys-step-done   { background: rgba(var(--mud-palette-success-rgb), 0.16); color: var(--mud-palette-success); }
.sys-step-sep    { color: var(--mud-palette-text-disabled); font-weight: 700; }

/* --- Server status rows (shared with health server-status-item) -- */
.sys-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 14px;
    border-radius: 10px;
    border: 1px solid var(--mud-palette-divider);
    background: var(--mud-palette-surface);
    transition: border-color 0.2s ease, background 0.2s ease;
}

.sys-row + .sys-row { margin-top: 8px; }
.sys-row-online    { border-color: rgba(var(--mud-palette-success-rgb), 0.30); }
.sys-row-offline   { background: rgba(var(--mud-palette-error-rgb), 0.05); border-color: rgba(var(--mud-palette-error-rgb), 0.25); }
.sys-row-updating  { background: rgba(var(--mud-palette-info-rgb), 0.07); border-color: rgba(var(--mud-palette-info-rgb), 0.30); }
.sys-row-done      { background: rgba(var(--mud-palette-success-rgb), 0.07); border-color: rgba(var(--mud-palette-success-rgb), 0.30); }
.sys-row-failed    { background: rgba(var(--mud-palette-error-rgb), 0.07); border-color: rgba(var(--mud-palette-error-rgb), 0.30); }

/* --- Summary count chips (health overview) ----------------------- */
.sys-count-chip {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 6px 14px;
    border-radius: 10px;
    font-weight: 600;
    font-size: 0.85rem;
    border: 1px solid var(--mud-palette-divider);
    background: var(--mud-palette-background-paper);
}

.sys-count-chip .sys-count-num {
    font-variant-numeric: tabular-nums;
    font-weight: 700;
}

/* --- Entrance animation ------------------------------------------ */
.sys-fade-in {
    animation: sys-fade-in 0.35s ease both;
}

@keyframes sys-fade-in {
    from { opacity: 0; transform: translateY(10px); }
    to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
    .sys-live-dot,
    .sys-fade-in { animation: none; }
    .sys-stat,
    .sys-row { transition: none; }
    .sys-hero-icon { backdrop-filter: none; }
}

/* ===================================================================
   THEME EDITOR PAGE
   =================================================================== */

/* Color swatch strip - horizontal row of color previews */
.theme-color-swatch-strip {
    display: flex;
    gap: 4px;
    flex-wrap: wrap;
    padding: 8px 0;
}

.theme-color-swatch {
    width: 28px;
    height: 28px;
    border-radius: 6px;
    border: 2px solid rgba(var(--mud-palette-text-primary-rgb), 0.12);
    transition: transform 0.15s ease, box-shadow 0.15s ease;
    cursor: pointer;
}

.theme-color-swatch:hover {
    transform: scale(1.2);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
}

.theme-color-swatch-lg {
    width: 36px;
    height: 36px;
    border-radius: 8px;
}

/* Color picker card with preview bar */
.theme-color-picker-card {
    position: relative;
    overflow: hidden;
    border-radius: 8px;
    border: 1px solid rgba(var(--mud-palette-text-primary-rgb), 0.08);
    transition: border-color 0.2s ease, box-shadow 0.2s ease;
    background: var(--mud-palette-surface);
}

.theme-color-picker-card:hover {
    border-color: rgba(var(--mud-palette-primary-rgb), 0.3);
    box-shadow: 0 2px 8px rgba(var(--mud-palette-primary-rgb), 0.1);
}

.theme-color-preview {
    height: 6px;
    width: 100%;
    transition: background-color 0.2s ease;
}

/* Console preview blinking cursor animation */
.theme-console-preview span[style*="border-left"] {
    animation: blink 1s step-end infinite;
}

@keyframes blink {
    0%, 100% { opacity: 1; }
    50% { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
    .theme-color-swatch:hover {
        transform: none;
    }

    .theme-console-preview span[style*="border-left"] {
        animation: none;
    }
}

/* =========================================================================
   Mobile usability — game service pages (phones, MudBlazor Xs ≤ 599.98px)
   ========================================================================= */

/* Stacked data tables.
   On phones MudBlazor collapses MudTable/MudDataGrid into a stacked
   label/value layout (each <td> renders its column title via ::before).
   Long unbreakable tokens — IP addresses, file paths, hostnames — set the
   table's min-content width and push it past the viewport, clipping the
   value side off the right edge. Cap the table at the container width and
   let those tokens break so every value stays on-screen. Verified on the
   Activity grid: table 464px → 410px in a 410px container, 0 overflow. */
@media (max-width: 599.98px) {
    .mud-table-container .mud-table-root {
        width: 100%;
        max-width: 100%;
        table-layout: fixed;
    }

    .mud-table-container .mud-table-root .mud-table-cell {
        overflow-wrap: anywhere;
    }
}

/* Toolbars (MudToolBar + the MudDataGrid/MudTable ToolBarContent bar, which is a MudToolBar with
   .mud-table-toolbar). MudBlazor toolbars are a fixed-height nowrap flex row, so on phones a toolbar
   with a title + search + several action buttons overflows the viewport and drags the whole page
   into a horizontal scrollbar (Themes/Games list pages et al.). Let every toolbar wrap on Xs instead —
   this mirrors MudBlazor's own opt-in .mud-toolbar-wrap-content idiom (height:auto + min-height +
   flex-wrap). The app bar is excluded: it must stay a single row because the fixed layout offsets
   content by --mud-appbar-height. Verified on the Themes grid: toolbar children overflowed 341px past
   the bar in a 360px container, grid scrollWidth 685 → 344 (no overflow) with this rule. */
@media (max-width: 599.98px) {
    .mud-toolbar:not(.mud-toolbar-appbar) {
        height: auto;
        min-height: var(--mud-internal-toolbar-height);
        flex-wrap: wrap;
        row-gap: 4px;
        padding-top: 8px;
        padding-bottom: 8px;
    }
}

/* File-manager loading skeleton: its left pane is a stand-in for the desktop folder tree, which is
   hidden on phones (the real tree uses MudHidden SmAndDown). Hide the skeleton tree too so the loading
   state matches the mobile layout — the contents skeleton (Width=100%) then fills the row. */
@media (max-width: 599.98px) {
    .fm-skeleton-tree {
        display: none;
    }
}

/* =========================================================================
   TCAHtmlEditor Design tab — the Quill canvas is always an email surface
   ========================================================================= */

/* Email HTML is authored against the white canvas email clients render on.
   quill.mudblazor.css (loaded by TCAdmin.LoadQuill) themes the editing surface
   with the Mud palette, so in dark mode the canvas goes dark with light text —
   while the content's own light table cells stay light: white-on-white text,
   invisible table lines. Pin the CANVAS to email-client colors in both themes;
   the toolbar and its dropdowns stay palette-themed. Higher specificity than
   the package's .ql-container rule, so stylesheet load order doesn't matter.
   color-scheme keeps the canvas scrollbar light to match. */
.tca-html-editor .ql-container.ql-snow {
    background-color: #ffffff;
    color: #212121;
    color-scheme: light;
}

/* =========================================================================
   Service home components (the ServiceHome layout-component catalog)
   ========================================================================= */

/* Shared chrome for the docker metric tiles (service-cpu/memory/disk/uptime-tile). Lives here —
   not in each component — so the compiled page and template-placed tiles style identically without
   four inline <style> copies. */
.docker-metric-card {
    transition: transform 0.2s ease, box-shadow 0.2s ease;
    min-height: 120px;
}
.docker-metric-card:hover {
    transform: translateY(-2px);
}

/* Shared chrome for the docker terminals. The terminal components carry the class themselves so a
   template-placed terminal is framed standalone; when one sits inside an already-framed host (the
   compiled home's tabs paper uses the same class), the inner frame goes transparent instead of
   drawing a border inside a border. */
.docker-terminal-wrapper {
    background: var(--mud-palette-surface);
    border: 1px solid var(--mud-palette-lines-default);
}
.docker-terminal-wrapper .docker-terminal-wrapper {
    background: transparent;
    border: none;
}

/* AI Assistant confirmation-card diff + admin-transcript tool arguments/results. Preserve the diff's / JSON's
   own whitespace and SCROLL it horizontally inside its own box (alignment kept, never widening the page —
   docs/MOBILE.md §1); the flex ancestors are unlocked by .tca-ai-chat below so the box shrinks to scroll
   instead of dragging the page wide. Content is Razor-encoded, so untrusted text is display-safe. */
.tca-ai-diff-pre {
    white-space: pre;
    overflow-x: auto;
    max-width: 100%;
    font-family: var(--tca-font-mono);
    font-size: 0.8125rem;
    margin: 0;
}

/* Confirmation-card diff lines: removals in the theme's error color, additions in success (both palettes
   track the active MudBlazor theme); context/marker lines slightly dimmed so the change stands out.
   display:block gives each span its own line — Blazor trims literal newlines inside elements, so the
   markup carries none; min-height keeps empty diff lines from collapsing to zero height. */
.tca-ai-diff-pre > span { display: block; min-height: 1.2em; }
.tca-ai-diff-add { color: var(--mud-palette-success); }
.tca-ai-diff-del { color: var(--mud-palette-error); }
.tca-ai-diff-ctx { color: var(--mud-palette-text-secondary); }

/* AI Assistant chat drawer + admin transcript — keep every message inside the phone viewport. The message
   list is a flex column; inside each row the bubble / confirmation card / tool panel is a flex item that
   (default min-width:auto) refuses to shrink below its content, so a wide diff, code block, table, or long
   unbreakable token would drag the whole PAGE wide. min-width:0 unlocks the flex item so its inner
   overflow-x:auto box (the diff/JSON and markdown <pre>/<table>) shrinks to scroll, max-width caps it at
   the viewport, and overflow-wrap breaks long prose tokens. Harmless at desktop widths — the rules only
   engage when content would overflow. The same flex idiom the widgets use, docs/MOBILE.md §1 + §3. */
.tca-ai-chat > * > * {
    min-width: 0;
    max-width: 100%;
    overflow-wrap: anywhere;
}

/* AI Assistant settings — the read-only data-disclosure preview is prose spliced with the assistant name
   and provider list; break a long unbreakable token so a 60-char name / provider string can't widen the
   card past a phone. docs/MOBILE.md §1. */
.tca-ai-disclosure {
    overflow-wrap: anywhere;
}

/* AI Assistant settings — the Balance & Usage table's per-day drill-down. The breakdown rows deliberately
   reuse the day row's own three columns so Requests/Credits stay under the totals they add up to; the indent
   and the tint are then the only things saying "these belong to the row above", so both are load-bearing.
   The indent clears the expander (dense cell padding + a Size.Small icon button + its me-1) so a username
   starts where the date it belongs to starts. Tinted with the theme's own hover token rather than a fixed
   grey, so it stays subtle in both light and dark. */
.tca-ai-usage-user {
    background-color: var(--mud-palette-action-default-hover);
}

.tca-ai-usage-user > td:first-child {
    padding-left: 50px;
}

/* Keep the expander from inflating a dense row — its default hit area is taller than the cell's line box. */
.tca-ai-usage-expander {
    padding: 2px;
}

/* AI Assistant chat input row — let the text field yield so a long (localized) Send/Stop label can never
   push the row past the viewport. docs/MOBILE.md §3. */
.tca-ai-input-row,
.tca-ai-input-row > * {
    min-width: 0;
}

/* AI Assistant chat input textarea. MudBlazor's outlined variant reserves shrunk-label headroom on the
   INNER textarea (margin-top + padding-bottom 18.5px each), but this field is placeholder-only — no label
   ever shrinks into that space, so it reads as dead air. MudTextField's Class lands on the OUTER
   .mud-input-control (no InputClass on MudTextField), so utility classes can't reach the textarea; this
   rule gives it the my-1 rhythm instead: 4px above and below the text, inside the outlined frame. */
.tca-ai-input-row .mud-input > textarea.mud-input-root {
    margin: 4px 0 0;
    padding: 0 14px 4px;
}

/* AI Assistant system notice (e.g. session resumed after a restart). A subtle, italic, muted line set apart
   from the user/assistant bubbles and tool chips. */
.tca-ai-notice {
    font-style: italic;
    opacity: 0.7;
}

/* AI Assistant markdown bubble. The assistant's reply is rendered markdown, so collapse the outer margins of
   its first/last block (the bubble supplies the padding) and keep wide content — code blocks, tables — inside
   the bubble by scrolling rather than blowing out its width. */
.tca-ai-markdown > * > :first-child {
    margin-top: 0;
}

.tca-ai-markdown > * > :last-child {
    margin-bottom: 0;
}

.tca-ai-markdown pre,
.tca-ai-markdown table {
    display: block;
    max-width: 100%;
    overflow-x: auto;
}

.tca-ai-markdown img {
    max-width: 100%;
}

/* Scale headings to chat proportions — MudMarkdown renders them at full document size, which is oversized
   inside a message bubble. Keep the hierarchy, drop the scale, and tighten the vertical rhythm. */
.tca-ai-markdown h1 {
    font-size: 1.3rem;
}

.tca-ai-markdown h2 {
    font-size: 1.15rem;
}

.tca-ai-markdown h3 {
    font-size: 1.05rem;
}

.tca-ai-markdown h4,
.tca-ai-markdown h5,
.tca-ai-markdown h6 {
    font-size: 1rem;
}

.tca-ai-markdown h1,
.tca-ai-markdown h2,
.tca-ai-markdown h3,
.tca-ai-markdown h4,
.tca-ai-markdown h5,
.tca-ai-markdown h6 {
    margin-top: 0.75em;
    margin-bottom: 0.35em;
    line-height: 1.3;
}

/* AI Assistant floating chat window (AiChatWidget). Host-owned overlay mounted from MainLayout on every
   page — including custom-template layouts — so it positions itself against the VIEWPORT only and makes
   no assumption about the surrounding chrome. z-index sits above the nav drawer (1100) and below the
   popover base (1200) so tooltips/menus opened INSIDE the window still render on top of it. */
.tca-ai-widget {
    position: fixed;
    /* Tucked near the edge on purpose: the page's own scrollbar lives in this margin, and with a wider gap
       it reads as if it belongs to the chat window. 4px keeps the floating look while covering it. */
    right: 4px;
    bottom: 16px;
    width: min(420px, calc(100vw - 32px));
    height: min(640px, calc(100dvh - 32px));
    z-index: 1150;
    display: flex;
    flex-direction: column;
    overflow: hidden; /* clip the panel to the paper's rounded corners */
}

/* Maximized fills the viewport, over the app bar (1300) too — that's what "maximize" means — while
   staying under dialogs (1400) and snackbars (1500); popovers opened from inside still work, exactly as
   they do from inside a MudDialog. */
.tca-ai-widget-max {
    inset: 0;
    width: auto;
    height: auto;
    border-radius: 0;
    z-index: 1310;
}

/* Closed = hidden, never unmounted: the chat session, transcript, draft, and any in-flight stream keep
   running (unread accrues on the nav toggle) and reopen instantly. */
.tca-ai-widget-hidden {
    display: none;
}

/* Phones: the window is always full-screen (the maximize control is hidden at this width — there is
   nothing in between to restore to). Same viewport-fill rules as maximized. */
@media (max-width: 599.98px) {
    .tca-ai-widget {
        inset: 0;
        width: auto;
        height: auto;
        border-radius: 0;
        z-index: 1310;
    }
}

/* The scrolling transcript region inside the window. The panel is a fixed-height flex column (header /
   alerts / THIS / input), so this is the only part that scrolls — TCAdmin.AutoScroll keeps it pinned to
   the newest line while the reader is at the bottom. */
.tca-ai-panel-messages {
    overflow-y: auto;
    overscroll-behavior: contain; /* the page behind the window must not scroll when the transcript ends */
}

/* The page-context chip above the input: its label is a URL or entity name of arbitrary length — ellipsize
   it inside the window's width instead of widening the row (docs/MOBILE.md §1). overflow:hidden on
   .mud-chip-content is LOAD-BEARING for shrinking: it zeroes the flex automatic minimum size all the way up
   the chip → tooltip-root → row chain (without it the chip balloons to the full label width and escapes the
   window). MudBlazor renders the × close button INSIDE that clipped content box with a -4px overhanging
   margin — that cut the button's circle — so the button keeps its width and loses the overhang instead. */
/* The tooltip's activator wrapper is shrink-to-fit — cap it at the row so the chip's max-width:100% below
   resolves against a bounded box instead of growing with its own content. */
.tca-ai-context-tooltip {
    max-width: 100%;
    min-width: 0;
}

.tca-ai-context-chip {
    max-width: 100%;
}

.tca-ai-context-chip .mud-chip-content {
    overflow: hidden;
    min-width: 0;
}

.tca-ai-context-chip .tca-ai-context-chip-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Beats MudBlazor's .mud-chip.mud-chip-size-small .mud-chip-close-button (0,3,0) regardless of stylesheet
   order — app.css loads BEFORE MudBlazor.min.css, so a specificity tie would lose. */
.tca-ai-context-chip.mud-chip .mud-chip-content .mud-chip-close-button {
    flex-shrink: 0;
    margin-right: 0;
    margin-inline-end: 0;
}

/* ===== Theme Wizard =====
   Static layout only (sizes / radius / borders / padding) for the color swatches and the
   light/dark preview mock-ups. The colors themselves are set inline from runtime-derived hex
   values (a color wizard cannot express user-chosen colors as static classes) — see THEME_WIZARD.md. */
.theme-wizard-swatch {
    height: 44px;
    border-radius: 8px;
    border: 1px solid rgba(0, 0, 0, 0.12);
}

.theme-wizard-swatch-dot {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    border: 1px solid rgba(0, 0, 0, 0.15);
    flex-shrink: 0;
}

.theme-wizard-extracted {
    width: 100%;
    height: 56px;
    border-radius: 8px;
    border: 1px solid rgba(0, 0, 0, 0.12);
    cursor: pointer;
}

.theme-wizard-preview {
    overflow: hidden;
}

.theme-wizard-color-input {
    max-width: 180px;
}

.theme-wizard-preview-appbar {
    padding: 10px 14px;
    border-radius: 10px 10px 0 0;
}

.theme-wizard-preview-body {
    padding: 16px;
    border-radius: 0 0 10px 10px;
}

.theme-wizard-preview-surface {
    padding: 14px;
    border-radius: 8px;
}