/* The real cause of the "page too big, needs a pinch to fix" report: a 64px logo plus the full
   org name never wrapped or shrank, so the navbar (and the whole page, since nothing constrained
   its width) rendered wider than a phone screen - genuine horizontal overflow, not a zoom/DPI
   issue. Browsers don't auto-zoom-out to compensate; they just let it overflow. Keeping the logo
   at full size, so instead of shrinking anything, the brand's own contents (logo + name) and the
   rest of the navbar are both allowed to wrap onto extra lines if they don't fit on one. */
.navbar .container-fluid {
    flex-wrap: wrap;
    align-items: center;
    row-gap: 0.5rem;
}

/* Pins the avatar/login menu to the navbar's right edge via normal flex flow (margin-left: auto
   pushes it to the far end of its flex line, wrapping onto its own line below the brand block if
   it doesn't fit next to it - same trick used everywhere else in this app for "push this to the
   end"). A previous version used position:absolute with a hardcoded pixel offset (top: 87px)
   calculated for one specific logo+banner+social-icons height - broke two different ways
   depending on the org's actual configuration: overlapping page content below when the real
   navbar was shorter than assumed (no logo/banner configured), or landing behind/under other
   content when it wrapped taller on a narrow phone screen (real logo+banner+social icons all
   present). Flex flow adapts to whatever the navbar's actual height turns out to be instead of
   guessing it up front. */
.navbar-account-menu {
    margin: 0 0 0 auto !important;
}

/* flex-basis:100% forces a line break after the brand in the wrapping flex container above (a
   standard flex multi-row technique) - brand/logo always gets its own full-width row, at any
   screen size, and the social icons + avatar (now plain flex siblings of brand, not nested inside
   it) naturally share the row underneath, with the avatar still pinned to that row's own right
   edge via .navbar-account-menu's margin-left:auto above. This replaced an earlier attempt built
   on nested flex-column + a mobile-only CSS grid switch (using display:contents to "unwrap" the
   nesting) - that relies on display:contents interacting correctly with grid auto-placement,
   which isn't consistently supported across browsers and broke on the org's own phone. Plain
   flex-wrap has no such gap and needs no nesting or media query at all - the same rule produces
   the right layout on both desktop and mobile. */
.navbar-brand {
    flex-wrap: wrap;
    flex-basis: 100%;
}

.navbar-logo {
    height: 64px;
}

/* The closed nav rail (see .collapsible-panel.closed) eats into the available width on every
   authenticated page - the login page has no rail at all, which is why only there the full-size
   brand text fit without clipping. Shrinking both the logo and the text on narrow screens gives
   the org name enough room to sit beside the logo instead of wrapping onto its own line below it
   (the .navbar-brand flex-wrap above stays on as a safety net for an org name too long to fit even
   at this size, rather than risking the horizontal-overflow bug this navbar had before). */
@media (max-width: 767.98px) {
    .navbar-logo {
        height: 40px;
    }

    .navbar-brand-text {
        font-size: 0.9rem;
        white-space: nowrap;
    }
}

/* The footer's copyright/build columns sit right next to each other (justify-content-between
   with only two items) - on a narrow screen the copyright text wraps and its widest line can
   butt up against the build version column with no gap. Shrinking the text below md gives both
   columns more room without changing the layout. */
@media (max-width: 767.98px) {
    footer.app-footer {
        font-size: 0.75rem;
    }
}

/* Stops Android Chrome's automatic text/layout "boosting" after a page load or big DOM change
   (e.g. the login redirect, or the nav panel opening/closing) - that auto-resize is what needed
   a manual pinch to correct, not an actual overflow bug. Doesn't affect the user's own ability
   to pinch-zoom. */
html {
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
}

h1:focus {
    outline: none;
}

