:root {
    --bb-gold: #F2B233;
    --bb-gold-rgb: 242, 178, 51;
    --bb-gold-pale: #FBDB7C;
    --bb-green-deep: #0F352C;
    --bb-green-mid: #1F6652;
    --bb-red: #BC2727;
    --bb-red-dark: #9E0000;
    --bb-ink: #16140F;
    --bb-white: #FFFFFF;
    --bb-border-dark: #23272B;
    /* The lit appearance of the 3D scenes' red wall (red_wall = 0xBC2727 in the *.js scene files) as it actually renders on screen, noticeably lighter/pinker than the raw --bb-red hex. Measured by pixel-scanning a /schedule screenshot. Used on /contact to visually echo "the wall you just walked through" coming from /home, without replaying a real 3D scene. */
    --bb-wall-pink: #F17870;
    /* Soft shadow shared by the whole file-manager "card" family (new folder form, drop zone, hub cards, move banner, .navbar-admin mobile panel): one setting to give consistent depth to all these blocks. */
    --bb-shadow-soft: 0 4px 14px rgba(0, 0, 0, 0.18);
}

body {
    background-color: var(--bb-gold);
}

/* Skip link: the page's first focusable element, invisible until keyboard focus (moved off-screen rather than display:none, to stay Tab-reachable), then visible and high-contrast once focused. Lets keyboard users skip the navbar/3D scene straight to #main-content. */
.skip-link {
    position: absolute;
    z-index: 2000;
    top: -3rem;
    left: 0.5rem;
    padding: 0.6rem 1.2rem;
    background: var(--bb-ink);
    color: var(--bb-white);
    font-weight: bold;
    border-radius: 0 0 8px 8px;
    transition: top 0.15s ease;
}
.skip-link:focus {
    top: 0;
    outline: 3px solid var(--bb-white);
    outline-offset: 2px;
}

.avatar {
    max-width: 128px;
    max-height: 128px;
    border-radius: 25px;
}

.avatar-medium {
    max-width: 64px;
    max-height: 64px;
}

/* Gold on red only reaches 3.24:1, below AA (4.5:1). White (6.07:1, AA) instead, same fix as #joinForm/#loginForm for the same color pair. */
.badge-red {
    color: var(--bb-white);
    background-color: var(--bb-red);
}

.btn-link, a,
.btn-link:hover, a:hover {
    color: var(--bb-green-mid);
    border-radius: 25px;
}
/* White text (not green) on red background: green on red only reaches ~1.45:1, same fix as the navbar, here for the desk/admin "reject" buttons. */
.btn-red {
    color: var(--bb-white);
    font-weight: bold;
    border-radius: 25px;
    background: var(--bb-red);
    width: fit-content;
}
.btn-red:hover{
    color: var(--bb-white);
    background: var(--bb-red-dark);
}
/* --bb-ink here rather than white: these buttons sit on light backgrounds (body's gold, white table rows/cards), unlike .login/.join on the dark 3D scene. ink/gold 9.81:1, ink/white 18.4:1 (AAA either way). */
.btn-red:focus-visible,
.btn-green:focus-visible {
    outline: 3px solid var(--bb-ink);
    outline-offset: 2px;
}

/* White text (not red) on green background: same fix, for "validate" buttons. */
.btn-green {
    color: var(--bb-white);
    font-weight: bold;
    border-radius: 25px;
    background: var(--bb-green-mid);
    width: fit-content;
}
.btn-green:hover{
    color: var(--bb-white);
    background: var(--bb-green-deep);
}
.bg-yellow {
    background: var(--bb-gold);
}

.centered {
    display: flex;
    align-items: center;
    justify-content: center;
}

/* .text-green: a color utility used directly on the body's gold background. --bb-green-deep reaches 7.15:1 (AAA) there, unlike the lighter green previously used which only reached 2.77:1 (below AA). */
.text-green {
    color: var(--bb-green-deep);
}
.text-yellow {
    color: var(--bb-gold);
}

#c {
    position: absolute;
    z-index: 800;
    top: 0;
    width: 100%;
    height: 100%;
    display: block;
}

canvas {
	display: block;
}

.loader {
    display: block;
    background: url("b_mascot_loading-HY_sOcJ.png") center no-repeat;
    width: 100px;
    height: 100px;
    position: absolute;
    top: 50%;
    left: 50%;
    margin-left: -50px;
    margin-top: -50px;

}
.isloaded .loader {
    height: 0;
    -webkit-transition-property: background-color height;
    -webkit-transition-duration: 0.3s;
    -webkit-transition-delay: 0.6s;
    -webkit-transition-timing-function: ease;
    transition-property: background-color height;
    transition-duration: 0.3s;
    transition-delay: 0.6s;
    transition-timing-function: ease;
}

.loading {
    position: absolute;
    z-index: 1000;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    display: block;
    background: var(--bb-red-dark);
}

.isloaded{
    position: absolute;
    z-index: 1000;
    top: 0;
    left: 0;
    width: 100%;
    height: 0%;
    display: block;
    background: var(--bb-red-dark);
    -webkit-transition-property: background-color height;
    -webkit-transition-duration: 0.3s;
    -webkit-transition-delay: 0.5s;
    -webkit-transition-timing-function: ease;
    transition-property: background-color height;
    transition-duration: 0.3s;
    transition-delay: 0.5s;
    transition-timing-function: ease;
}

.list-group-item.active {
    background-color: var(--bb-green-mid);
    border-color: var(--bb-green-mid);
}

/* Same contrast fix as the other forms below: without an explicit color, this would inherit the generic "form" rule's gold on green (3.63:1, below AA). White reaches 6.83:1 (AA). */
#contactForm {
    position: absolute;
    z-index: 1100;
    width: 790px;
    height: 400px;
    background: var(--bb-green-mid);
    left: 50%;
    margin-left: -290px;
    top: 23px;
    color: var(--bb-white);
}

