html, body {
    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
    overflow-x: hidden;
    min-height: 100vh;
    margin: 0;
    padding: 0;
}

/* The body was Bootstrap's white, and it shows.

   MainLayout puts 2rem of padding down the left of <article> and 1.5rem down the right. Pages that
   paint their own dark background sit inside that padding, so the gutters either side of them were
   showing the white body through — a pale strip down both edges of the content area on every page
   that had not been added to the exclusion list in MainLayout.razor.css. That list is a chain of
   :not(:has(...)) clauses, one per page, and it only ever covered the handful anyone had noticed:
   the photographer layout, the gallery, checkout, order-success and the admin pages.

   Colouring the body removes the reason those exemptions exist. The gutter still exists, it just
   matches what it sits beside, so a page that has never been special-cased looks right by default
   rather than by maintenance. --pi-bg is the base the page wrappers are built on. */
body {
    background-color: var(--pi-bg, #050816);
}

/* The default link colour for the site, which is dark nearly everywhere. #006bb7 was Bootstrap's
   blue for white pages and gave 3.6:1 on the page background — under the 4.5:1 AA floor. The 13
   stylesheets that set their own link colour are unaffected; this is what the other 60-odd
   components using a plain <a> fall back to. --pi-blue is 8.2:1 there.

   Buttons are untouched: <a class="btn btn-primary"> matches a class selector, which outranks this
   element one, so it keeps its own colour. */
a, .btn-link {
    color: var(--pi-blue, #00b7ff);
}

a:hover, .btn-link:hover {
    color: #ffffff;
}

/* Pale islands on a dark site. Bootstrap's surface components ship with white or near-white
   backgrounds, and the Account/Manage pages use them unthemed — so a link tuned for the dark theme
   is unreadable inside them. This is the one place the old dark blue was doing the right thing:
   "Contact Support" in a .card footer measured 2.15:1 against white after the change above, worse
   than the 3.6:1 it replaced.

   Inheriting rather than naming a colour, because it always resolves to the container's own text
   colour — which whoever styled that container already made readable against it. That holds
   whether the surface is still Bootstrap-white or has been themed dark, so these rules cannot
   themselves create a contrast failure. The underline carries the link affordance that dropping
   the colour gives up.

   :not(.btn) so a button inside one of these — which several pages have — keeps the colour its own
   class gives it instead of inheriting the panel's. */
.alert a:not(.btn),
.card a:not(.btn),
.modal-content a:not(.btn),
.list-group-item a:not(.btn),
.dropdown-menu a:not(.btn),
.toast a:not(.btn),
.bg-light a:not(.btn),
.bg-white a:not(.btn) {
    color: inherit;
    text-decoration: underline;
}

.alert a:not(.btn):hover,
.card a:not(.btn):hover,
.modal-content a:not(.btn):hover,
.list-group-item a:not(.btn):hover,
.dropdown-menu a:not(.btn):hover,
.toast a:not(.btn):hover,
.bg-light a:not(.btn):hover,
.bg-white a:not(.btn):hover {
    color: inherit;
}

.btn-primary {
    color: #fff;
    background-color: #1b6ec2;
    border-color: #1861ac;
}

.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
  box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
}

.content {
    padding-top: 0;
}

h1:focus {
    outline: none;
}

.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."
    }

#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;
    }

/* Sidebar overflow fix — prevent horizontal scrollbar */
.sidebar {
    overflow-x: hidden;
}

.nav-scrollable {
    overflow-x: hidden;
}

.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;
}

.text-decoration-underline-hover {
    text-decoration: none;
}

.text-decoration-underline-hover:hover {
    text-decoration: underline;
}

/* ===================================
   PHOTO INFINITY DESIGN SYSTEM
   =================================== */

* {
    box-sizing: border-box;
}

/* Layout */
.photo-infinity-layout {
    margin: 0;
    min-height: 100vh;
    background: radial-gradient(circle at 80% 30%, rgba(180, 0, 255, 0.22), transparent 30%),
                radial-gradient(circle at 20% 70%, rgba(0, 140, 255, 0.18), transparent 30%),
                #050812;
    color: white;
    display: flex;
    flex-direction: column;
    font-family: Inter, Arial, sans-serif;
}