/* Nav sidebar links are real <button>s (see NavSidebar.razor) so navigation can be driven
   programmatically, but they should still look and feel exactly like the plain links they
   replaced. Hover gets a washed-out solid fill (a lighter tint of the theme's primary colour,
   like an inactive button); the current page's own link gets Bootstrap's normal nav-pills
   ".active" treatment (solid primary fill, white text) and stays that way - "sticky" rather
   than just a hover flash - via NavLinkClass() in the code-behind. */
.nav-pills .nav-link.btn-link {
    color: var(--bs-body-color);
    text-decoration: none;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.nav-pills .nav-link.btn-link:hover,
.nav-pills .nav-link.btn-link:focus {
    background-color: color-mix(in srgb, var(--bs-primary) 55%, white);
    color: #fff;
    text-decoration: none;
    box-shadow: none;
}

/* Same specificity as .nav-pills .nav-link.btn-link above, but this one needs to win for the
   active link's own resting state too (not just its :hover/:focus, handled below) - without it,
   Bootstrap's own .nav-pills .nav-link.active white-text rule loses the cascade to our later
   app.css rule above (equal specificity, later source order), leaving the active item's blue
   background with the wrong (dark) text/icon colour. The nav icons use fill="currentColor" so
   this one rule covers both text and icon. */
.nav-pills .nav-link.btn-link.active,
.nav-pills .nav-link.btn-link.active:hover,
.nav-pills .nav-link.btn-link.active:focus {
    background-color: var(--bs-primary);
    color: #fff;
}

/* Home page stat cards - styled like outline buttons (border/text in the button colour, solid
   fill on hover) so it's obvious they're clickable, not just informational. */
.stat-card-link {
    border-color: var(--bs-primary);
    color: var(--bs-primary);
    transition: background-color 0.15s ease, color 0.15s ease;
}

.stat-card-link:hover {
    background-color: var(--bs-primary);
    color: #fff;
}

.stat-card-link:hover p {
    color: inherit !important;
}

/* Documents page's "Upload a document" card collapses to give the document list more room -
   plain .card-header doesn't get Bootstrap's accordion-button chevron styling for free, so this
   adds an equivalent one by hand, rotating in step with the same .collapsed class Bootstrap's
   collapse JS already toggles on the trigger element. */
.card-header[data-bs-toggle="collapse"] {
    cursor: pointer;
    user-select: none;
}

.upload-toggle-chevron {
    transition: transform 0.2s ease;
}

.card-header[data-bs-toggle="collapse"].collapsed .upload-toggle-chevron {
    transform: rotate(-90deg);
}

.stat-card-link-danger {
    border-color: var(--bs-danger);
    color: var(--bs-danger);
}

.stat-card-link-danger:hover {
    background-color: var(--bs-danger);
    color: #fff;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid #e50000;
}

.validation-message {
    color: #e50000;
}

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

.darker-border-checkbox.form-check-input {
    border-color: #929292;
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
    color: var(--bs-secondary-color);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
    text-align: start;
}

.cat-hover-link {
    position: relative;
    display: inline-block;
}

.cat-hover-thumb {
    display: none;
    position: absolute;
    bottom: 100%;
    left: 0;
    width: 32px;
    height: 32px;
    object-fit: cover;
    border: 1px solid var(--bs-border-color, #dee2e6);
    border-radius: 4px;
    background: var(--bs-body-bg, #fff);
    z-index: 1000;
    margin-bottom: 2px;
}

.cat-hover-link:hover .cat-hover-thumb {
    display: block;
}

.navbar-dark .navbar-brand,
.navbar-dark .nav-link {
    color: var(--navbar-fg, rgba(255, 255, 255, 0.85));
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.85);
}

.navbar-dark .navbar-brand:hover,
.navbar-dark .nav-link:hover {
    color: var(--navbar-fg, #fff);
    opacity: 0.85;
}

.navbar .btn-outline-light {
    color: var(--navbar-fg, #f8f9fa);
    border-color: var(--navbar-fg, rgba(255, 255, 255, 0.5));
}

/* No margin-top here - .navbar .container-fluid's own row-gap now provides the space between the
   brand's row and this one, uniformly with whatever else shares this row (the avatar), instead of
   a per-item margin that would throw off their vertical centering against each other. */

.social-links .social-link {
    color: var(--navbar-fg, rgba(255, 255, 255, 0.85));
    display: inline-flex;
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.85);
    transition: opacity 0.15s ease, transform 0.15s ease;
}

.social-links .social-link:hover {
    color: var(--navbar-fg, #fff);
    opacity: 0.8;
    transform: translateY(-1px);
}

.navbar .btn-outline-light:hover {
    color: var(--navbar-fg, #f8f9fa);
    background-color: rgba(127, 127, 127, 0.2);
}

/* Sidebar + content sit side by side at md+ (the default .d-flex row behaviour); below 768px the
   row becomes a column so NavSidebar's mobile rendering (just the hamburger button - see that
   component) stacks in normal flow between the (now full-width) navbar above and the page content
   below, rather than needing a fixed-position guess at the navbar's actual height. */
@media (max-width: 767.98px) {
    .app-body-row {
        flex-direction: column;
    }
}

.app-nav-sidebar .app-nav-links {
    padding: 0.5rem 0;
}

.app-nav-sidebar .nav-link.btn-link {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}

.app-nav-sidebar .nav-icon {
    flex-shrink: 0;
}

.app-nav-static {
    width: 220px;
    flex-shrink: 0;
    border-right: 1px solid var(--bs-border-color, #dee2e6);
    overflow-y: auto;
}

/* Medium (768-1023.98px): icon-only, no user toggle - purely responsive, matching the plan's
   "no chevron/pin at all" for the whole redesign, not just the desktop tier. */
@media (max-width: 1023.98px) {
    .app-nav-static {
        width: 64px;
    }

    .app-nav-static .nav-label {
        display: none;
    }

    .app-nav-static .nav-link.btn-link {
        justify-content: center;
    }

    .app-nav-static .nav-icon {
        width: 20px;
        height: 20px;
    }
}

.nav-hamburger {
    margin: 0.5rem 0 0 0.75rem;
    width: 44px;
    height: 40px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    border: 1px solid var(--bs-border-color, #dee2e6);
    border-radius: 0.375rem;
    background: var(--bs-body-bg, #fff);
    color: var(--bs-body-color);
}

.nav-hamburger span {
    display: block;
    width: 20px;
    height: 2px;
    background: currentColor;
}

/* Always rendered (prerendered with the rest of NavSidebar), hidden until app.js's hamburger
   handler puts .nav-mobile-open on <html> - see NavSidebar.razor for why the toggle is client-side. */
.nav-mobile-backdrop,
.app-nav-mobile-drawer {
    display: none;
}

html.nav-mobile-open .nav-mobile-backdrop {
    display: block;
}

html.nav-mobile-open .app-nav-mobile-drawer {
    display: flex;
}

.nav-mobile-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.35);
    z-index: 1040;
}

.app-nav-mobile-drawer {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    width: min(85vw, 320px);
    z-index: 1050;
    background: var(--bs-body-bg, #fff);
    box-shadow: 0 0 20px rgba(0, 0, 0, 0.35);
    overflow-y: auto;
}

.cat-journey-dot {
    width: 28px;
    height: 28px;
    font-size: 0.8rem;
}

.cat-journey-line {
    flex: 1 1 auto;
    height: 2px;
}

/* Font choices for DocumentTemplate rich text (RichTextEditor.razor / Quill). Self-hosted under
   wwwroot/fonts - no Google Fonts CDN request, matching this site's script-src/style-src 'self'
   CSP everywhere else. The family names here match exactly across three places that must agree:
   app.js's style-based font attributor whitelist, DocumentTemplateMergeService.
   AllowedFontFamilies (the sanitize/parse whitelist), and Program.cs's QuestPDF font registration
   for PDF rendering (which loads wwwroot/fonts/{FamilyName}.ttf by that same name) - one shared
   vocabulary. All four are OFL-licensed (wwwroot/fonts/OFL-*.txt). OpenSans/Merriweather are
   variable fonts - a single file's weight/style axes cover regular through bold for the in-browser
   preview; PlayfairDisplay is a variable weight axis but has no italic instance in this file, and
   CourierPrime is a single static weight - both synthesise bold/italic the same way PDF rendering
   already does for all four (verified visually acceptable in a real Docker container matching
   production before any of this was added). */
@font-face {
    font-family: 'OpenSans';
    src: url('/fonts/OpenSans.ttf') format('truetype-variations');
    font-weight: 300 800;
    font-style: normal;
}
@font-face {
    font-family: 'Merriweather';
    src: url('/fonts/Merriweather.ttf') format('truetype-variations');
    font-weight: 300 900;
    font-style: normal italic;
}
@font-face {
    font-family: 'PlayfairDisplay';
    src: url('/fonts/PlayfairDisplay.ttf') format('truetype-variations');
    font-weight: 400 900;
    font-style: normal;
}
@font-face {
    font-family: 'CourierPrime';
    src: url('/fonts/CourierPrime.ttf') format('truetype');
    font-weight: 400;
    font-style: normal;
}

/* Quill's snow theme hardcodes the font picker's "unset" option label to "Sans Serif" (baked in
   for its own default serif/monospace whitelist) - overridden per actual whitelist value here
   since this app offers a different set instead (see app.js's font attributor registration). Each
   ::before rule also previews the option in its own actual font. */
.ql-snow .ql-picker.ql-font .ql-picker-label::before,
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
    content: 'Default';
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="OpenSans"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="OpenSans"]::before {
    content: 'Open Sans';
    font-family: 'OpenSans', sans-serif;
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="Merriweather"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="Merriweather"]::before {
    content: 'Merriweather';
    font-family: 'Merriweather', serif;
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="PlayfairDisplay"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="PlayfairDisplay"]::before {
    content: 'Playfair Display';
    font-family: 'PlayfairDisplay', serif;
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="CourierPrime"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="CourierPrime"]::before {
    content: 'Courier Prime';
    font-family: 'CourierPrime', monospace;
}

/* Same "unlabelled custom whitelist falls back to Quill's own hardcoded default" gap as the font
   picker above, for the same reason: Quill's built-in size labels only cover its own small/large/
   huge keywords, so with this app's px-based whitelist (app.js) every option - including the unset
   default - fell back to the built-in default label "Normal", showing up as "Normal" repeated once
   per option with no way to tell them apart. Confirmed as a real report, not just a theoretical
   gap. */
.ql-snow .ql-picker.ql-size .ql-picker-label::before,
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
    content: 'Normal';
}

.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="8px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="8px"]::before {
    content: 'Small';
}

.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="10px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="10px"]::before {
    content: 'Compact';
}

.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="16px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="16px"]::before {
    content: 'Large';
}

.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="22px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="22px"]::before {
    content: 'Extra large';
}

.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="28px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="28px"]::before {
    content: 'Huge';
}

