/* ══ Design tokens ══════════════════════════════════════════════════════════════════════════
   The one place the app's shape lives: radius, rhythm, surfaces, layout. Every colour token
   derives from a MudBlazor palette variable, so dark mode and the seven tenant presets follow
   without a second declaration. Components read these through var(); nothing restates a value.
   See .claude/rules/ui-conventions.md. This file is also loaded by the sign-in pages, so every
   rule below targets an aura-* class or a .mud-layout descendant, never a bare element. */
:root {
    /* Shape */
    --aura-radius-card: 12px;
    --aura-radius-control: 8px;
    --aura-radius-badge: 6px;
    --aura-radius-pill: 999px;

    /* Rhythm: header to content and card to card; inside a card; a card's own padding. */
    --aura-space-page: 24px;
    --aura-space-stack: 16px;
    --aura-card-pad: 20px;
    --aura-page-gutter: 24px;

    /* Surfaces. A card's edge is the divider (a hairline), not lines-default, which is the
       input border and reads heavy around a whole card. */
    --aura-line: var(--mud-palette-divider);
    --aura-line-strong: var(--mud-palette-lines-default);
    --aura-surface: var(--mud-palette-surface);
    --aura-surface-inset: var(--mud-palette-background-gray);
    --aura-tint-primary: color-mix(in srgb, var(--mud-palette-primary) 10%, transparent);
    --aura-shadow-card: 0 1px 2px rgb(15 23 42 / 0.04);
    --aura-shadow-raised: 0 8px 24px -6px rgb(15 23 42 / 0.22);

    /* Layout */
    --aura-appbar-height: 48px;
    --aura-sticky-top: calc(var(--aura-appbar-height) + 32px);
    --aura-sidebar-width: 360px;
    --aura-rail-width: 240px;
    --aura-content-max: 1600px;

    /* Type */
    --aura-font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;

    /* Product signals. Fixed, not the tenant's brand: impersonation must read the same in
       every tenant, whatever colour its preset makes the primary. */
    --aura-impersonation: #7c3aed;
    --aura-impersonation-text: #ffffff;
    --aura-sandbox: var(--mud-palette-warning);

    /* Paper: a rendered document — an email, a letter, a statement — is authored on white and
       previewed on white in either theme, because that is how it will be read. */
    --aura-paper: #ffffff;
    --aura-paper-ink: #1a1a1a;
}

@media (min-width: 1280px) {
    :root {
        --aura-sidebar-width: 380px;
    }
}

@media (max-width: 600px) {
    :root {
        --aura-card-pad: 16px;
        --aura-page-gutter: 16px;
    }
}

html, body {
    font-family: 'Inter', system-ui, -apple-system, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    background-color: var(--mud-palette-background);
    color: var(--mud-palette-text-primary);
}

/* WASM loading splash — replaced by <Routes> when the runtime boots.
   Uses MudBlazor palette variables so it tracks the active tenant theme
   (including dark mode) rather than hardcoded colors. */
#app-loading {
    position: fixed;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: var(--mud-palette-background);
    z-index: 9999;
}

#app-loading .spinner {
    width: 48px;
    height: 48px;
    border: 3px solid var(--mud-palette-lines-default, rgba(127, 127, 127, 0.2));
    border-top-color: var(--mud-palette-primary);
    border-radius: 50%;
    animation: app-loading-spin 0.8s linear infinite;
}

@keyframes app-loading-spin {
    to { transform: rotate(360deg); }
}

h1:focus {
    outline: none;
}

.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."
    }

#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;
    }

/* Quill editor — theme integration with MudBlazor */
.ql-toolbar.ql-snow {
    border-color: var(--mud-palette-lines-default);
    background-color: var(--mud-palette-background);
    border-radius: 8px 8px 0 0;
}

.ql-container.ql-snow {
    border-color: var(--mud-palette-lines-default);
    background-color: color-mix(in srgb, var(--mud-palette-surface) 94%, var(--mud-palette-text-primary));
    color: var(--mud-palette-text-primary);
    font-family: 'Inter', system-ui, -apple-system, sans-serif;
    font-size: 14px;
    border-radius: 0 0 8px 8px;
}