/* Anti-spam honeypot: moved off-screen rather than display:none, since some bots specifically ignore that, and removed from the accessibility tree via aria-hidden/tabindex="-1" on the field itself in the templates. */
.hp-field {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

.contact-status {
    font-weight: 600;
    min-height: 1.2em;
}

.contact-status.is-error {
    color: var(--bb-gold-pale);
}

form {
    background: var(--bb-green-mid);
    text-align: left;
    color: var(--bb-gold);
    padding: 2% 4%;
    border: 5px solid var(--bb-border-dark);
}

/* .login/.join and #joinForm/#loginForm moved to assets/login/join.css: a page with its own 3D scene gets its own file. */

/* Same contrast fix as #joinForm/#loginForm: any plain <form> inherits gold on green from the generic "form" rule (3.63:1, below AA). White (6.82:1, AAA) instead. Scoped to body.desk to leave story/music/join forms untouched, already styled separately. */
body.desk form {
    color: var(--bb-white);
}
/* Bootstrap's default validation error red (#dc3545) only reaches 1.51:1 on this green background, nearly invisible. --bb-gold-pale reaches 5.04:1 (AA) and stays visually distinct from the white labels. */
body.desk form .invalid-feedback {
    color: var(--bb-gold-pale);
}
/* .btn-green has the exact same background as the surrounding desk/admin <form>, making it invisible with no visual boundary. A white border detaches it (6.82:1 on the green background) rather than changing its fill color. */
body.desk form .btn-green {
    border: 2px solid var(--bb-white);
}

/* Markdown cheat-sheet for the Story section form: the parent <form> is already white-on-green (6.82:1), so this box stands out via an overlaid darker background rather than a new hue. --bb-gold-pale on that composite background reaches 8.35:1 (AAA). */
.markdown-help {
    margin-bottom: 1rem;
    padding: 0.85rem 1rem;
    background: rgba(0, 0, 0, 0.18);
    border-left: 4px solid var(--bb-gold);
    border-radius: 6px;
}
.markdown-help-title {
    margin: 0 0 0.5rem;
    font-weight: bold;
}
.markdown-help ul {
    margin: 0;
    padding-left: 1.1rem;
}
.markdown-help li {
    margin-bottom: 0.3rem;
    font-size: 0.95rem;
}
.markdown-help code {
    padding: 0.1rem 0.35rem;
    background: rgba(0, 0, 0, 0.35);
    border-radius: 4px;
    color: var(--bb-gold-pale);
    font-family: "Courier New", monospace;
}

/* EasyMDE toolbar: the library sets no background on .editor-toolbar (inherits the form's green) nor a color on its buttons (default browser black, ~3:1, below AA). Darkened to --bb-green-deep for a distinct toolbar look (13.4:1 with white), icons in white. Hover/active state uses --bb-green-mid + white border rather than the library's near-white default, which would hide the white icon on top of it. */
.editor-toolbar {
    background: var(--bb-green-deep);
    border-color: var(--bb-green-mid);
}
.editor-toolbar button {
    color: var(--bb-white);
}
.editor-toolbar button:hover,
.editor-toolbar button.active {
    background: var(--bb-green-mid);
    border-color: var(--bb-white);
}
.editor-toolbar i.separator {
    border-left-color: var(--bb-white);
    opacity: 0.4;
}
.editor-preview {
    color: var(--bb-ink);
}

/* One consistent page title style across desk/admin/event: a single <h1> per page, styled with the brand's display font (Bungee) rather than the browser's default per-heading-level sizing. */
body.desk h1 {
    font-family: "Bungee", "Arial Black", sans-serif;
    color: var(--bb-red-dark);
    text-transform: uppercase;
    letter-spacing: 0.02em;
    font-size: 1.6rem;
}
/* Section subtitles: same font family as h1 for consistent typography, smaller and without the bright color to mark the hierarchy. */
body.desk h2 {
    font-family: "Bungee", "Arial Black", sans-serif;
    color: var(--bb-ink);
    font-size: 1.15rem;
    letter-spacing: 0.01em;
}

/* No .card wrapper is used for the user detail page anymore: the "promote" button is a plain button on the page's gold background, and the edit form keeps its natural green box from the generic "form" rule below. */

/* The generic "form" rule was also bleeding its green background/thick border behind action-only <form> elements (delete/refuse buttons, just hidden fields + an icon button). Not scoped to body.desk, since .btn-form is also used outside desk on /music. */
.btn-form {
    display: inline-block;
    background: transparent;
    border: none;
    padding: 0;
}

/* Flash messages: brand background + border rather than Bootstrap's generic pale green. White on --bb-green-deep reaches 13.4:1 (AAA). Only alert-success exists in this scope, since every desk/admin addFlash() call uses 'success'. */
body.desk .alert-success {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    background: var(--bb-green-deep);
    color: var(--bb-white);
    border: none;
    border-left: 5px solid var(--bb-gold);
    border-radius: 10px;
    font-weight: bold;
}
body.desk .alert-success i {
    font-size: 1.4rem;
    color: var(--bb-gold);
}
body.desk .alert-success p {
    margin: 0;
}

/* "Add a picture!" placeholder: matches the real avatar's size (64px) as a dashed dropzone-style box rather than a plain text button, for the same visual presence as the photo once added. */
body.desk .add-picture {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.3rem;
    width: 64px;
    height: 64px;
    padding: 0.5rem;
    border-radius: 16px;
    border: 3px dashed var(--bb-red-dark);
    background: rgba(158, 0, 0, 0.08);
    color: var(--bb-red-dark);
    font-weight: bold;
    font-size: 0.7rem;
    line-height: 1.1;
    text-align: center;
}
body.desk .add-picture i {
    font-size: 1.4rem;
}
body.desk .add-picture:hover,
body.desk .add-picture:focus-visible {
    background: var(--bb-red);
    border-color: var(--bb-white);
    color: var(--bb-white);
}

/* User detail page header: a real identity banner (avatar in a gold frame, name + instrument/city subtitle, icon-only back/contact actions) rather than large text buttons, roles as pills rather than table rows. */
body.desk .profile-header {
    display: flex;
    align-items: center;
    gap: 1.25rem;
    flex-wrap: wrap;
    margin-bottom: 1.5rem;
}
body.desk .profile-identity {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex: 1;
    min-width: 0;
}
/* --bb-green-mid background, same as the role badges below, rather than a new neutral color. White text on it reaches 6.81:1 (AAA). */
body.desk .profile-avatar-frame {
    position: relative;
    width: 72px;
    height: 72px;
    border-radius: 50%;
    border: 3px solid var(--bb-gold);
    background: var(--bb-green-mid);
    color: var(--bb-white);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.6rem;
    flex-shrink: 0;
    overflow: hidden;
}
body.desk .profile-avatar-frame img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* "Large" variant of the same frame, used in the edit form: the picture becomes the page's central element rather than just an identification medallion. */
body.desk .profile-avatar-frame-lg {
    width: 128px;
    height: 128px;
    font-size: 2.5rem;
}
/* Camera badge, purely decorative (pointer-events: none): the real click target is the native file field below, stretched over the whole frame, this badge only shows the "click to change photo" affordance. */
body.desk .profile-avatar-edit {
    position: absolute;
    right: 0;
    bottom: 0;
    width: 2.1rem;
    height: 2.1rem;
    border-radius: 50%;
    background: var(--bb-gold);
    color: var(--bb-ink);
    border: 2px solid var(--bb-green-deep);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1rem;
    pointer-events: none;
}
/* The native file field is stretched as an invisible layer over the whole frame rather than a small classic Bootstrap input, making the whole photo clickable. Bootstrap's auto-generated label is hidden: the field's real accessible name comes from an sr-only form_label in the template instead. */
body.desk .profile-avatar-frame .custom-file {
    position: absolute;
    inset: 0;
    opacity: 0;
    cursor: pointer;
    z-index: 2;
}
body.desk .profile-avatar-frame .custom-file-input {
    width: 100%;
    height: 100%;
    cursor: pointer;
}
body.desk .profile-avatar-frame .custom-file-label {
    display: none;
}
/* Dedicated keyboard focus ring carried by the whole frame rather than the invisible (opacity: 0) file field itself; without this, a keyboard focus on that field would show nowhere. */
body.desk .profile-avatar-frame:focus-within {
    outline: 3px solid var(--bb-white);
    outline-offset: 3px;
}
body.desk .profile-name {
    margin: 0;
    text-align: left;
}
body.desk .profile-subtitle {
    margin: 0.15rem 0 0;
    color: var(--bb-ink);
    font-weight: bold;
    opacity: 0.75;
}
/* Icon-only "back"/"contact" buttons in the header: same square size as the table icon buttons, repeated explicitly here since they're outside a .table. */
body.desk .profile-header > .btn-red,
body.desk .profile-header > .btn-green {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.5rem;
    height: 2.5rem;
    padding: 0;
    flex-shrink: 0;
}

body.desk .role-pills {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
    margin-bottom: 1.5rem;
}
body.desk .role-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    background: var(--bb-green-mid);
    color: var(--bb-white);
    /* Symmetric padding regardless of the badge's content, whether or not it has a trailing remove button. */
    padding: 0.4rem 1rem;
    border-radius: 25px;
    font-weight: bold;
}
body.desk .role-badge .btn-red {
    width: 1.75rem;
    height: 1.75rem;
    min-width: 1.75rem;
    font-size: 0.85rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
}