/* CatShare.razor's photo gallery thumbnail strip - see crlmWireCatGallery in app.js */
.crlm-gallery-thumb {
    opacity: 0.6;
    transition: opacity 0.15s, border-color 0.15s;
}

.crlm-gallery-thumb:hover {
    opacity: 0.85;
}

.crlm-gallery-thumb-active {
    opacity: 1;
    border-color: var(--bs-primary) !important;
    border-width: 2px !important;
}

/* AdoptableCatsShowcase.razor's cat cards - bio clamped to 6 lines with a bottom fade + "...more"
   link, only revealed when it actually overflows (see crlmWireBioClamp in app.js). line-height is
   set explicitly here (rather than relying on Bootstrap's inherited default) so the 6-line
   max-height below is guaranteed to line up with what's actually rendered. mask-image fades the
   real text pixels to transparent rather than overlaying a background-coloured gradient, so it
   works correctly in both light and dark theme with no colour to keep in sync. The "...more" link
   is a sibling of .cat-bio, not a child - CSS mask-image fades an element's entire painted output
   including its descendants, which would otherwise fade the link itself into unreadability right
   where it needs to stand out. */
.cat-bio-wrap {
    position: relative;
}

.cat-bio {
    line-height: 1.4;
    max-height: calc(1.4em * 6);
    overflow: hidden;
}