.ql-snow .ql-stroke {
    stroke: var(--mud-palette-text-primary);
}

.ql-snow .ql-fill {
    fill: var(--mud-palette-text-primary);
}

.ql-snow .ql-picker-label {
    color: var(--mud-palette-text-primary);
}

.ql-snow .ql-picker-options {
    background-color: var(--mud-palette-surface);
    border-color: var(--mud-palette-lines-default);
}

.ql-snow .ql-picker-item {
    color: var(--mud-palette-text-primary);
}

.ql-editor.ql-blank::before {
    color: var(--mud-palette-text-disabled);
}

/* ApexCharts tooltip theming — uses MudBlazor palette variables to adapt to light/dark mode */
.apexcharts-tooltip {
    background: var(--mud-palette-surface) !important;
    color: var(--mud-palette-text-primary) !important;
    border-color: var(--mud-palette-lines-default) !important;
}

.apexcharts-tooltip-title {
    background: var(--mud-palette-background) !important;
    color: var(--mud-palette-text-primary) !important;
    border-bottom-color: var(--mud-palette-lines-default) !important;
}

.apexcharts-tooltip-text,
.apexcharts-tooltip-text-y-label,
.apexcharts-tooltip-text-y-value {
    color: var(--mud-palette-text-primary) !important;
}

.apexcharts-tooltip-series-group {
    background: transparent !important;
}

.apexcharts-xaxistooltip {
    background: var(--mud-palette-surface) !important;
    color: var(--mud-palette-text-primary) !important;
    border-color: var(--mud-palette-lines-default) !important;
}

.apexcharts-xaxistooltip-text {
    color: var(--mud-palette-text-primary) !important;
}

.apexcharts-xaxistooltip::before,
.apexcharts-xaxistooltip::after {
    border-bottom-color: var(--mud-palette-surface) !important;
}

/* ── Help drawer ──────────────────────────────────────────────────────────────
   Global rather than scoped because these target the drawer's own root element.
   HelpDrawer.razor's root is a <MudDrawer>, which MudBlazor renders, so it never receives the
   component's CSS-isolation attribute and a scoped rule can never match it. See the note in
   HelpDrawer.razor.css. */
.help-drawer-root {
    max-width: 100vw;
}

/* Full width on a phone. Set through the width variable, not `width`: MudBlazor closes the drawer by
   moving it right by --mud-drawer-width, so widening it with `width` alone left it closing short —
   a 100vw drawer pushed out by only 480px, and a strip of it stayed on screen at 481-600px wide. */
@media (max-width: 600px) {
    .help-drawer-root {
        --mud-drawer-width: 100vw !important;
    }
}

/* ── Tab labels ───────────────────────────────────────────────────────────────
   CLAUDE.md: never render UI text in ALL CAPS. ThemeBuilder already clears the uppercase
   MudBlazor applies to MudButton and Typo.overline, but tab labels are not driven by either
   typography entry — MudBlazor uppercases .mud-tab in its own stylesheet, so the theme cannot
   reach them and every MudTabs in the app shouted its labels ("PRE-BUILT REPORTS").

   Global rather than scoped for the same reason as the help drawer above: .mud-tab is rendered
   by MudBlazor, so it never carries a component's CSS-isolation attribute. */
.mud-tab {
    text-transform: none;
}

/* MudBlazor 9 activator wrapper for MudFileUpload dropzones. CustomContent replaced
   ActivatorContent and no longer opens the picker itself, so the dropzone is wrapped in a
   clickable element that calls OpenFilePickerAsync. Shared because four pages use it, and
   scoped CSS could not reach it from all of them. */
.upload-activator {
    display: block;
    cursor: pointer;
}

/* ── Side nav: the Administration link ───────────────────────────────────────
   The side nav has one Administration link to the hub (AdminAreaCatalog). It stays highlighted
   on every admin page, not only on the hub its href points at, so NavMenu adds this class when
   the current page is one the catalog claims. MudNavLink puts Class on its wrapper while its
   active look lives on the inner link, so the look is restated here for both placements. Global
   rather than scoped: both elements are rendered by MudBlazor. */