/* Field block shared by /desk/profile and admin/user/show: "photo on the left, info on the right" for the identity line, then field groups below as cards (same gold border/--bb-green-deep background as other cards on the site). */
body.desk .profile-form-header {
    display: flex;
    align-items: center;
    gap: 1.5rem;
    flex-wrap: wrap;
    margin-bottom: 1.5rem;
}
body.desk .profile-form-header-fields {
    flex: 1;
    min-width: 220px;
}
body.desk .profile-field-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 0 1.5rem;
}
/* Bootstrap form-groups already have their own bottom margin: avoids doubling up with the grid's "gap" above. */
body.desk .profile-field-grid .form-group {
    margin-bottom: 1rem;
}
/* Read-only nickname/email on the admin side: same visual rhythm as a form-group (label + value) without being a real field. */
body.desk .profile-readonly-field {
    margin: 0 0 1rem;
}
body.desk .profile-readonly-field strong {
    display: block;
    font-size: 0.85rem;
    margin-bottom: 0.25rem;
}
body.desk .profile-form-card {
    background: var(--bb-green-deep);
    border: 2px solid var(--bb-gold);
    border-radius: 12px;
    box-shadow: var(--bb-shadow-soft);
    padding: 1.5rem;
    margin: 0 0 1.5rem;
}
/* The default body.desk h2 color (--bb-ink, meant for light backgrounds) is unreadable on this dark green, so white is used instead (13.4:1, AAA). */
body.desk .profile-form-card h2 {
    color: var(--bb-white);
    margin: 0 0 1rem;
    font-size: 1.05rem;
}

/* Roles to add: short pills rather than full-sentence buttons, same visual language as .role-badge above so an admin visually associates "current role" and "role to add". The full sentence stays available via aria-label/confirm for accessibility. */
body.desk .promote-pills {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.6rem;
    margin-bottom: 1.5rem;
}
body.desk .promote-pills .btn-green {
    border-radius: 25px;
    padding: 0.45rem 1.2rem;
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}

/* Themed scrollbar matching the rest of the site (Story/Music/Schedule each have one). Targeted on html.desk rather than body.desk: the window scrollbar is driven by the root <html> element, not <body>, as long as <body> has no overflow of its own, so the "desk" class is set on <html> too. */
html.desk {
    scrollbar-width: thin;
    scrollbar-color: var(--bb-gold-pale) transparent;
    /* Without this, the space reserved for the vertical scrollbar only exists on pages tall enough to actually scroll, so the fixed navbar and content shifted by a few px between pages depending on scrollbar presence. scrollbar-gutter reserves that space permanently. */
    scrollbar-gutter: stable;
}
html.desk::-webkit-scrollbar {
    width: 10px;
}
html.desk::-webkit-scrollbar-track {
    background: transparent;
}
html.desk::-webkit-scrollbar-thumb {
    background-color: var(--bb-gold-pale);
    border-radius: 8px;
}
html.desk::-webkit-scrollbar-thumb:hover {
    background-color: var(--bb-gold);
}

/* Icon-only action buttons in tables: a fixed size and centered icon so every table's actions look alike regardless of the surrounding column text. */
body.desk .table .btn-red,
body.desk .table .btn-green {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    padding: 0;
}

/* The 5 /desk tables are separate <table> elements sharing the same columns: in default auto layout, each table computes its column widths independently from its own content, so the "Actions" column (and others) don't line up between tables despite identical columns. table-layout: fixed + matching % widths force a real column-by-column alignment. */
body.desk .table {
    table-layout: fixed;
    width: 100%;
}
body.desk .table th:nth-child(1),
body.desk .table td:nth-child(1) {
    width: 22%;
}
body.desk .table th:nth-child(2),
body.desk .table td:nth-child(2) {
    width: 18%;
}
body.desk .table th:nth-child(3),
body.desk .table td:nth-child(3) {
    width: 16%;
}
body.desk .table th:nth-child(4),
body.desk .table td:nth-child(4) {
    width: 16%;
}
body.desk .table th:nth-child(5),
body.desk .table td:nth-child(5) {
    width: 16%;
}
body.desk .table th:nth-child(6),
body.desk .table td:nth-child(6) {
    width: 12%;
}
/* table-layout: fixed no longer auto-shrinks a column for a very long word: allows wrapping instead of overflowing the cell. */
body.desk .table td {
    overflow-wrap: break-word;
}

/* White hover text (not gold/red): same contrast fix as the navbar, here for the "pay membership"/"subscribe" CTAs. */
.red-hover:hover {
    background-color: var(--bb-red);
    border-radius: 5px;
    color: var(--bb-white);
    padding: 6px 12px;
}

.green-hover:hover {
    background-color: var(--bb-green-mid);
    border-radius: 5px;
    color: var(--bb-white);
    padding: 6px 12px;
}

.navbar-collapse.collapsing, .no-transition {
  -webkit-transition: height 0.0s;
  -moz-transition: height 0.0s;
  -ms-transition: height 0.0s;
  -o-transition: height 0.0s;
  transition: height 0.0s;

}
.navbar {
    position: fixed;
    z-index: 1000;
    background: transparent;
}

.navbar.mini {
    background: var(--bb-green-deep);
    width: 100%;
}

/* Round hamburger button badge, drum-skin style */
.navbar-toggler {
    position: relative;
    z-index: 1100;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    width: 54px;
    height: 54px;
    background: var(--bb-gold);
    border: 3px solid var(--bb-ink);
    border-radius: 50%;
    box-shadow: 0 3px 8px rgba(0, 0, 0, 0.35);
    transition: transform 0.15s ease, background-color 0.15s ease;
}
.navbar-toggler:hover {
    transform: scale(1.06);
}
.navbar-toggler[aria-expanded="true"] {
    background: var(--bb-green-mid);
    border-color: var(--bb-gold);
}
@media (prefers-reduced-motion: reduce) {
    .navbar-toggler {
        transition: none;
    }
}

.navbar-collapse {
    top: 8%;
    left: 50%;
    transform: translateX(-50%);
    width: min(90%, 440px);
    max-height: 82vh;
    overflow-y: auto;
    background: var(--bb-green-mid);
    border: 3px solid var(--bb-gold);
    border-radius: 14px;
    box-shadow: 0 20px 50px rgba(0, 0, 0, 0.45);
    padding: 2.5rem 2rem;
    position: fixed;
    z-index: 1000;
    text-align: center;
}

/* Main navbar links: gold on green, never red on green. Also neutralizes the generic "li.nav-item:hover" rule (red background) further down, which would otherwise show through on hover. */
.navbar-collapse .navbar-nav .nav-item {
    background: transparent;
    border-radius: 0;
}
.navbar-collapse .navbar-nav .nav-item + .nav-item {
    border-top: 1px solid rgba(var(--bb-gold-rgb), 0.25);
}
.navbar-collapse .nav-link {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    padding: 0.75rem 0.5rem;
    border-radius: 8px;
    background: transparent;
    transition: background-color 0.15s ease, color 0.15s ease;
}
.navbar-collapse .nav-link i {
    font-size: 1.15rem;
    line-height: 1;
    color: var(--bb-gold-pale);
    transition: color 0.15s ease;
}
.navbar-collapse .nav-link h2 {
    margin: 0;
    font-family: "Bungee", "Arial Black", sans-serif;
    font-size: 1.1rem;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    white-space: nowrap;
    color: var(--bb-gold-pale);
}
/* Current page: same visual treatment as :hover/:focus-visible, targeted on aria-current="page" set server-side from the active route. */
.navbar-collapse .nav-link:hover,
.navbar-collapse .nav-link:focus-visible,
.navbar-collapse .nav-link[aria-current="page"] {
    background: var(--bb-gold);
}
.navbar-collapse .nav-link:hover i,
.navbar-collapse .nav-link:hover h2,
.navbar-collapse .nav-link:focus-visible i,
.navbar-collapse .nav-link:focus-visible h2,
.navbar-collapse .nav-link[aria-current="page"] i,
.navbar-collapse .nav-link[aria-current="page"] h2 {
    color: var(--bb-green-deep);
}
.navbar-collapse .nav-link:focus-visible {
    outline: 3px solid var(--bb-white);
    outline-offset: 2px;
}