.cat-bio.cat-bio-clamped {
    -webkit-mask-image: linear-gradient(to bottom, black calc(100% - 1.4em), transparent 100%);
    mask-image: linear-gradient(to bottom, black calc(100% - 1.4em), transparent 100%);
}

.cat-bio-more {
    position: absolute;
    right: 0;
    bottom: 0;
    font-weight: 600;
    font-size: 0.8125em;
    color: var(--bs-secondary-color);
    text-decoration: underline;
}

.cat-bio-more:hover {
    color: var(--bs-body-color);
}

/* Bootstrap's .offcanvas-end defaults to a fixed 400px width regardless of viewport - fine on
   desktop, but wider than a phone screen. max-width caps it to whatever room is actually there
   without needing a breakpoint-specific override. */
.page-help-offcanvas {
    max-width: 100vw;
}
/* Page top bar: the app-wide position for a page's Back button (left) and "? Help" button (right),
   on its own row above the page title. Pages without a Back button still put Help top right here,
   so it's always in the same place. .page-nav-btn gives both buttons one identical size. */
.page-top-bar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
}

.page-nav-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.25rem;
    min-width: 5.5rem;
}

/* Phones (<768px, where the sidebar becomes the hamburger - see .nav-hamburger): Help moves up into
   the hamburger's row instead, at the far right, mirroring it - same inset from the edge and the
   same 44x40 size, icon only. .app-body-row is the positioning context (nothing between it and the button is
   positioned). A Back button stays top left of the page; a top bar holding only Help collapses,
   so pages without Back don't spend a row on it. */
