.large {
    font-size: 20px;
}

.huge {
    font-size: 24px;
}

.medium {
    font-size: 16px;
}


/* `gray` was a fixed #808080 that read as a hard bar on a dark page and a muddy
   one on white. --mud-palette-divider is the token MudBlazor already swaps per
   mode, so the rule stops caring which mode is live. */
.heading {
    font-size: 24px;
    border-bottom: 3px solid var(--mud-palette-divider, rgba(0,0,0,.12));
    margin-bottom: 0;
    margin-top: 10px;
    padding: 5px 0;
}

.section-head {
    font-size: 24px;
    border-bottom: 2px solid gray;
    margin-bottom: 0;
    margin-top: 20px;
}

.status {
    padding: 5px 10px;
    border-start-start-radius: 10px;
    border-end-start-radius: 10px;
    display: flex;
    text-align: center;
    font-weight: bold;
    min-width: 60px;
}
.form-group {
    margin-bottom: 5px !important;
}

.bm-header {    
    padding: 10px 20px !important;
    background-color: royalblue;
    color: white;
}
.form-area {
    max-width: 920px;
    margin: 0 auto;
}

.sub-total {
    border-bottom: 1px solid gray;
    border-top: 1px solid gray;
}

.grand-total {
    border-bottom: 2px solid gray;
    border-top: 1px solid gray;
}

.login-area {
    max-width: 400px;
    margin: 0 auto;
    padding: 30px;
    border-radius: 10px;
    border: 1px solid gray;
}

.login-page {
    background-color: darkgray;
    background-image: url(/images/background.png);
    
}

    .login-page h1 {
        font-size: 24px;
    }

    .mud-tab {
        min-width: auto;
    }

h1.header {
    display: flex;
    flex-direction: row;
}

    h1.header:before, h1:after {
        content: "";
        flex: 1 1;
        border-bottom: 5px solid;
        margin: auto;
    }

    h1.header:before {
        margin-right: 10px
    }

    h1.header:after {
        margin-left: 10px
    }

    .blazored-modal {
        padding: 0 !important;
        z-index: 2000 !important;
    }



td, th {
    /*text-align: center;*/ /* Horizontal alignment */
    vertical-align: middle; /* Vertical alignment */
    padding: 5px; /* Optional for spacing */
}

.side-modal-overlay {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(0,0,0,0.4);
    z-index: 2040;
}

.side-modal {
    position: fixed;
    top: 0;
    right: 0;
    width: 400px;
    height: 100%;
    background-color: #fff;
    box-shadow: -2px 0 8px rgba(0,0,0,0.2);
    z-index: 2050;
    display: flex;
    flex-direction: column;
    animation: slideIn 0.3s ease-out forwards;
}

@keyframes slideIn {
    from {
        transform: translateX(100%);
    }

    to {
        transform: translateX(0);
    }
}