/* On phones, icons only: the label stays readable to screen readers (sr-only technique) but is no longer shown on screen. */
@media (max-width: 576px) {
    .navbar-collapse .nav-link i {
        font-size: 1.5rem;
    }
    .navbar-collapse .nav-link h2 {
        position: absolute;
        width: 1px;
        height: 1px;
        padding: 0;
        margin: -1px;
        overflow: hidden;
        clip: rect(0, 0, 0, 0);
        white-space: nowrap;
        border: 0;
    }
}

/* Language switcher: 3 plain links rather than a <select>, since native browser select chrome can't be styled to match the rest. */
.navbar-collapse .lang-switcher {
    margin-top: 0;
    padding-top: 0.75rem;
    border-top: 1px solid rgba(var(--bb-gold-rgb), 0.25);
    display: flex;
    justify-content: center;
    gap: 0.5rem;
}
.navbar-collapse .lang-link {
    display: inline-block;
    padding: 0.25rem 0.6rem;
    border-radius: 6px;
    font-weight: bold;
    font-size: 0.85rem;
    letter-spacing: 0.04em;
    color: var(--bb-gold-pale);
    border: 1px solid transparent;
}
.navbar-collapse .lang-link:hover,
.navbar-collapse .lang-link:focus-visible {
    border-color: var(--bb-gold-pale);
}
.navbar-collapse .lang-link.active {
    background: var(--bb-gold);
    color: var(--bb-green-deep);
}

.navbar-collapse .navbar-text {
    display: block;
    margin-top: 1.5rem;
    font-style: italic;
    color: var(--bb-gold-pale);
    opacity: 0.85;
}

.navbar-admin {
    width: 100%;
    z-index: 1000;
    background: var(--bb-red);
}
.navbar-admin .container {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
}
/* Hamburger button: same round badge as the public navbar's .navbar-toggler, reused as-is for consistency; app.js's Escape-to-close handling applies to both navbars since only one is ever present per page. */
.navbar-admin .navbar-toggler {
    margin: 0.5rem 0;
}
/* .text-yellow (gold) only reaches 3.24:1 on this red background, below AA; switched to white (6.07:1) for this context specifically, without touching .text-yellow elsewhere. */
.navbar-admin .text-yellow {
    color: var(--bb-white);
}
/* White outline rather than --bb-ink (used elsewhere on light backgrounds): here the background is red, and white/red reaches 6.07:1 while ink/red would only reach 3.03:1. */
.navbar-admin .nav-link:focus-visible {
    outline: 3px solid var(--bb-white);
    outline-offset: 2px;
    border-radius: 8px;
}
/* Current page indicator: white background + dark red text, the same color pair already validated on this red background elsewhere (8.55:1, AAA). */
.navbar-admin .nav-link[aria-current="page"] {
    background: var(--bb-white);
    color: var(--bb-red-dark);
    border-radius: 8px;
}
.navbar-admin .nav-link[aria-current="page"] i {
    color: var(--bb-red-dark);
}
/* Mobile (<768px): a real collapsible menu (hamburger + #navbarAdminNav panel, WAI-ARIA disclosure pattern) rather than a flex-wrap that stacked all items into one full-screen column above the page content.
   #navbarAdminNav deliberately has no .navbar-collapse class: that class already carries a centered floating-card style meant for the public navbar, not wanted here (this panel is inline in the page flow, not a popup). .collapse:not(.show) and .navbar-nav's flex-direction already come from bootstrap.min.css. */
@media (max-width: 767px) {
    /* Collapsed panel: a darker shade (--bb-red-dark, 8.56:1 for white text) plus rounded corners and a shadow, so it visibly detaches from the hamburger button above instead of forming one flat red block. The 15px red halo from .navbar-admin's own padding stays visible all around, like a frame. */
    .navbar-admin #navbarAdminNav {
        width: 100%;
        margin-top: 0.5rem;
        padding: 0.75rem 0.75rem 1.25rem;
        background: var(--bb-red-dark);
        border-radius: 12px;
        box-shadow: var(--bb-shadow-soft);
    }
    .navbar-admin .nav-item.ml-auto {
        margin-left: 0 !important;
    }
    /* Comfortable tap target (44px, above the 24px minimum): each item takes the panel's full width. */
    .navbar-admin .nav-link {
        min-height: 44px;
        padding: 0.6rem 0.5rem;
    }
    .navbar-admin .lang-switcher {
        justify-content: center;
        padding: 0.6rem 0.5rem;
    }
}
@media (min-width: 768px) {
    .navbar-admin .navbar-toggler {
        display: none;
    }
    .navbar-admin .collapse {
        display: flex !important;
        flex: 1;
    }
    .navbar-admin .navbar-nav {
        flex-direction: row;
        align-items: center;
    }
}

/* Language switcher: same 3 links as .navbar-collapse above, but white instead of gold since this background is red rather than green (6.07:1). */
.navbar-admin .lang-switcher {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0 0.75rem;
}
.navbar-admin .lang-link {
    display: inline-block;
    padding: 0.25rem 0.6rem;
    border-radius: 6px;
    font-weight: bold;
    font-size: 0.85rem;
    letter-spacing: 0.04em;
    color: var(--bb-white);
    border: 1px solid transparent;
}
.navbar-admin .lang-link:hover,
.navbar-admin .lang-link:focus-visible {
    border-color: var(--bb-white);
}
.navbar-admin .lang-link.active {
    background: var(--bb-white);
    color: var(--bb-red-dark);
}

/* Fixed top navbar, desktop only: below 768px .navbar-admin can already span multiple lines, so fixing it there would require reserving an unpredictable content height at the top of every page. #main-content gets a padding-top matching the navbar's measured height so nothing hides behind it on load. */
@media (min-width: 768px) {
    .navbar-admin {
        position: fixed;
        top: 0;
        left: 0;
    }
    body.desk main {
        padding-top: 58px;
    }
    /* Flash messages render between the header and <main>, outside the padding-top above, so without this margin-top they'd slide under the fixed navbar. */
    body.desk .flash-messages {
        margin-top: 58px;
    }
}

/* Bootstrap 4's .container caps at 1140px, leaving a huge empty margin on wide screens. This selector's higher specificity wins at every size without duplicating breakpoints; only the largest breakpoint's cap is raised, the gutter and smaller max-widths stay Bootstrap's. */
body.desk .container {
    max-width: 1400px;
}

.navbar .navbar-toggler svg {
    width: 24px;
    height: 24px;
    color: var(--bb-ink);
}
.navbar-toggler[aria-expanded="true"] svg {
    color: var(--bb-gold);
}

/* Explicit white text: without it, links inherit the global green rule and become green-on-green (unreadable) on the active pills of /schedule and the Story minisite. */
.nav-pills .nav-link.active, .nav-pills .show > .nav-link {
    background: var(--bb-green-mid);
    color: var(--bb-white);
}

/* Same red/green contrast bug as the old navbar (~1.1:1), here on the schedule/story pill hover state: white text instead. */
li.nav-item.active, li.nav-item:hover,
.navbar-dark .navbar-nav .nav-link:hover, .navbar-dark .navbar-nav .nav-link:focus,
.navbar-dark .navbar-nav .show > .nav-link, .navbar-dark .navbar-nav .active > .nav-link, .navbar-dark .navbar-nav .nav-link.show, .navbar-dark .navbar-nav .nav-link.active {
    color: var(--bb-white);
    background-color: var(--bb-red);
    border-radius: 25px;
}
.navbar-dark .navbar-nav .nav-link {
    color: var(--bb-white);
    background: var(--bb-red);
}