@media (max-width: 767.98px) {
    .app-body-row {
        position: relative;
    }

    .page-top-bar .page-help-trigger {
        position: absolute;
        top: 0.5rem;
        right: 0.75rem;
        width: 44px;
        min-width: 0;
        height: 40px;
        padding: 0;
        /* Same outline, corners and colours as .nav-hamburger - via Bootstrap's button variables
           so the pressed/hover states stay in that look instead of switching to filled grey. */
        border-radius: 0.375rem;
        --bs-btn-border-width: 1px;
        --bs-btn-color: var(--bs-body-color);
        --bs-btn-bg: var(--bs-body-bg, #fff);
        --bs-btn-border-color: var(--bs-border-color, #dee2e6);
        --bs-btn-hover-color: var(--bs-body-color);
        --bs-btn-hover-bg: var(--bs-secondary-bg);
        --bs-btn-hover-border-color: var(--bs-border-color, #dee2e6);
        --bs-btn-active-color: var(--bs-body-color);
        --bs-btn-active-bg: var(--bs-secondary-bg);
        --bs-btn-active-border-color: var(--bs-border-color, #dee2e6);
    }

    .page-help-trigger .page-help-label {
        display: none;
    }

    .page-help-trigger svg {
        width: 20px;
        height: 20px;
    }

    .page-top-bar.justify-content-end {
        height: 0;
        margin-bottom: 0;
    }
}

/* Blazor error bar - hidden until Blazor itself shows it. Global rather than in
   MainLayout.razor.css (where the template put it): scoped CSS only applies to markup rendered by
   that one component, so PublicLayout's copy of this div was unstyled and permanently visible. */
#blazor-error-ui {
    color-scheme: light only;
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    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;
    }