.side-modal-header {
    padding: 1rem;
    border-bottom: 1px solid #ddd;
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.side-modal-body {
    padding: 1rem;
    overflow-y: auto;
    flex-grow: 1;
}

.close-btn {
    background: none;
    border: none;
    font-size: 1.5rem;
    cursor: pointer;
}

.modal-class {
    max-height: 90%;
}

/* ==========================================================================
   Modal dialogs — one scrollbar, and it belongs to the dialog.

   Every editor dialog used to show two vertical scrollbars: its own, from the
   form body's `max-height: 70vh; overflow-y: auto`, and a second one down the
   right of the window. The second one appeared because the dialog is free to
   grow taller than the screen — 70vh of body, plus the title bar, the form
   padding, the validation summary and the buttons row, comes to more than
   100vh — and whatever is behind it then has to scroll to reach the bottom of
   the dialog.

   The fix is structural rather than another guessed height: cap the dialog at
   the viewport, and let the body inside it take whatever space is left over.
   The per-dialog `max-height: 70vh` rules have been removed to match, so the
   markup no longer has to predict how tall its own chrome is.

   Loaded after MudBlazor.min.css (see App.razor), so these win on order at
   equal specificity.
   ========================================================================== */

/* Nothing outside the dialog scrolls while it is open. */
.mud-dialog-container {
    overflow: hidden;
}

body:has(.mud-dialog-container) {
    overflow: hidden;
}

.mud-dialog {
    display: flex;
    flex-direction: column;
    /* dvh, so the mobile address bar sliding away does not leave a gap. */
    max-height: calc(100dvh - 3rem);
    overflow: hidden;
}

.mud-dialog > .mud-dialog-title,
.mud-dialog > .mud-dialog-actions {
    flex: 0 0 auto;
}

/* The dialog body. Most of these dialogs render an EditForm straight into the
   dialog rather than wrapping it in <MudDialog>, so the body element is a
   <form> as often as it is .mud-dialog-content — and a couple are a plain div.
   All three take the space the title and actions leave and scroll inside it.
   min-height: 0 is what actually allows that: without it a flex child refuses
   to shrink below its content and the overflow moves back outside. */
.mud-dialog > .mud-dialog-content,
.mud-dialog > form,
.mud-dialog > div:not(.mud-dialog-title):not(.mud-dialog-actions) {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    /* Bootstrap rows hang 12px outside their parent on each side. That 24px is
       empty gutter — the columns' own padding — but it was enough to raise a
       horizontal scrollbar under every dialog. Clip it. */
    overflow-x: hidden;
}

/* The exception: a handful of older forms declare a fixed min-width wider than
   the dialog they open in (min-width: 800px inside a 600px dialog). Clipping
   those would put real fields off-screen with no way to reach them, so they
   keep a horizontal scrollbar. Narrowing them to fit is the better fix, one
   form at a time. */
.mud-dialog > form[style*="min-width"] {
    overflow-x: auto;
}

/* A form that marks its own scrolling body keeps its Save / Discard row
   pinned at the bottom instead of scrolling it away. The form becomes the
   column, .dialog-scroll is the only part that moves. */
.mud-dialog > form:has(> .dialog-scroll) {
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.mud-dialog > form:has(> .dialog-scroll) > :not(.dialog-scroll) {
    flex: 0 0 auto;
}

.dialog-scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    /* Bootstrap rows carry negative side margins that poke ~12px outside an
       unpadded parent. That is empty gutter, so clip it rather than raise a
       horizontal scrollbar over nothing. */
    overflow-x: hidden;
}

/* Modal content */
.blazored-modal-content {
    background-color: var(--mud-palette-surface) !important;
    color: var(--mud-palette-text-primary) !important;
    border-radius: 8px;
    box-shadow: var(--mud-elevation-6); /* MudBlazor shadow */
}

.dropArea {
    border: 2px dashed gray;
    padding: 10px 20px;
    display: flex;
    text-align: center;
    margin-bottom: 20px;
    align-items: center;
    justify-content: center;
    font-size: .8rem;
    cursor: pointer;
    position: relative;
    min-height: 40px;
}

    .dropArea:hover {
        background-color: antiquewhite;
        color: #333;
    }

    .dropArea input[type=file] {
        position: absolute;
        width: 100%;
        height: 100%;
        opacity: 0;
        cursor: pointer;
    }

.dropAreaDrug {
    background-color: darkgray;
}


.fileinput-button {
    border: 2px dashed gray;
    padding: 5px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: .85rem;
    cursor: pointer;
    position: relative;
    max-height: 40px;
    width: 100%;
}

    .fileinput-button input[type=file] {
        position: absolute;
        width: 100%;
        height: 100%;
        opacity: 0;
        display: block;
        cursor: pointer;
    }

.animated-background {
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    overflow: hidden;
    z-index: -2;
}

.bg-frame {
    position: absolute;
    width: 100%;
    height: 100%;
    background-size: cover;
    background-position: center;
    animation: fadeImages 20s infinite;
    opacity: 0;
    will-change: opacity, transform;
}

    /* NOTE: source files on disk are .JPG (uppercase) — Windows dev boxes resolve
       either case, but this matters on case-sensitive (Linux) hosting. */
    .bg-frame:nth-child(1) {
        background-image: url('/images/bg-01.JPG');
        animation-delay: 0s;
    }

    .bg-frame:nth-child(2) {
        background-image: url('/images/bg-02.JPG');
        animation-delay: 5s;
    }

    .bg-frame:nth-child(3) {
        background-image: url('/images/bg-03.JPG');
        animation-delay: 10s;
    }
    .bg-frame:nth-child(4) {
        background-image: url('/images/bg-04.JPG');
        animation-delay: 15s;
    }

@keyframes fadeImages {
    0% {
        opacity: 0;
        transform: scale(1.06);
    }

    8% {
        opacity: 1;
    }

    25% {
        opacity: 1;
        transform: scale(1.12);
    }

    33% {
        opacity: 0;
    }

    100% {
        opacity: 0;
    }
}

/* Darkening/brand-tint overlay so foreground content stays readable over any photo. */
.bg-overlay {
    position: fixed;
    inset: 0;
    z-index: -1;
    background: linear-gradient(160deg, rgba(5, 39, 103, 0.82) 0%, rgba(58, 6, 71, 0.78) 100%);
}

[data-bs-theme="dark"] .bg-overlay {
    background: linear-gradient(160deg, rgba(3, 12, 32, 0.9) 0%, rgba(24, 4, 30, 0.88) 100%);
}

@media (prefers-reduced-motion: reduce) {
    .bg-frame {
        animation: none;
        opacity: 1;
    }
}

.transparent-content {
    background-color: transparent !important;
    box-shadow: none;
}

/* ── Links ──────────────────────────────────────────────────────────────────
   Nothing in this stylesheet gave <a> a colour, so unclassed links fell through
   to Bootstrap's reboot and, for the visited state, to the user agent — whose
   :visited purple is unreadable on the dark surface. Declaring `a` covers
   :link and :visited together (an author rule beats the UA's :visited rule),
   so a visited link now looks exactly like an unvisited one.

   The accent used to be a pair of hand-picked blues rather than
   --mud-palette-primary, because the tenant's PaletteDark.Primary was the same
   deep navy as its light one and links disappeared in dark mode.

   That root cause is now fixed. AppThemeService.MapToMudTheme derives the dark
   palette with ColorUtils.ForDarkSurface, which lifts each brand colour until it
   clears WCAG AA on the dark surface (#0054A6 -> #5990C5, 4.94:1) instead of
   darkening it (#001567, 1.16:1). So --mud-palette-primary is now a colour that
   is legible in BOTH modes, and --app-accent is simply an alias for it. One
   accent, defined once, following the tenant's own brand colour.

   The literal is only a fallback for the moment before MudThemeProvider has
   emitted its :root block — MudBlazor.min.css consumes these variables but
   defines none of them.

   Defined on :root rather than on .app-light / .app-dark because dialogs,
   popovers and the error UI render as siblings of MudLayout and never see those
   classes. MainLayout still stamps them; nothing here needs them any more.

   MudBlazor's own anchors (.mud-nav-link, .mud-button-root) and the tiles and
   bar rows on the members dashboard all set colour via a class, so they keep
   winning on specificity — this only reaches genuinely unstyled links.        */
:root {
    --app-accent: var(--mud-palette-primary, #2a78d6);
}

/* A bare `a` here is deliberate — do NOT write `a:visited`.
   Author rules beat the user agent's stylesheet regardless of specificity, so
   this single selector already covers :link AND :visited and kills the UA's
   purple. Spelling out `a:visited` raises specificity to 0,1,1, which outranks
   MudBlazor's own `.mud-nav-link` (0,1,0) — that is what turned every visited
   item in the nav drawer blue. At 0,0,1 this rule loses to every component
   class, so it only ever reaches genuinely unstyled links. */
a {
    color: var(--app-accent);
}

/* Hover affordance, restricted to anchors carrying no class at all, so it
   cannot reach MudBlazor's or Bootstrap's own components. */
a:not([class]):hover {
    text-decoration: underline;
}

/* The active nav row is left to MudBlazor now. Its own rule paints it with
   --mud-palette-primary, which since the AppThemeService fix is a colour that
   passes AA on the drawer in both modes — so the override that used to sit here
   (reproducing their 0,5,0 selector to repaint it with --app-accent) would only
   restate what they already do. Removed rather than kept as a no-op.

   Keeping the note because the specificity is a trap if this ever needs
   overriding again: their selector is
     .mud-navmenu.mud-navmenu-default .mud-nav-link.active:not(.mud-nav-link-disabled)
   at 0,5,0, and an earlier attempt here at 0,3,0 silently lost every time. Match
   it exactly, and rely on site.css being linked after MudBlazor.min.css. Their
   font-weight is !important, so that one needs !important to beat. */



/* ──────────────────────────────────────────────────────────────────────────
   Bootstrap 5.3 colour mode
   ──────────────────────────────────────────────────────────────────────────
   MainLayout.SyncBootstrapTheme stamps data-bs-theme="dark"/"light" on <html>
   from the same flag that drives MudBlazor, so Bootstrap's own variables
   (--bs-body-bg, --bs-border-color, --bs-emphasis-color, .table, .card) follow
   the toggle. Nothing below re-implements that; these are only the app's own
   classes, which Bootstrap knows nothing about.

   `.inputlabel` is the label cell in the Classic ASP detail tables — carried
   over by MemberHeader.razor. It had no rule at all in this project, so those
   cells rendered as ordinary body text and the label/value distinction that
   makes the header readable was lost in both modes.                          */
/* Every --mud-palette-* below carries a fallback on purpose. MudBlazor.min.css
   only CONSUMES these variables — it defines none of them. MudThemeProvider emits
   them at runtime as an inline :root block, so before the circuit renders (and in
   any context where the provider is absent) the var() would otherwise resolve to
   an invalid value rather than to nothing.

   Note the spelling: MudBlazor uses --mud-palette-background-gray, American, with
   no `grey` variant anywhere in the package. */
.inputlabel {
    font-weight: 600;
    color: var(--mud-palette-text-secondary, rgba(0,0,0,.6));
    background-color: var(--mud-palette-background-gray, #f5f5f5);
    white-space: nowrap;
}

/* The member header sits inside a MudCard, so its own borders should be the
   card's, not Bootstrap's default grey. Scoped to the class rather than to
   `.table` so no other Bootstrap table is affected. */
.member-header-table,
.member-header-table > tbody > tr > td {
    border-color: var(--mud-palette-lines-default, rgba(0,0,0,.12));
}

.member-header-table > tbody > tr > td {
    padding: .35rem .5rem;
    vertical-align: middle;
}


/* ──────────────────────────────────────────────────────────────────────────
   App-bar account menu
   ──────────────────────────────────────────────────────────────────────────
   Global rather than a MainLayout.razor.css. Scoped CSS stamps its b-xxxxx
   attribute only on plain elements written in the component's own markup, never
   on markup emitted by a child component — so `.user-avatar` sitting on
   <MudAvatar> would never have matched. The menu body compounds it: MudMenu
   hands its content to MudPopoverProvider, which renders outside MudLayout, so
   a ::deep rule anchored on the layout would not reach it either.

   Every colour is a --mud-palette-* variable with a literal fallback, so the
   menu follows the tenant's theme and the device's light/dark mode with nothing
   further to wire up. MudThemeProvider emits those variables at runtime and
   MudBlazor.min.css only consumes them, hence the fallbacks.               */

.user-avatar-button {
    cursor: pointer;
    display: flex;
    align-items: center;
    border-radius: 50%;
    /* Matches the ripple padding on the app bar's other icon buttons so the
       avatar sits on the same optical line as the menu and theme icons. */
    margin-inline-start: 4px;
}

.user-avatar-button:hover {
    opacity: .85;
}

/* The <img> fills the MudAvatar circle. object-fit keeps a non-square upload
   from being stretched — cooperative member photos are rarely square. */
.user-avatar-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 50%;
    display: block;
}

.user-menu-head {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: .85rem 1rem;
    min-width: 240px;
    max-width: 320px;
}

/* min-width:0 is what lets the ellipsis below actually work: a flex item
   defaults to min-width:auto, which refuses to shrink below its content and
   makes the menu grow instead of truncating a long address. */
.user-menu-identity {
    min-width: 0;
}

.user-menu-name {
    font-weight: 600;
    font-size: .9rem;
    line-height: 1.3;
    color: var(--mud-palette-text-primary, rgba(0,0,0,.87));
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.user-menu-email {
    font-size: .78rem;
    line-height: 1.3;
    color: var(--mud-palette-text-secondary, rgba(0,0,0,.6));
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* A real <button type="submit">, not a MudMenuItem: it belongs to the hidden
   #logoutForm in the app bar via the `form` attribute, and only a native submit
   button can do that. Styled to sit flush with MudBlazor's own list rows. */
.user-menu-signout {
    display: flex;
    align-items: center;
    gap: .6rem;
    width: 100%;
    padding: .6rem 1rem;
    border: 0;
    background: none;
    font: inherit;
    font-size: .875rem;
    text-align: start;
    cursor: pointer;
    color: var(--mud-palette-text-primary, rgba(0,0,0,.87));
}

.user-menu-signout:hover {
    background-color: var(--mud-palette-action-default-hover, rgba(0,0,0,.06));
}

.user-menu-signout:focus-visible {
    outline: 2px solid var(--mud-palette-primary, #2a78d6);
    outline-offset: -2px;
}