/* Aligned to /story's 3D screen: the camera is fixed but its aspect ratio follows the window, so the displayed screen changes size/position with it. No real 3D->2D projection here, just vw/vh units calibrated by pixel measurement at a reference size, tracking resize reasonably well without being pixel-perfect at every ratio. */
#miniSite {
    position: absolute;
    z-index: 900;
    left: 21.8vw;
    top: 1.6vh;
    width: 76.4vw;
    height: 63.9vh;
    background: transparent;
    overflow-y: scroll;
}

/* /schedule's rules moved to assets/schedule/schedule.css: a page with its own 3D scene gets its own file rather than growing this shared one. */

/* File manager: reuses the vocabulary already established on body.desk (solid --bb-green-mid pills like .role-badge) rather than a separate style. Shared vertical spacing for every block on the page. */
.desk-intro {
    margin-bottom: 1rem;
}
/* Explains the /desk/files/music <-> /music link, the only space tied to a second page: a left border + slightly darkened background over the body's gold rather than a large solid panel. --bb-ink on this composite background comfortably clears AAA. */
.desk-music-help {
    margin-bottom: 1.5rem;
    padding: 0.85rem 1rem;
    background: rgba(0, 0, 0, 0.06);
    border-left: 4px solid var(--bb-green-mid);
    border-radius: 6px;
    color: var(--bb-ink);
}
.desk-music-help p {
    margin: 0 0 0.5rem;
}
.desk-music-help a {
    font-weight: bold;
    color: var(--bb-green-mid);
}
.desk-music-help a:hover,
.desk-music-help a:focus-visible {
    color: var(--bb-green-deep);
}
.desk-breadcrumb,
.desk-actions,
.desk-folders,
.desk-documents,
.desk-empty,
.desk-track {
    margin-bottom: 1.5rem;
}

.desk-breadcrumb {
    color: var(--bb-ink);
    font-weight: bold;
}
.desk-breadcrumb ol {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.3rem;
    list-style: none;
    padding: 0;
    margin: 0;
}
.desk-breadcrumb li {
    display: flex;
    align-items: center;
    gap: 0.3rem;
}
.desk-breadcrumb a {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    color: var(--bb-green-mid);
}
/* Current breadcrumb item: plain text, no link to self, per the WAI-ARIA breadcrumb pattern. --bb-ink like the rest of the trail, already distinct from the green links with no extra styling needed. */
.desk-breadcrumb [aria-current] {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
}
.desk-breadcrumb-sep {
    opacity: 0.6;
}

/* "New folder" and the drop zone: the two most likely actions on arriving in a folder, given equal visual weight side by side on desktop, stacked on mobile. */
.desk-actions {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1rem;
}
@media (min-width: 640px) {
    .desk-actions {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr);
        align-items: stretch;
    }
}

/* Create-folder form: a bare <form> would otherwise inherit the generic "form" rule (--bb-green-mid background), where the --bb-ink label only reached 2.70:1, below AA. Styled as a dedicated card in the same visual family as .quick-upload-zone next to it (same border, transparent background over the body's gold) but with a solid rather than dashed border, signaling "field to fill" rather than "zone to drop into". --bb-ink/--bb-gold = 9.81:1 (AAA). */
.desk-new-folder {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    padding: 1.25rem;
    background: transparent;
    color: var(--bb-ink);
    border: 2px solid var(--bb-green-mid);
    border-radius: 10px;
    box-shadow: var(--bb-shadow-soft);
}
.desk-new-folder label {
    margin: 0;
    font-weight: bold;
    font-size: 1.05rem;
    color: var(--bb-ink);
}
.desk-new-folder-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
}
.desk-new-folder input[type="text"] {
    flex: 1 1 12rem;
    min-height: 44px;
    padding: 0.5rem 0.75rem;
    border: 2px solid var(--bb-ink);
    border-radius: 8px;
    background: var(--bb-white);
    color: var(--bb-ink);
}
.desk-new-folder input[type="text"]:focus-visible {
    outline: 3px solid var(--bb-ink);
    outline-offset: 1px;
}
/* Comfortable 44px tap target on the "Create" button: .btn-green only has a small padding inherited from Bootstrap by default. */
.desk-new-folder .btn-green {
    min-height: 44px;
    padding: 0.5rem 1.25rem;
}

/* Drop zone: --bb-green-mid border (the site's action accent) on the gold background inherited from body.desk. Same shadow as .desk-new-folder next to it to stay visually related despite the different border style (dashed vs solid). */
.quick-upload-zone {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    padding: 1.5rem;
    border: 2px dashed var(--bb-green-mid);
    border-radius: 10px;
    box-shadow: var(--bb-shadow-soft);
    text-align: center;
    color: var(--bb-green-deep);
    font-weight: bold;
    cursor: pointer;
    transition: background-color 0.15s ease, border-color 0.15s ease;
}
.quick-upload-zone i {
    font-size: 1.3rem;
}
.quick-upload-zone:hover {
    background: rgba(var(--bb-gold-rgb), 0.25);
}
.quick-upload-zone.dragover {
    background: var(--bb-green-mid);
    border-style: solid;
    color: var(--bb-white);
}
.quick-upload-zone:focus-visible {
    outline: 3px solid var(--bb-white);
    outline-offset: 2px;
}
/* While uploading: no more green ("action possible"), the zone goes visually at rest to leave the spotlight to the progress bar below. cursor: progress rather than not-allowed, since clicking isn't broken, just does nothing more while it's uploading. */
.quick-upload-zone.uploading {
    border-color: var(--bb-ink);
    color: var(--bb-ink);
    cursor: progress;
    opacity: 0.7;
}

/* Wraps the drop zone/progress/status in a single .desk-actions cell: spacing between them comes from this gap, not individual margins. */
.desk-upload-card {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

/* Red/gold progress bar (brand colors): diagonal "construction site" stripes, a clear visual cue that something is actively happening, distinct from the rest of the green UI. Respects prefers-reduced-motion (static stripes). */
.quick-upload-progress-track {
    height: 0.9rem;
    border-radius: 999px;
    background: var(--bb-gold-pale);
    border: 1px solid var(--bb-ink);
    overflow: hidden;
}
.quick-upload-progress-bar {
    height: 100%;
    width: 0;
    background: repeating-linear-gradient(
        135deg,
        var(--bb-red) 0,
        var(--bb-red) 12px,
        var(--bb-gold) 12px,
        var(--bb-gold) 24px
    );
    background-size: 34px 34px;
    transition: width 0.2s ease;
}
@media (prefers-reduced-motion: no-preference) {
    .quick-upload-progress-bar {
        animation: quick-upload-stripes 1s linear infinite;
    }
}
@keyframes quick-upload-stripes {
    from {
        background-position: 0 0;
    }
    to {
        background-position: 34px 0;
    }
}
.quick-upload-progress-label {
    margin: 0.4rem 0 0;
    font-size: 0.85rem;
    font-weight: bold;
    color: var(--bb-ink);
}

.quick-upload-status {
    list-style: none;
    padding: 0;
    color: var(--bb-red-dark);
    font-weight: bold;
}

/* Folders: same solid --bb-green-mid pill as .role-badge, with the delete button INSIDE the pill rather than beside it in a second bubble, to stay in the same visual vocabulary as the rest of desk/admin. */
.desk-folders {
    list-style: none;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
}
.desk-folder-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    /* Deliberately asymmetric padding: at an even 16px/16px, the solid red delete button appeared closer to the edge than the folder icon, even though both CSS boxes are pixel-identical. This compensates for the optical effect, not the box itself. */
    padding: 0.4rem 1.3rem 0.4rem 1rem;
    background: var(--bb-green-mid);
    color: var(--bb-white);
    border-radius: 25px;
    font-weight: bold;
}
.desk-folder-badge a {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    color: var(--bb-white);
}
.desk-folder-badge a:hover,
.desk-folder-badge a:focus-visible {
    color: var(--bb-gold-pale);
}
.desk-folder-badge a:focus-visible {
    outline: 3px solid var(--bb-white);
    outline-offset: 2px;
}
.desk-folder-badge .btn-red {
    width: 1.75rem;
    height: 1.75rem;
    min-width: 1.75rem;
    font-size: 0.85rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
}