/* Header */
.photo-infinity-header {
    height: 78px;
    padding: 0 50px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-bottom: 1px solid rgba(255, 255, 255, 0.12);
    background: rgba(5, 8, 18, 0.7);
    backdrop-filter: blur(15px);
}

.pi-logo {
    font-size: 26px;
    font-weight: 700;
    display: flex;
    gap: 12px;
    align-items: center;
    color: white;
}

.pi-infinity {
    font-size: 40px;
    background: linear-gradient(90deg, #00b7ff, #7b32ff, #ff36c9);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}

.pi-nav a {
    color: #ddd;
    margin-left: 35px;
    text-decoration: none;
    transition: color 0.2s;
}

.pi-nav a:hover {
    color: #00b7ff;
}

/* Main Content */
.photo-infinity-main {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 100px;
    padding: 60px;
}

/* Base card styles (used by multiple pages) */
.pi-card {
    border-radius: 22px;
    overflow: hidden;
    transition: transform 0.3s ease;
}

.pi-card img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Footer */
.photo-infinity-footer {
    padding: 25px 60px;
    border-top: 1px solid rgba(255, 255, 255, 0.12);
    display: flex;
    justify-content: space-between;
    color: #aaa;
    font-size: 14px;
}

/* Responsive Design */
@media (max-width: 1200px) {
}

@media (max-width: 1000px) {
    .photo-infinity-main {
        padding: 30px;
    }
}

@media (max-width: 600px) {
    /* A fixed height plus non-wrapping flex made the brand and the nav collide at
       phone widths: "Photo Infinity" and "Browse Photos" each broke across two
       lines and spilled out of the 65px box. Let the bar grow and wrap into two
       centred rows instead, and keep each label on a single line. */
    .photo-infinity-header {
        padding: 12px 20px;
        height: auto;
        min-height: 65px;
        flex-wrap: wrap;
        justify-content: center;
        row-gap: 6px;
    }

    .pi-logo {
        font-size: 20px;
        white-space: nowrap;
    }

    .pi-infinity {
        font-size: 32px;
    }

    .pi-nav {
        display: flex;
        justify-content: center;
    }

    .pi-nav a {
        margin: 0 12px;
        font-size: 14px;
        white-space: nowrap;
    }

    .photo-infinity-main {
        padding: 20px;
    }

    .photo-infinity-footer {
        padding: 20px;
        flex-direction: column;
        gap: 10px;
        text-align: center;
    }
}

/* ===================================
   SHARED GLOBAL STYLES
   =================================== */

:root {
    --pi-bg: #050816;
    --pi-panel: rgba(11, 16, 36, 0.85);

    /* Same value as --pi-panel, under the name six scoped stylesheets already ask for.
       BulkUpload, Checkout, CreateEvent, EditEvent, EventBorderManage and EventView each declared
       it in a ":root" block of their own — but those are component stylesheets, so Blazor rewrites
       the selector to ":root[b-xxxxx]" and <html> never carries a component's scope attribute. The
       variable was therefore defined nowhere, and "background: var(--pi-card-bg)" on .pi-card is
       invalid at computed-value time, which makes the whole declaration "unset" — transparent, and
       overriding the .pi-card background just below. Every card panel on those six pages was see
       -through against the page gradient. */
    --pi-card-bg: rgba(11, 16, 36, 0.85);

    --pi-line: rgba(255, 255, 255, 0.08);

    /* The muted grey the dark theme already uses for secondary text — 7.6:1 on --pi-panel. Named
       here so the Bootstrap corrections below do not each invent their own. */
    --pi-text-muted: #9aa5bd;

    --pi-blue: #00b7ff;
    --pi-green: #2ecc71;
    --pi-cyan: #a3edfd;
    --pi-gold: #f2e562;
    --pi-purple: #8b35ff;
    --pi-pink: #ff36c9;
}

/* Shared card component styles */
.pi-card {
    background: var(--pi-panel);
    border: 1px solid var(--pi-line);
    border-radius: 16px;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.35);
    padding: 22px;
    height: 100%;
}

/* Button styling */
.pi-button {
    display: inline-block;
    padding: 12px 20px;
    border-radius: 12px;
    background: linear-gradient(90deg, var(--pi-purple), var(--pi-blue));
    color: white;
    text-decoration: none;
    border: none;
    cursor: pointer;
    transition: all 0.2s;
}

.pi-button:hover {
    opacity: 0.9;
    transform: translateY(-1px);
    color: white;
}

.pi-badge {
    background: linear-gradient(90deg, var(--pi-purple), var(--pi-blue));
    color: white;
    padding: 4px 12px;
    border-radius: 8px;
    font-size: 12px;
    font-weight: 600;
}

/* Responsive rules for the layout classes above live with them, further up this
   file — a second copy used to sit here and silently won the cascade, so edits to
   the original had no effect. */

/* Public Gallery Page - Full Width Override */
body:has(.pi-gallery-page) {
    margin: 0 !important;
    padding: 0 !important;
    background: #050816 !important;
}

body:has(.pi-gallery-page) .page {
    margin: 0 !important;
    padding: 0 !important;
}

body:has(.pi-gallery-page) main {
    margin: 0 !important;
    padding: 0 !important;
}

body:has(.pi-gallery-page) article {
    margin: 0 !important;
    padding: 0 !important;
}

/* Cart Page - Full Width Override */
body:has(.pi-cart-page) {
    margin: 0 !important;
    padding: 0 !important;
    background: #050816 !important;
}

body:has(.pi-cart-page) .page {
    margin: 0 !important;
    padding: 0 !important;
}

body:has(.pi-cart-page) main {
    margin: 0 !important;
    padding: 0 !important;
}

body:has(.pi-cart-page) article {
    margin: 0 !important;
    padding: 0 !important;
}

/* My Downloads Page - Full Width Override */
body:has(.pi-downloads-page) {
    margin: 0 !important;
    padding: 0 !important;
    background: #050816 !important;
}

body:has(.pi-downloads-page) .page {
    margin: 0 !important;
    padding: 0 !important;
}

body:has(.pi-downloads-page) main {
    margin: 0 !important;
    padding: 0 !important;
}

body:has(.pi-downloads-page) article {
    margin: 0 !important;
    padding: 0 !important;
}

/* Account pages that paint their own dark background. Their wrapper is only as wide as the
   layout's content column, so without this the body's white shows down the right-hand side,
   and on overscroll. Must live here: scoped CSS cannot reach body. */
/* .pi-confirm-page covers RegisterConfirmation, ConfirmEmail and ResendEmailConfirmation. */
/* .pi-auth-page is the shared AuthMessage component: ForgotPasswordConfirmation,
   ResetPasswordConfirmation, InvalidPasswordReset, InvalidUser and Lockout. */
body:has(.pi-denied-page),
body:has(.pi-auth-page),
body:has(.pi-confirm-page) {
    background: #050816 !important;
}

/* Not Found Page - Full Width Override */
body:has(.pi-notfound-page) {
    margin: 0 !important;
    padding: 0 !important;
    background: #050816 !important;
}

body:has(.pi-notfound-page) .page,
body:has(.pi-notfound-page) main,
body:has(.pi-notfound-page) article {
    margin: 0 !important;
    padding: 0 !important;
}

/* Customer Portal - Full Width Override */
body:has(.pi-customer-portal-page) {
    margin: 0 !important;
    padding: 0 !important;
    background: #050816 !important;
}

body:has(.pi-customer-portal-page) .page {
    margin: 0 !important;
    padding: 0 !important;
}

body:has(.pi-customer-portal-page) main {
    margin: 0 !important;
    padding: 0 !important;
}

body:has(.pi-customer-portal-page) article {
    margin: 0 !important;
    padding: 0 !important;
}

/* Order Confirmation Page - Full Width Override */
/* Here rather than in OrderSuccess.razor.css, for the same reason as the orders block below. */
body:has(.pi-order-success-page) {
    margin: 0 !important;
    padding: 0 !important;
    background: #050816 !important;
}

body:has(.pi-order-success-page) .page {
    margin: 0 !important;
    padding: 0 !important;
}

body:has(.pi-order-success-page) main {
    margin: 0 !important;
    padding: 0 !important;
}

body:has(.pi-order-success-page) article {
    margin: 0 !important;
    padding: 0 !important;
}

/* My Orders Page - Full Width Override */
/* Lives here, not in Orders.razor.css: scoped CSS stamps the component's b-… attribute onto
   the last element of the selector, so a copy in that file compiled to
   body:has(.pi-orders-page)[b-…] and never matched anything. */
body:has(.pi-orders-page) {
    margin: 0 !important;
    padding: 0 !important;
    background: #050816 !important;
}

body:has(.pi-orders-page) .page {
    margin: 0 !important;
    padding: 0 !important;
}

body:has(.pi-orders-page) main {
    margin: 0 !important;
    padding: 0 !important;
}

body:has(.pi-orders-page) article {
    margin: 0 !important;
    padding: 0 !important;
}

/* Browse Page - Full Width Override */
body:has(.pi-browse-page) {
    margin: 0 !important;
    padding: 0 !important;
    background: #050816 !important;
}

body:has(.pi-browse-page) .page {
    margin: 0 !important;
    padding: 0 !important;
}

body:has(.pi-browse-page) main {
    margin: 0 !important;
    padding: 0 !important;
}

body:has(.pi-browse-page) article {
    margin: 0 !important;
    padding: 0 !important;
}

/* Checkout Page - Full Width Override */
body:has(.pi-checkout-page) {
    margin: 0 !important;
    padding: 0 !important;
    background: #050816 !important;
}

body:has(.pi-checkout-page) .page {
    margin: 0 !important;
    padding: 0 !important;
}

body:has(.pi-checkout-page) main {
    margin: 0 !important;
    padding: 0 !important;
}

body:has(.pi-checkout-page) article {
    margin: 0 !important;
    padding: 0 !important;
}

/* ===================================
   ADMIN AREA THEME
   ===================================

   Shared rather than per-page: there are eleven admin pages and they were all plain Bootstrap on
   the browser's white, so giving each its own stylesheet would mean eleven copies of the same
   overrides drifting apart. An admin page opts in by wrapping its markup — modals included, since
   those sit outside the main container — in <div class="pi-admin-page">.

   These override the Bootstrap classes already in the admin markup rather than replacing them, so
   a page joins the theme without being rewritten. */

.pi-admin-page {
    min-height: 100vh;
    background: radial-gradient(circle at 80% 0%, rgba(139, 53, 255, 0.18), transparent 35%),
                radial-gradient(circle at 15% 40%, rgba(0, 140, 255, 0.14), transparent 35%),
                var(--pi-bg);
    color: #e6ebf7;
    padding: 1.5rem 0.75rem 3rem;
}

/* article.content carries 32px of left padding and 24px of right, which left the dark page inset
   with a white strip down each side. Same treatment the checkout page already needed, and the
   body is painted too so nothing shows through beneath a short page. */
body:has(.pi-admin-page) {
    background: var(--pi-bg) !important;
}

body:has(.pi-admin-page) article {
    margin: 0 !important;
    padding: 0 !important;
}

.pi-admin-page h1,
.pi-admin-page h2,
.pi-admin-page h3,
.pi-admin-page h4,
.pi-admin-page h5,
.pi-admin-page h6 {
    color: #ffffff;
}

.pi-admin-page .text-muted {
    color: #9ba5bc !important;
}

.pi-admin-page a:not(.btn) {
    color: #4dc3ff;
}

/* Cards */
.pi-admin-page .card {
    background: var(--pi-panel);
    border: 1px solid var(--pi-line);
    border-radius: 14px;
    color: #e6ebf7;
}

.pi-admin-page .card-header {
    background: rgba(255, 255, 255, 0.03);
    border-bottom: 1px solid var(--pi-line);
    color: #ffffff;
}

.pi-admin-page .card-footer {
    background: rgba(255, 255, 255, 0.03);
    border-top: 1px solid var(--pi-line);
}

.pi-admin-page .bg-light {
    background: rgba(255, 255, 255, 0.04) !important;
    color: #e6ebf7;
}

/* Tables. Bootstrap paints rows with --bs-table-bg and a box-shadow, so the variables have to be
   set rather than the background. */
.pi-admin-page .table {
    --bs-table-bg: transparent;
    --bs-table-color: #e6ebf7;
    --bs-table-striped-bg: rgba(255, 255, 255, 0.03);
    --bs-table-striped-color: #e6ebf7;
    --bs-table-hover-bg: rgba(0, 183, 255, 0.08);
    --bs-table-hover-color: #ffffff;
    --bs-table-border-color: var(--pi-line);
    color: #e6ebf7;
}

/* thead and tfoot carry class="table-light" on several of these pages, and that class sets
   --bs-table-color to black and --bs-table-bg to a near-white. Bootstrap paints each cell from
   those variables, so setting colour on the row group was not enough — the headings stayed black
   on the dark strip. Set the variables instead, which is what the cells actually read.

   .table-light is matched wherever it appears rather than only on thead: the payouts and revenue
   pages put it on tfoot for their totals row, which is how eight white cells survived the first
   pass. */
.pi-admin-page .table > thead,
.pi-admin-page .table > tfoot,
.pi-admin-page .table-light {
    --bs-table-bg: rgba(255, 255, 255, 0.04);
    --bs-table-color: #cbd2e5;
    color: #cbd2e5;
}

/* A thead with no class at all, which the AI moderation table has: nothing sets its own
   background, so it fell through to the browser default white. */
.pi-admin-page thead {
    background-color: transparent;
}

/* Contextual row classes — .table-success on a totals row, and the rest — are meaningful, so they
   keep their meaning and lose their light-theme colours. Bootstrap gives them pale tints meant for
   a white table (#d1e7dd and friends), which on this background read as bright bands. */
.pi-admin-page .table-success {
    --bs-table-bg: rgba(0, 220, 154, 0.14);
    --bs-table-color: #b6f2dc;
}

.pi-admin-page .table-danger {
    --bs-table-bg: rgba(244, 67, 54, 0.14);
    --bs-table-color: #ffc9c4;
}

.pi-admin-page .table-warning {
    --bs-table-bg: rgba(255, 193, 7, 0.14);
    --bs-table-color: #ffe6a3;
}

.pi-admin-page .table-info {
    --bs-table-bg: rgba(33, 150, 243, 0.14);
    --bs-table-color: #cfe4ff;
}

.pi-admin-page .table-primary {
    --bs-table-bg: rgba(0, 183, 255, 0.14);
    --bs-table-color: #cfe4ff;
}

.pi-admin-page .table > thead th {
    border-bottom-color: var(--pi-line);
    background-color: rgba(255, 255, 255, 0.04);
    color: #cbd2e5;
}

/* Forms */
.pi-admin-page .form-control,
.pi-admin-page .form-select {
    background: rgba(8, 13, 24, 0.9);
    border: 1px solid var(--pi-line);
    color: #ffffff;
}

.pi-admin-page .form-control:focus,
.pi-admin-page .form-select:focus {
    background: rgba(8, 13, 24, 0.9);
    border-color: rgba(0, 183, 255, 0.6);
    box-shadow: 0 0 0 3px rgba(0, 183, 255, 0.12);
    color: #ffffff;
}

.pi-admin-page .form-control::placeholder {
    color: #6f7a91;
}

.pi-admin-page .form-label {
    color: #cbd2e5;
}

.pi-admin-page .input-group-text {
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid var(--pi-line);
    color: #cbd2e5;
}

/* Modals — these sit outside the page container in the markup, which is why a page has to wrap
   them in .pi-admin-page too. */
.pi-admin-page .modal-content {
    background: #0b1024;
    border: 1px solid var(--pi-line);
    color: #e6ebf7;
}

.pi-admin-page .modal-header,
.pi-admin-page .modal-footer {
    border-color: var(--pi-line);
}

.pi-admin-page .modal-header:not(.bg-danger):not(.bg-warning):not(.bg-success):not(.bg-primary) {
    background: rgba(255, 255, 255, 0.03);
}

.pi-admin-page .btn-close {
    filter: invert(1) grayscale(100%) brightness(200%);
}

/* The invert above is for close buttons sitting on the admin theme's dark surfaces. A toast is
   not one of those: Bootstrap's text-bg-* toasts are light with dark text, so inverting the x
   there left it white on cyan and all but invisible, while the words beside it stayed black. */
.pi-admin-page .toast .btn-close {
    filter: none;
}

/* Alerts */
.pi-admin-page .alert-info {
    background: rgba(33, 150, 243, 0.12);
    border-color: rgba(33, 150, 243, 0.35);
    color: #cfe4ff;
}

.pi-admin-page .alert-success {
    background: rgba(0, 220, 154, 0.12);
    border-color: rgba(0, 220, 154, 0.35);
    color: #b6f2dc;
}

.pi-admin-page .alert-warning {
    background: rgba(255, 193, 7, 0.12);
    border-color: rgba(255, 193, 7, 0.35);
    color: #ffe6a3;
}

.pi-admin-page .alert-danger {
    background: rgba(244, 67, 54, 0.12);
    border-color: rgba(244, 67, 54, 0.4);
    color: #ffc9c4;
}

/* Buttons that are otherwise near-invisible on a dark panel */
.pi-admin-page .btn-outline-secondary {
    border-color: rgba(255, 255, 255, 0.25);
    color: #cbd2e5;
}

.pi-admin-page .btn-outline-secondary:hover {
    background: rgba(255, 255, 255, 0.08);
    color: #ffffff;
}

.pi-admin-page .btn-secondary,
.pi-admin-page .btn-light {
    background: rgba(255, 255, 255, 0.1);
    border-color: rgba(255, 255, 255, 0.18);
    color: #e6ebf7;
}

.pi-admin-page .btn-light:hover {
    background: rgba(255, 255, 255, 0.16);
    color: #ffffff;
}

/* Bootstrap's progress track is #e9ecef, which is one of the brightest things on a dark page.
   The bar itself keeps whatever colour the page gave it. */
.pi-admin-page .progress {
    background-color: rgba(255, 255, 255, 0.08);
}

.pi-admin-page .btn:focus-visible {
    outline: 2px solid var(--pi-blue);
    outline-offset: 2px;
}

/* List groups */
.pi-admin-page .list-group-item {
    background: transparent;
    border-color: var(--pi-line);
    color: #e6ebf7;
}

/* Nav tabs */
.pi-admin-page .nav-tabs {
    border-bottom-color: var(--pi-line);
}

.pi-admin-page .nav-tabs .nav-link {
    color: #9ba5bc;
    background: transparent;
    border-color: transparent;
}

.pi-admin-page .nav-tabs .nav-link.active {
    color: #ffffff;
    background: rgba(255, 255, 255, 0.05);
    border-color: var(--pi-line) var(--pi-line) transparent;
}

/* ---------------------------------------------------------------------------
   Bootstrap defaults that assume a light background

   These ship coloured for white pages and were never themed, so on the dark
   background they range from hard to read to genuinely invisible. Measured on
   a gallery page against --pi-panel / --pi-bg:

     .form-text                 1.22:1   the hint under a search or form field
     .breadcrumb-item.active    1.29:1   the page you are on
     .badge.bg-info             2.28:1   white on #00b7ff
     .breadcrumb-item a         3.60:1   Bootstrap's link blue
     .text-info-emphasis        3.92:1   dark teal, meant for a pale info panel

   .form-text appears in 21 components and breadcrumbs in 15 — registration,
   two-factor sign-in and every gallery among them — so this belongs here
   rather than in any one page's scoped stylesheet. WCAG AA for body text is
   4.5:1; each rule below clears it.
   --------------------------------------------------------------------------- */

.form-text {
    color: var(--pi-text-muted);
}

.breadcrumb-item.active {
    color: var(--pi-text-muted);
}

/* --pi-cyan, the theme's own link colour on dark: 11.6:1, against 3.6:1 for the
   #006bb7 Bootstrap falls back to. */
.breadcrumb-item a {
    color: var(--pi-cyan);
    text-decoration: none;
}

.breadcrumb-item a:hover,
.breadcrumb-item a:focus-visible {
    color: #ffffff;
    text-decoration: underline;
}

.breadcrumb-item + .breadcrumb-item::before {
    color: var(--pi-text-muted);
}

/* bg-info is the bright --pi-blue, which is a light fill: it needs dark text on
   it, not white. Same reasoning for the emphasis colour sitting on top of it. */
.badge.bg-info,
.badge.text-bg-info {
    color: #05121c;
}

/* !important only because Bootstrap ships this utility as "!important" itself — the text-*-emphasis
   colours are declared that way, so a plain declaration here loses however specific it is. */
.text-info-emphasis {
    color: #05121c !important;
}