.mud-navmenu .nav-admin-current.mud-nav-link:not(.mud-nav-link-disabled),
.mud-navmenu .nav-admin-current .mud-nav-link:not(.mud-nav-link-disabled) {
    color: var(--mud-palette-primary);
    background-color: var(--mud-palette-action-default-hover);
}

.mud-navmenu.mud-navmenu-bordered .nav-admin-current.mud-nav-link:not(.mud-nav-link-disabled),
.mud-navmenu.mud-navmenu-bordered .nav-admin-current .mud-nav-link:not(.mud-nav-link-disabled) {
    border-inline-end-style: solid;
    border-inline-end-width: 2px;
}

/* ══ Aura UI — global classes ══════════════════════════════════════════════════════════════
   Rules that decorate elements MudBlazor renders (tables, tabs, the nav), which a component's
   scoped CSS can never reach, plus the page frame. A Ui component's own plain elements are
   styled by its scoped .razor.css instead. See .claude/rules/ui-conventions.md. */

/* Page frame. MudMainContent's own padding-top compensates for the app bar; pa-6 used to
   override it with !important, so this restates the same offsets as tokens. */
.mud-main-content.aura-main {
    margin-top: calc(var(--aura-appbar-height) - 8px);
    padding: var(--aura-page-gutter) !important;
}

.mud-main-content.aura-onboarding-main {
    min-height: 100vh;
}

.aura-page {
    max-width: var(--aura-content-max);
    margin-inline: auto;
}

/* Tables. The table is its own card: a hairline frame, the inset surface behind a quiet header
   row, tabular numerals so money lines up. --flush drops the frame for a table that already
   sits inside a SectionCard. */
.mud-table.aura-table {
    border: 1px solid var(--aura-line);
    border-radius: var(--aura-radius-card);
    background-color: var(--aura-surface);
    box-shadow: var(--aura-shadow-card);
    overflow: hidden;
}

.mud-table.aura-table.aura-table--flush {
    border: 0;
    border-radius: 0;
    box-shadow: none;
    background-color: transparent;
}

.mud-table.aura-table .mud-table-head .mud-table-cell {
    background-color: var(--aura-surface-inset);
    color: var(--mud-palette-text-secondary);
    font-size: 0.8125rem;
    font-weight: 600;
    white-space: nowrap;
}

.mud-table.aura-table .mud-table-cell {
    font-variant-numeric: tabular-nums;
}

.mud-table.aura-table .mud-table-foot .mud-table-cell {
    font-weight: 600;
    border-top: 1px solid var(--aura-line);
}

.mud-table.aura-table .mud-table-pagination {
    border-top: 1px solid var(--aura-line);
}

/* A row's icon actions — RowActionButton and RowActionsMenu side by side. Each wraps its button
   in a span over a tooltip or a menu root, and those sat on different baselines: the edit or run
   button rode a few pixels above the menu beside it. */
.aura-row-action {
    display: inline-flex;
    align-items: center;
    vertical-align: middle;
}

.aura-row-action > .mud-tooltip-root,
.aura-row-action > .mud-menu {
    display: inline-flex;
    align-items: center;
}

/* A plain MudSimpleTable gets the same header treatment. */
.mud-simple-table.aura-table table thead th {
    background-color: var(--aura-surface-inset);
    color: var(--mud-palette-text-secondary);
    font-size: 0.8125rem;
    font-weight: 600;
    white-space: nowrap;
}

.mud-simple-table.aura-table table td {
    font-variant-numeric: tabular-nums;
}

/* Numbers and identifiers. aura-num replaces the inline text-align:right on money columns and
   the text-right class, which MudBlazor 9 does not define. */