/* "Shared" note badge: same already-validated color pair as .role-badge/.desk-folder-badge, rather than an undefined Bootstrap badge-* class. */
.note-shared-badge {
    display: inline-block;
    background: var(--bb-green-mid);
    color: var(--bb-white);
    padding: 0.15rem 0.6rem;
    border-radius: 25px;
    font-size: 0.75rem;
    font-weight: bold;
    margin-left: 0.5rem;
}

/* Document list: a color-coded icon per file type for quick scanning of a large tree, name + meta on 2 lines, actions on the right. Plain lines separated by a rule rather than one card per row, consistent with avoiding large solid blocks on this page. */
.desk-documents {
    list-style: none;
    padding: 0;
}
.desk-document {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.6rem 0;
    border-bottom: 1px solid rgba(var(--bb-gold-rgb), 0.6);
}
.desk-document:last-child {
    border-bottom: none;
}
.desk-document-icon {
    flex-shrink: 0;
    width: 1.75rem;
    text-align: center;
    font-size: 1.25rem;
    color: var(--bb-ink);
}
.desk-document--audio .desk-document-icon {
    color: var(--bb-green-mid);
}
.desk-document--video .desk-document-icon {
    color: var(--bb-red-dark);
}
.desk-document--image .desk-document-icon {
    color: var(--bb-green-deep);
}
.desk-document-main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}
.desk-document-main a {
    font-weight: bold;
    overflow-wrap: anywhere;
}
.desk-document-meta {
    color: var(--bb-ink);
    font-size: 0.8rem;
    opacity: 0.8;
}

/* Favorite star: outline by default, solid green once active, the same "positive" green as .btn-green elsewhere. */
.desk-favorite-star {
    flex-shrink: 0;
    background: none;
    border: none;
    padding: 0.2rem;
    font-size: 1.2rem;
    line-height: 1;
    color: var(--bb-ink);
    cursor: pointer;
}
.desk-favorite-star.active {
    color: var(--bb-green-mid);
}
.desk-favorite-star:focus-visible {
    outline: 3px solid var(--bb-white);
    outline-offset: 2px;
}
/* .btn-red keeps its own focus-visible outline, already defined earlier in this file. */
.desk-document .btn-red {
    width: 2.25rem;
    height: 2.25rem;
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
}

.desk-empty {
    color: var(--bb-ink);
    opacity: 0.8;
}

/* Songs/voices (root level only). A rule above each song (except the first) separates them without stacking solid cards. */
.desk-track {
    padding-top: 1.5rem;
    border-top: 1px solid rgba(var(--bb-gold-rgb), 0.6);
}
.desk-track:first-of-type {
    padding-top: 0;
    border-top: none;
}
.desk-track h2 small {
    font-family: inherit;
    text-transform: none;
    font-weight: normal;
    color: var(--bb-ink);
    opacity: 0.75;
    letter-spacing: normal;
}
.desk-voices {
    list-style: none;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem 1rem;
}
.desk-voices li {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
}

/* Two-state pill: outline at rest, solid once active. Same radius/padding as .role-badge and .desk-folders a, staying in the same "pill" vocabulary across this page. */
.desk-voice-toggle {
    padding: 0.4rem 1rem;
    border-radius: 25px;
    border: 2px solid var(--bb-green-mid);
    background: transparent;
    color: var(--bb-green-deep);
    font-weight: bold;
    cursor: pointer;
}
.desk-voice-toggle.active {
    background: var(--bb-green-mid);
    border-color: var(--bb-green-mid);
    color: var(--bb-white);
}
.desk-voice-toggle:focus-visible {
    outline: 3px solid var(--bb-white);
    outline-offset: 2px;
}
.desk-voice-players {
    color: var(--bb-ink);
    font-size: 0.85rem;
    opacity: 0.8;
}

/* Per-row "Move" button: same size as the delete buttons above, --bb-ink color (a neutral action, neither positive green nor destructive red) to stay distinguishable among them. */
.desk-move-start {
    width: 1.75rem;
    height: 1.75rem;
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: var(--bb-ink);
    color: var(--bb-white);
}
.desk-folder-badge .desk-move-start {
    width: 1.75rem;
    height: 1.75rem;
    min-width: 1.75rem;
    font-size: 0.85rem;
}
.desk-document .desk-move-start {
    width: 2.25rem;
    height: 2.25rem;
}
.desk-move-start:hover,
.desk-move-start:focus-visible {
    background: var(--bb-green-mid);
    color: var(--bb-white);
}
.desk-move-start:focus-visible {
    outline: 3px solid var(--bb-white);
    outline-offset: 2px;
}

/* Tap targets (44px, as elsewhere on this page) for the icon-only buttons on folder pills and document rows, enlarged only on mobile where a finger replaces the mouse cursor, without changing their usual compact size on desktop where several sit side by side. */
@media (max-width: 576px) {
    .desk-favorite-star {
        min-width: 44px;
        min-height: 44px;
    }
    .desk-folder-badge .btn-red,
    .desk-folder-badge .desk-move-start,
    .desk-document .btn-red,
    .desk-document .desk-move-start {
        width: 44px;
        height: 44px;
        min-width: 44px;
    }
    .desk-voice-toggle {
        min-height: 44px;
    }
}

/* Move-mode banner ("choose a destination"): solid --bb-green-mid, the same "action possible" green as the rest of the page, to signal an active mode rather than passive info. Same shadow as .desk-new-folder/.quick-upload-zone for consistent depth across the page's "action" blocks. */
.desk-move-banner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.5rem;
    padding: 1rem 1.3rem;
    border-radius: 10px;
    background: var(--bb-green-mid);
    color: var(--bb-white);
    box-shadow: var(--bb-shadow-soft);
}
.desk-move-banner p {
    margin: 0;
    font-weight: bold;
}
.desk-move-actions {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
}
.desk-move-actions .btn-green {
    background: var(--bb-white);
    color: var(--bb-green-deep);
}
.desk-move-actions .btn-green:hover,
.desk-move-actions .btn-green:focus-visible {
    background: var(--bb-gold-pale);
}
.desk-move-actions .btn-link {
    color: var(--bb-white);
    font-weight: bold;
    text-decoration: underline;
}
.desk-move-actions .btn-link:focus-visible {
    outline: 3px solid var(--bb-white);
    outline-offset: 2px;
}

/* Search: same field style as .desk-new-folder's text input above, staying in the same "card" form vocabulary on this page. */
.desk-search {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem;
    margin-bottom: 1.5rem;
}
.desk-search input[type="search"] {
    flex: 1 1 14rem;
    min-height: 44px;
    padding: 0.5rem 0.75rem;
    border: 2px solid var(--bb-ink);
    border-radius: 8px;
    background: var(--bb-white);
    color: var(--bb-ink);
}
.desk-search input[type="search"]:focus-visible {
    outline: 3px solid var(--bb-ink);
    outline-offset: 1px;
}
/* Pushed to the right of the search bar: a secondary action (trash access), unrelated to the search itself. */
.desk-trash-link {
    margin-left: auto;
}
.desk-search-summary {
    color: var(--bb-ink);
    font-weight: bold;
    margin-bottom: 1.5rem;
}
/* Path of a search result (which folder it's in), below the name, same subdued treatment as .desk-document-meta. */
.desk-result-path {
    display: block;
    color: var(--bb-ink);
    font-size: 0.8rem;
    opacity: 0.75;
}

/* Document sort: text links, green at rest like the rest of this page's action links, bold once active rather than another pill (there are already plenty on this page). */
.desk-sort-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.9rem;
    margin-bottom: 0.75rem;
    font-size: 0.9rem;
}
.desk-sort-bar-label {
    color: var(--bb-ink);
    opacity: 0.75;
}
.desk-sort-link {
    color: var(--bb-green-mid);
    font-weight: bold;
}
.desk-sort-link.active {
    color: var(--bb-ink);
    text-decoration: underline;
}
.desk-sort-link:focus-visible {
    outline: 3px solid var(--bb-ink);
    outline-offset: 2px;
}

/* Multi-select: a checkbox per row. Sized comfortably by default, not just under the mobile @media like the icon buttons above, since a checkbox with no adjacent visible label benefits from a larger target than a native box's usual 1em. */
.desk-select {
    width: 1.3rem;
    height: 1.3rem;
    flex-shrink: 0;
    accent-color: var(--bb-green-mid);
}
.desk-select:focus-visible {
    outline: 3px solid var(--bb-ink);
    outline-offset: 2px;
}
.desk-bulk-toolbar {
    margin-bottom: 0.75rem;
}
.desk-select-all {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    color: var(--bb-ink);
    font-weight: bold;
    cursor: pointer;
}

/* Bulk actions bar: stuck at the bottom of the screen so it stays visible after scrolling a long list, same "action possible" green as .desk-move-banner. */
.desk-bulk-bar {
    position: sticky;
    bottom: 0;
    z-index: 5;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.9rem;
    margin: 1.5rem auto 0;
    max-width: 40rem;
    padding: 0.9rem 1.3rem;
    border-radius: 10px;
    background: var(--bb-green-mid);
    color: var(--bb-white);
    box-shadow: var(--bb-shadow-soft);
}
#desk-bulk-count {
    font-weight: bold;
    margin-right: auto;
}
.desk-bulk-bar .btn-green {
    background: var(--bb-white);
    color: var(--bb-green-deep);
}
.desk-bulk-bar .btn-green:hover,
.desk-bulk-bar .btn-green:focus-visible {
    background: var(--bb-gold-pale);
}

/* Drag-and-drop move: the folder hovered during a drag gets a clearly different background, the only reliable visual cue since the cursor itself can't be relied on during a native HTML5 drag. */
.desk-dropzone-active {
    background: var(--bb-green-deep) !important;
    outline: 3px dashed var(--bb-white);
    outline-offset: 2px;
}

/* Trash: reuses the .desk-folders/.desk-documents/.desk-folder-badge/.desk-document classes from the normal view, plus a few elements specific to this page. */
.desk-trash-back {
    display: inline-block;
    margin-bottom: 1rem;
}
.desk-trash-empty {
    margin-bottom: 1.5rem;
}

/* /desk/files hub: one card per space, same solid --bb-green-mid pill as .desk-folder-badge but large, since this is the page's main content rather than a secondary action. Same shadow as the rest of the file manager's "card" family. */
.desk-spaces {
    list-style: none;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
}
.desk-space-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.6rem;
    width: 12rem;
    padding: 2rem 1rem;
    background: var(--bb-green-mid);
    color: var(--bb-white);
    border-radius: 14px;
    font-weight: bold;
    text-align: center;
    box-shadow: var(--bb-shadow-soft);
    transition: background-color 0.15s ease, transform 0.15s ease;
}
.desk-space-card i {
    font-size: 2.5rem;
}
.desk-space-card:hover,
.desk-space-card:focus-visible {
    background: var(--bb-green-deep);
    color: var(--bb-white);
    transform: translateY(-2px);
}
.desk-space-card:focus-visible {
    outline: 3px solid var(--bb-white);
    outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
    .desk-space-card {
        transition: none;
    }
}
/* Below 400px (a single column regardless, given the gap), the card fills the available width instead of staying fixed at 12rem with an asymmetric gap beside it. */
@media (max-width: 400px) {
    .desk-space-card {
        width: 100%;
        max-width: 20rem;
    }
}

/* Document preview modal: white background rather than the brand palette, so it doesn't tint the colors of an image/PDF shown inside.
   [hidden]: the display:flex rule below has the same specificity as the browser's default [hidden] { display: none }, and author-origin rules (this file) win over user-agent ones at equal specificity, so without this explicit override the modal stayed displayed despite the hidden attribute set by file-preview.js. */
.file-preview-modal[hidden] {
    display: none;
}
.file-preview-modal {
    position: fixed;
    inset: 0;
    z-index: 2000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1.5rem;
}
.file-preview-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(22, 20, 15, 0.85);
}
.file-preview-dialog {
    position: relative;
    display: flex;
    flex-direction: column;
    width: 100%;
    max-width: 900px;
    max-height: 100%;
    background: var(--bb-white);
    border-radius: 10px;
    overflow: hidden;
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.4);
}
.file-preview-header {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0.75rem 1rem;
    background: var(--bb-red);
    color: var(--bb-white);
}
.file-preview-header h2 {
    flex: 1;
    min-width: 0;
    margin: 0;
    font-family: inherit;
    font-size: 1rem;
    font-weight: bold;
    color: var(--bb-white);
    overflow-wrap: anywhere;
}
.file-preview-download,
.file-preview-close {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    background: none;
    border: none;
    color: var(--bb-white);
    font-weight: bold;
    cursor: pointer;
}
.file-preview-close {
    font-size: 1.3rem;
    padding: 0.2rem;
}
.file-preview-download:hover,
.file-preview-close:hover {
    color: var(--bb-gold-pale);
}
.file-preview-download:focus-visible,
.file-preview-close:focus-visible {
    outline: 3px solid var(--bb-white);
    outline-offset: 2px;
}
.file-preview-body {
    flex: 1;
    min-height: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    overflow: auto;
    background: var(--bb-ink);
}
.file-preview-body img {
    max-width: 100%;
    max-height: 75vh;
    object-fit: contain;
}
.file-preview-body iframe {
    width: 100%;
    height: 75vh;
    border: none;
    background: var(--bb-white);
}
.file-preview-body audio {
    width: 100%;
}
.file-preview-body video {
    max-width: 100%;
}

/* Same contrast fix already applied to body.desk form (gold on green only reaches 3.63:1, below AA). White reaches AAA (6.82:1). */
.registration-form {
    color: var(--bb-white);
}
.registration-form .invalid-feedback {
    color: var(--bb-gold-pale);
}

/* /register header, using the Bungee display font and .text-green (7.15:1 on the gold background, AAA). */
.registration-header {
    text-align: center;
    margin: 2rem auto 1.5rem;
}
.registration-header h1 {
    display: inline-block;
    margin: 0;
    font-family: "Bungee", "Arial Black", sans-serif;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    font-size: 1.8rem;
}

/* Mandatory-admin-validation warning + membership fee reminder: --bb-green-deep background (already used elsewhere for this dark card/panel role) with the gold border already the site's most common color pair. Red only reaches 3.03:1/2.15:1 here (below AA), so no red: bold text + icon carry the "warning" distinction instead of relying on hue. White text reaches 13.4:1 (AAA). */
.registration-notice {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    background: var(--bb-green-deep);
    border: 2px solid var(--bb-gold);
    border-radius: 12px;
    box-shadow: var(--bb-shadow-soft);
    padding: 1.25rem 1.5rem;
    margin: 0 auto 2rem;
    max-width: 560px;
    text-align: left;
    color: var(--bb-white);
}
.registration-notice > i {
    font-size: 1.5rem;
    flex-shrink: 0;
    margin-top: 0.15rem;
    color: var(--bb-gold);
}
.registration-notice-warning {
    font-weight: bold;
    margin: 0 0 0.5rem;
}
.registration-notice p:last-child {
    /* --bb-gold-pale on --bb-green-deep: 9.9:1 (AAA), distinguishes this secondary paragraph from the first (warning, white) without relying on bold alone. */
    margin: 0;
    color: var(--bb-gold-pale);
}