.aura-num {
    text-align: right !important;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.aura-mono {
    font-family: var(--aura-font-mono);
    font-size: 0.9em;
}

.aura-strong {
    font-weight: 600;
}

.aura-muted {
    color: var(--mud-palette-text-secondary);
}

.aura-center {
    text-align: center;
}

.aura-nowrap {
    white-space: nowrap;
}

/* An inset panel inside a card: a note, an explanation, an address block, a meta line. */
.aura-inset {
    padding: 10px 14px;
    border-radius: var(--aura-radius-control);
    background-color: var(--aura-surface-inset);
}

/* Tabs: an underline strip, not a raised bar. */
.mud-tabs.aura-tabs > .mud-tabs-tabbar {
    background-color: transparent;
    border-radius: 0;
    border-bottom: 1px solid var(--aura-line);
}

.mud-tabs.aura-tabs .mud-tab {
    min-width: 0;
    padding-inline: 16px;
    font-weight: 500;
    color: var(--mud-palette-text-secondary);
}

.mud-tabs.aura-tabs .mud-tab.mud-tab-active {
    color: var(--mud-palette-primary);
}

.mud-tabs.aura-tabs .mud-tabs-panels {
    padding-top: var(--aura-space-page);
}

/* Side nav: a tinted pill for the current page instead of a bar on the drawer's edge. The
   admin link keeps its own class, since it stays current across every admin page. */
.mud-navmenu.aura-nav .mud-nav-link {
    border-radius: var(--aura-radius-control);
    margin-block: 1px;
}

.mud-navmenu.aura-nav .mud-nav-link.active:not(.mud-nav-link-disabled),
.mud-navmenu.aura-nav .nav-admin-current.mud-nav-link:not(.mud-nav-link-disabled),
.mud-navmenu.aura-nav .nav-admin-current .mud-nav-link:not(.mud-nav-link-disabled) {
    color: var(--mud-palette-primary);
    background-color: var(--aura-tint-primary);
    border-inline-end-width: 0;
    font-weight: 600;
}

/* App chrome edges: hairlines, not lines-default. */
.mud-appbar.aura-appbar {
    border-bottom: 1px solid var(--aura-line);
}

.mud-drawer.aura-nav-drawer {
    border-inline-end: 1px solid var(--aura-line);
}

.mud-drawer.aura-side-drawer {
    border-inline-start: 1px solid var(--aura-line);
}

/* A closed temporary drawer keeps MudBlazor's shadow, which falls back onto the page's right edge. */
.mud-drawer.aura-side-drawer.mud-drawer--closed {
    box-shadow: none;
}

/* Signals. */
.aura-impersonation-banner.mud-alert {
    background-color: var(--aura-impersonation);
    color: var(--aura-impersonation-text);
    position: sticky;
    top: 0;
    z-index: 11;
}

.aura-sandbox-banner.mud-alert {
    position: sticky;
    top: 0;
    z-index: 10;
}

.aura-impersonation-avatar.mud-avatar {
    background-color: var(--aura-impersonation);
    color: var(--aura-impersonation-text);
}

.aura-impersonation-text {
    color: var(--aura-impersonation);
}

/* The composable dashboard grid Home renders. Global because it was a page-level <style>
   block. 24 columns and 50px rows MUST stay in sync with UserDashboardBuilder's .builder-grid,
   the tile validator's upper bound and the data-grid-row-height dashboard-grid.js reads. */
.user-dashboard-grid {
    display: grid;
    grid-template-columns: repeat(24, 1fr);
    gap: var(--aura-space-stack);
    grid-auto-rows: 50px;
}

.user-dashboard-cell {
    display: flex;
    min-height: 0;
    overflow: hidden;
}

@media (max-width: 768px) {
    .user-dashboard-grid {
        grid-template-columns: 1fr;
    }

    .user-dashboard-cell {
        grid-column: 1 / -1 !important;
        grid-row: auto !important;
    }
}

/* Set by dashboard-grid.js on a builder tile while it is dragged or resized. Global because
   script, not markup, writes the class, so a scoped rule could never match it. */
.mud-layout .builder-tile-moving,
.mud-layout .builder-tile-resizing {
    border-color: var(--mud-palette-primary) !important;
    box-shadow: var(--aura-shadow-raised);
    opacity: 0.92;
    z-index: 10;
}

/* An email or statement preview, sandboxed in an iframe. The paper it is read on is white in
   either theme, so the frame is too — the preview's own styles assume it. */
.aura-preview-frame {
    display: block;
    width: 100%;
    height: 620px;
    border: 1px solid var(--aura-line);
    border-radius: var(--aura-radius-control);
    background-color: var(--mud-palette-white);
}