/* "Already a member?" question at the top of /register: same detached-card treatment as .registration-notice above (--bb-green-deep + gold border, same verified contrasts), for visual consistency between the two cards on this page. */
.already-member-step {
    background: var(--bb-green-deep);
    border: 2px solid var(--bb-gold);
    border-radius: 12px;
    box-shadow: var(--bb-shadow-soft);
    padding: 1.5rem;
    margin: 0 auto 2rem;
    max-width: 560px;
    text-align: center;
    color: var(--bb-white);
}
.already-member-fieldset {
    border: 0;
    padding: 0;
    margin: 0;
}
.already-member-step legend {
    font-size: 1.2rem;
    font-weight: bold;
    color: var(--bb-white);
    margin: 0 0 1rem;
}
.already-member-hint {
    color: var(--bb-gold-pale);
    margin: 1rem 0 0;
}

/* Yes/No toggle as pill buttons rather than tiny, easy-to-miss radio bullets. The native input is kept (keyboard focus, native radio behavior, screen readers) but visually hidden: the label becomes the real visible button, clickable via its "for" even though the input itself is nearly invisible. */
.already-member-toggle {
    display: flex;
    justify-content: center;
    gap: 1rem;
    flex-wrap: wrap;
}
.already-member-toggle .form-check {
    position: relative;
    margin: 0;
    padding: 0;
}
.already-member-toggle .form-check-input {
    position: absolute;
    opacity: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    cursor: pointer;
}
.already-member-toggle .form-check-label {
    display: inline-flex;
    align-items: center;
    padding: 0.6rem 2rem;
    border-radius: 50px;
    border: 2px solid var(--bb-gold);
    background: transparent;
    color: var(--bb-white);
    font-weight: bold;
    cursor: pointer;
    transition: all 0.15s ease;
}
.already-member-toggle .form-check-input:checked + .form-check-label {
    background: var(--bb-gold);
    color: var(--bb-ink);
}
.already-member-toggle .form-check-input:focus-visible + .form-check-label {
    outline: 3px solid var(--bb-white);
    outline-offset: 2px;
}

/* HelloAsso reminder shown only when "No" is selected. Icon + text block rather than a plain paragraph, nested in the question card above rather than a separate second card, to stay visually tied to the answer that triggered it. */
.already-member-followup {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    text-align: left;
    margin-top: 1.5rem;
    padding-top: 1.5rem;
    border-top: 1px solid rgba(242, 178, 51, 0.35);
}
.already-member-followup > i {
    font-size: 1.5rem;
    flex-shrink: 0;
    margin-top: 0.15rem;
    color: var(--bb-gold-pale);
}
.already-member-followup-content {
    flex: 1;
    min-width: 0;
}
.already-member-followup-content p:first-child {
    color: var(--bb-white);
    margin-top: 0;
}
.already-member-followup-content .btn-green {
    margin: 0.5rem 0;
}
.already-member-note {
    font-size: 0.9rem;
    color: var(--bb-gold-pale);
    margin: 0.5rem 0 0;
}

/* Accounting space: sub-navigation for Files/Quotes & Invoices/Treasury, treasury balance, quote/invoice lines added dynamically. */
.accounting-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
    margin-bottom: 1.5rem;
}
.accounting-tab {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.5rem 1rem;
    background: var(--bb-green-mid);
    color: var(--bb-white);
    border-radius: 25px;
    font-weight: bold;
}
.accounting-tab:hover,
.accounting-tab.active {
    background: var(--bb-green-deep);
    color: var(--bb-white);
}
.accounting-tab:focus-visible {
    outline: 3px solid var(--bb-ink);
    outline-offset: 2px;
}

.accounting-balance {
    font-size: 1.3rem;
    color: var(--bb-ink);
    margin-bottom: 1rem;
}
.accounting-balance.negative strong {
    color: var(--bb-red-dark);
}
/* --bb-green-mid/--bb-red-dark reach 6.81:1 and 8.56:1 on the table's white background (AAA): color only reinforces the +/- sign already in front of the amount, which remains the primary info for a screen reader. */
.accounting-income {
    color: var(--bb-green-mid);
    font-weight: bold;
}
.accounting-expense {
    color: var(--bb-red-dark);
    font-weight: bold;
}

/* Quote/invoice line items: label/price/quantity side by side on desktop (stacked on mobile), the delete button aligned to the fields' height rather than their label. */
.accounting-line-row {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 0.75rem;
    margin-bottom: 0.5rem;
    padding-bottom: 0.5rem;
    border-bottom: 1px solid rgba(255, 255, 255, 0.25);
}
.accounting-line-row .form-group {
    margin-bottom: 0;
}
.accounting-line-row .form-group:first-child {
    flex: 3 1 12rem;
}
.accounting-line-row .form-group:not(:first-child) {
    flex: 1 1 6rem;
}

/* Same fix as .profile-form-card h2 above: the default body.desk h2 color is unreadable on the quote/invoice form's dark green background, so white is used instead. Prefixed with "body.desk" (2 classes, 0,2,0) rather than the class alone (0,1,0), which would lose to body.desk h2's higher specificity (0,1,2). */
body.desk .accounting-lines-heading {
    color: var(--bb-white);
}

/* "New client" link in the quote/invoice form: .text-green is meant for text on the page's gold background, not this form's green background, where it would be dark-green-on-green and nearly unreadable. --bb-gold-pale instead, the same choice as .invalid-feedback above, already verified at 5.04:1 (AA) on this background. */
.accounting-form-link {
    color: var(--bb-gold-pale);
    text-decoration: underline;
}
.accounting-form-link:hover,
.accounting-form-link:focus-visible {
    color: var(--bb-white);
}

/* Action button row for the Quotes/Invoices/Clients pages (1 to 4 buttons depending on context): unlike .desk-actions, a 2-column grid meant specifically for two equal-weight blocks, this is a simple wrapping flex where each button keeps its natural content width (.btn-green already has width: fit-content). */
.accounting-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 1.5rem;
}

/* Carpool board (/desk/carpool): one heading per event, offers below as cards. Event heading keeps the default body.desk h2 style (dark ink, readable on the page's gold background); the cards below switch to a darker surface, so they get their own text color rather than inheriting that dark ink (would be close to unreadable on --bb-green-deep). */
.carpool-event-heading {
    margin: 2rem 0 1rem;
}
.carpool-event-heading:first-of-type {
    margin-top: 0;
}
.carpool-event-location {
    font-weight: normal;
    font-size: 0.95rem;
}
.carpool-offer-list {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 1rem;
    margin-bottom: 1rem;
}
/* Reuses .profile-form-card for the same green-deep/gold-border/shadow surface as the rest of /desk, just adds the white text color that card family assumes its content will set for itself (cf. .profile-form-card h2 doing the same for headings). */
.carpool-offer-card {
    color: var(--bb-white);
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}
.carpool-offer-header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}
.carpool-offer-departure,
.carpool-offer-comment,
.carpool-passengers-heading {
    margin: 0;
}
.carpool-passengers-heading {
    font-weight: bold;
    margin-top: 0.4rem;
}
.carpool-passenger-list {
    margin: 0;
    padding-left: 1.2rem;
}
.carpool-offer-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.4rem;
}
