/* ==========================================================================
   Blowout Draft -- global theme
   Bootstrap (layout/utilities) + Web Awesome (components/tokens) + Font Awesome
   (icons) are loaded in App.razor. This file defines the brand palette and the
   handful of global styles our own chrome (nav, hero, footer, dashboard) uses.
   ========================================================================== */

:root {
    /* Brand: field-grass green (sampled from grass-background.jpg) with a warm amber
       accent for CTAs and a deep forest-green ink for the chrome. */
    --bd-brand: #3f7d1e;
    --bd-brand-strong: #2c5614;
    --bd-brand-soft: #eaf3e0;
    --bd-accent: #ff8a1e;
    --bd-accent-strong: #e6730a;
    --bd-ink: #10220b;
    --bd-ink-soft: #1a3312;
    --bd-ink-line: #2b4a1f;

    /* Win/loss semantic colors. */
    --bd-win: #16a34a;
    --bd-loss: #dc2626;

    --bd-header-h: 4rem;
}

/* Font Awesome runs as an SVG+JS kit: it swaps each <i class="fa-..."> for an <svg class=
   "svg-inline--fa"> and injects the sizing CSS (height:1em, etc.) into <head> at runtime. Blazor's
   enhanced navigation morphs <head> against the server response and strips that runtime-injected
   <style>, so after any navigation (or a back/forward) icons lose their height constraint and balloon
   to their intrinsic ~1em-of-nothing size. Pinning the core rules here -- in a linked stylesheet that
   enhanced nav preserves -- keeps icons correctly sized across navigation. */
.svg-inline--fa {
    display: var(--fa-display, inline-block);
    height: 1em;
    overflow: visible;
    vertical-align: -0.125em;
}

html, body {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

h1, h2, h3, .bd-display {
    font-weight: 800;
    letter-spacing: -0.02em;
}

a {
    color: var(--bd-brand);
}

/* ==========================================================================
   Shared UI primitives -- GLOBAL on purpose. Blazor scoped (.razor.css) styles
   only reach a component's own markup, not page content projected through
   @Body, so anything reused across layouts + pages must live here.
   ========================================================================== */

/* --- Brand wordmark --- */
.bd-brand {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    font-weight: 800;
    font-size: 1.35rem;
    letter-spacing: -0.02em;
    color: #fff;
    text-decoration: none;
    white-space: nowrap;
}

.bd-brand--sm { font-size: 1.15rem; }
.bd-brand__accent { color: var(--bd-accent); }

.bd-brand__mark {
    display: inline-grid;
    place-items: center;
    width: 2.2rem;
    height: 2.2rem;
    border-radius: 0.6rem;
    background: linear-gradient(135deg, var(--bd-brand), var(--bd-brand-strong));
    color: #fff;
    font-size: 1.1rem;
    transform: rotate(-8deg);
}

.bd-brand__mark--sm { width: 1.8rem; height: 1.8rem; font-size: 0.9rem; }

/* --- Eyebrow label --- */
.bd-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-size: 0.8rem;
    color: var(--bd-accent);
    background: rgba(255, 138, 30, 0.12);
    padding: 0.35rem 0.75rem;
    border-radius: 999px;
}

/* --- Brand buttons (anchors or <button>) --- */
.bd-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    font-weight: 700;
    padding: 0.5rem 1.05rem;
    border-radius: 0.6rem;
    text-decoration: none;
    border: 1px solid transparent;
    cursor: pointer;
    transition: transform .05s ease, filter .15s ease, background-color .15s ease;
    white-space: nowrap;
}

.bd-btn:active { transform: translateY(1px); }
.bd-btn--accent { background: var(--bd-accent); color: #221202; }
.bd-btn--accent:hover { filter: brightness(1.06); color: #221202; }
.bd-btn--brand { background: var(--bd-brand); color: #fff; }
.bd-btn--brand:hover { background: var(--bd-brand-strong); color: #fff; }
.bd-btn--ghost { color: #fff; border-color: rgba(255, 255, 255, 0.28); }
.bd-btn--ghost:hover { background: rgba(255, 255, 255, 0.1); color: #fff; }
.bd-btn--ghost-dark { border-color: rgba(255, 255, 255, 0.35); color: #fff; }
.bd-btn--lg { padding: 0.7rem 1.5rem; font-size: 1.05rem; }

/* --- External (OAuth) sign-in buttons: ExternalLoginPicker, on Login and Register --------------
   Deliberately NOT .bd-btn: these are provider identity, not site chrome. A neutral card with the
   provider's own mark reads as "that company's sign-in" and keeps every provider equal weight,
   where painting them all brand-green would make them look like our buttons rather than theirs.
   Lives here rather than in a scoped .razor.css because the Font Awesome kit swaps each <i> for an
   <svg> at runtime, which scoped CSS's compile-time attribute rewriting doesn't reach. */
.bd-oauth {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    max-width: 300px;
}

.bd-oauth__btn {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    width: 100%;
    padding: 0.65rem 1rem;
    font-weight: 600;
    font-size: 0.95rem;
    line-height: 1.25;
    color: var(--bd-ink);
    background: #fff;
    border: 1px solid #d4d9d0;
    border-radius: 0.6rem;
    cursor: pointer;
    transition: background-color .15s ease, border-color .15s ease, transform .05s ease;
}

.bd-oauth__btn:hover { background: #f6f8f4; border-color: #b9c2b2; }
.bd-oauth__btn:active { transform: translateY(1px); }
.bd-oauth__btn:focus-visible { outline: 2px solid var(--bd-brand); outline-offset: 2px; }

/* Fixed-width slot so every label starts on the same x, whatever the glyph's natural width. */
.bd-oauth__icon {
    flex: 0 0 1.25rem;
    display: flex;
    justify-content: center;
    font-size: 1.15rem;
}

/* Each mark in its own brand colour. Font Awesome's marks are single-colour, so these are the
   providers' primary brand values rather than their full multi-colour logos. */
.bd-oauth__btn--google .bd-oauth__icon { color: #4285f4; }
.bd-oauth__btn--microsoft .bd-oauth__icon { color: #00a4ef; }
.bd-oauth__btn--apple .bd-oauth__icon { color: #000; }
.bd-oauth__btn--facebook .bd-oauth__icon { color: #1877f2; }
.bd-oauth__btn--generic .bd-oauth__icon { color: var(--bd-brand); }

/* --- Hub prompt callouts (series renewal, pending invitations): a message with yes/no answers --- */
.bd-hubprompt {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem 1rem;
    margin-bottom: 1rem;
}

.bd-hubprompt__body { display: flex; align-items: baseline; gap: 0.6rem; min-width: 0; }
.bd-hubprompt__icon { color: var(--bd-brand); flex: none; }
.bd-hubprompt__text { min-width: 0; }

/* Keeps both answers on one line and away from the message as the callout narrows. */
.bd-hubprompt__actions { display: flex; gap: 0.5rem; flex: none; }

/* Dashboard stub page heading */
.bd-stub__title { font-size: 1.9rem; margin: 0 0 1.25rem; }

/* --- Dashboard page header (shared: scoreboard, commissioner, future dashboard pages) --- */
.bd-page__head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.5rem;
}

.bd-page__crumb {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--bd-brand);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

/* Breadcrumb trail (see Breadcrumbs.razor): inherits the crumb's brand/uppercase styling, laid out
   inline with muted separators. Links carry the brand colour and underline on hover. */
.bd-crumbs {
    display: inline-flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.4rem;
}

.bd-crumbs a { color: inherit; text-decoration: none; }
.bd-crumbs a:hover { text-decoration: underline; }
.bd-crumbs__link i { margin-right: 0.25rem; }
.bd-crumbs__sep { opacity: 0.45; font-weight: 400; }

.bd-page__title { font-size: 1.9rem; margin: 0.15rem 0 0; }
.bd-page__lede { color: #5b6672; font-size: 0.95rem; margin: 0 0 1.5rem; }

/* --- Blazor framework UI (moved here from the deleted default MainLayout) --- */
#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;
    }

.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."
    }

/* FocusOnNavigate (Routes.razor) moves focus to the page <h1> after each navigation so screen readers
   announce the new heading. The heading isn't interactive, so suppress the focus ring the browser would
   otherwise draw on it -- keyboard users can't Tab to a tabindex=-1 heading, so nothing is lost. */
h1:focus { outline: none; }

/* --- Form validation (from the default template) --- */
.valid.modified:not([type=checkbox]) { outline: 1px solid #26b050; }
.invalid { outline: 1px solid #e50000; }
.validation-message { color: #e50000; }

/* --- Cookie consent banner (rendered in App.razor; shown/hidden by wwwroot/js/consent.js) --- */
.bd-consent {
    position: fixed;
    left: 1rem;
    right: 1rem;
    bottom: 1rem;
    z-index: 2000;
    max-width: 60rem;
    margin: 0 auto;
    display: flex;
    align-items: center;
    gap: 1rem 1.5rem;
    flex-wrap: wrap;
    justify-content: space-between;
    padding: 1rem 1.25rem;
    background: var(--bd-ink, #10220b);
    color: #fff;
    border: 1px solid var(--bd-ink-line, #2b4a1f);
    border-radius: 0.75rem;
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.35);
}
.bd-consent[hidden] { display: none; }
.bd-consent__text { flex: 1 1 20rem; font-size: 0.9rem; line-height: 1.4; }
.bd-consent__text a { color: var(--bd-accent, #ff8a1e); }
.bd-consent__actions { display: flex; gap: 0.5rem; flex-shrink: 0; }
.bd-consent__btn {
    border: 1px solid transparent;
    border-radius: 0.5rem;
    padding: 0.5rem 1.1rem;
    font-weight: 700;
    cursor: pointer;
}
.bd-consent__btn--accent { background: var(--bd-accent, #ff8a1e); color: var(--bd-ink, #10220b); }
.bd-consent__btn--accent:hover { background: var(--bd-accent-strong, #e6730a); }
.bd-consent__btn--ghost { background: transparent; color: #fff; border-color: rgba(255, 255, 255, 0.4); }
.bd-consent__btn--ghost:hover { background: rgba(255, 255, 255, 0.1); }

/* --- Broadcast banners (BroadcastBanners.razor) + admin editor (Admin.razor) --- */
.bd-broadcasts { margin-bottom: 1rem; }
.bd-dashmain > .bd-broadcasts { margin-top: 0.25rem; }
.bd-broadcasts .bd-broadcast { margin-bottom: 0.75rem; }
.bd-broadcasts .bd-broadcast:last-child { margin-bottom: 0; }
/* Markdown wraps the body in <p>; drop the trailing margin so the alert isn't bottom-heavy. */
.bd-broadcast > :last-child { margin-bottom: 0; }

.bd-checkrow { display: flex; flex-wrap: wrap; gap: 0.6rem 1.25rem; }
.bd-checkrow label { display: inline-flex; align-items: center; gap: 0.35rem; margin: 0; }
.bd-broadcast-form { border: 1px solid #e3e6ea; border-radius: 0.6rem; padding: 1rem; margin-bottom: 1rem; }

/* Bootstrap and Web Awesome's native.css both style native form controls. On anything wearing
   Bootstrap's .form-check-input (checkboxes, switches, radios) they collide: Bootstrap draws the
   check/knob/dot via the input's background-image, while Web Awesome layers a second, masked
   checkmark through an ::after pseudo -- giving a "double checkmark". Bootstrap owns .form-check-input
   controls, so suppress Web Awesome's extra check there. Plain <input type=checkbox> (e.g. the modal
   toggles) keep the Web Awesome treatment. */
.form-check-input::after { display: none !important; }

/* ===== Error pages (500 "Fumble!" + 404 "Fourth & long") =====
   Lives in the global stylesheet (a static asset that still serves during a 500), not scoped CSS, so
   the pages stay styled even when the app is throwing. The .bd-err wrapper is the minimal ErrorLayout;
   the .bd-err__hero block is reused inside BrochureLayout for the 404. */
.bd-err {
    min-height: 100vh;
    min-height: 100svh;
    display: flex;
    flex-direction: column;
    background:
        radial-gradient(1100px 460px at 50% -8%, var(--bd-brand-soft, #eaf3e0), transparent 62%),
        #fff;
}

.bd-err__brand {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 1.25rem clamp(1rem, 4vw, 2.5rem);
    font-weight: 800;
    font-size: 1.2rem;
    color: var(--bd-ink, #10220b);
    text-decoration: none;
}
.bd-err__brand-mark { font-size: 1.4rem; }
.bd-err__brand-accent { color: var(--bd-accent, #ff8a1e); }

.bd-err__main {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: clamp(1rem, 4vw, 3rem) 1.25rem clamp(3rem, 8vw, 6rem);
}

/* Standalone framing when the hero rides inside BrochureLayout (the 404). */
.bd-err__standalone {
    display: flex;
    justify-content: center;
    padding: clamp(2.5rem, 8vw, 6rem) 1.25rem;
}

.bd-err__hero {
    text-align: center;
    max-width: 40rem;
}

.bd-err__art {
    width: min(78vw, 330px);
    margin: 0 auto clamp(1rem, 3vw, 2rem);
}
.bd-err__art svg { width: 100%; height: auto; display: block; overflow: visible; }

.bd-err__art--fumble { transform-origin: 50% 88%; animation: bd-err-fumble 1.7s ease-in-out infinite; }
.bd-err__art--fly { animation: bd-err-float 3.2s ease-in-out infinite; }
.bd-err__spark { animation: bd-err-spark 1.7s ease-in-out infinite; }

@keyframes bd-err-fumble {
    0%, 100% { transform: translateY(0) rotate(-7deg); }
    25%      { transform: translateY(-16px) rotate(7deg); }
    50%      { transform: translateY(0) rotate(-3deg); }
    75%      { transform: translateY(-7px) rotate(9deg); }
}
@keyframes bd-err-float {
    0%, 100% { transform: translateY(0) rotate(0deg); }
    50%      { transform: translateY(-12px) rotate(-2deg); }
}
@keyframes bd-err-spark {
    0%, 100% { opacity: 0.25; }
    30%      { opacity: 1; }
}

.bd-err__code {
    font-weight: 800;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--bd-brand, #3f7d1e);
    font-size: 0.9rem;
    margin: 0 0 0.4rem;
}

.bd-err__title {
    font-size: clamp(2.8rem, 13vw, 6rem);
    line-height: 0.95;
    font-weight: 900;
    letter-spacing: -0.02em;
    color: var(--bd-ink, #10220b);
    margin: 0 0 1rem;
}

/* The signature "FUMBLE!" — accent gradient, cocked slightly like it just hit the turf. */
.bd-err__title--fumble {
    display: inline-block;
    background: linear-gradient(180deg, var(--bd-accent, #ff8a1e), var(--bd-accent-strong, #e6730a));
    -webkit-background-clip: text;
    background-clip: text;
    color: var(--bd-accent, #ff8a1e); /* fallback if text-fill unsupported */
    -webkit-text-fill-color: transparent;
    transform: rotate(-3deg);
    filter: drop-shadow(0 3px 0 rgba(16, 34, 11, 0.14));
}

.bd-err__lede {
    font-size: clamp(1rem, 2.4vw, 1.18rem);
    color: #4b5563;
    margin: 0 auto 1.75rem;
    max-width: 33rem;
}

.bd-err__actions {
    display: flex;
    gap: 0.75rem;
    justify-content: center;
    flex-wrap: wrap;
}

/* Outline button that reads on the light error background (bd-btn--ghost is white-on-dark). */
.bd-err__btn-outline {
    background: #fff;
    color: var(--bd-brand, #3f7d1e);
    border-color: color-mix(in srgb, var(--bd-brand, #3f7d1e) 40%, transparent);
}
.bd-err__btn-outline:hover {
    background: var(--bd-brand-soft, #eaf3e0);
    color: var(--bd-brand-strong, #2c5614);
}

.bd-err__report { margin-top: 1.5rem; font-size: 0.95rem; color: #4b5563; }
.bd-err__report a { color: var(--bd-brand, #3f7d1e); font-weight: 700; }
.bd-err__report a:hover { color: var(--bd-brand-strong, #2c5614); }

.bd-err__meta { margin-top: 0.9rem; font-size: 0.8rem; color: #94a3b8; }
.bd-err__meta code { color: #64748b; }

@media (prefers-reduced-motion: reduce) {
    .bd-err__art--fumble,
    .bd-err__art--fly,
    .bd-err__spark { animation: none; }
}

/* ==========================================================================
   Home-grown replacements for Web Awesome components (migration off WA).
   ========================================================================== */

/* ----- Callout (replaces <wa-callout>): tinted, left-accented message box ----- */
.bd-callout {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    margin: 0 0 1rem;
    padding: 0.75rem 1rem;
    border: 1px solid var(--bd-callout-border, #e5e7eb);
    border-left-width: 4px;
    border-radius: 0.5rem;
    background: var(--bd-callout-bg, #f3f4f6);
}
/* The leading icon. BOTH selectors are needed: the markup ships an <i>, but the Font Awesome kit
   swaps it for an <svg> at runtime (see the note at the top of this file), and an `i` selector stops
   matching the moment it does -- which silently dropped the nudge, the shrink guard and the accent
   colour in every real browser, leaving the glyph top-aligned and in the body text's colour.
   The icon is a flex item, so it can't pick up the line box's half-leading the way inline content
   does; 0.25em is that half-leading at the callout's 16px/24px type, centring the 1em glyph on the
   first line instead of hanging it off the top. */
.bd-callout > i:first-child,
.bd-callout > svg:first-child {
    margin-top: 0.25em;
    flex-shrink: 0;
    color: var(--bd-callout-accent, #6b7280);
}
.bd-callout--neutral { --bd-callout-accent: #6b7280; --bd-callout-bg: #f3f4f6; --bd-callout-border: #e5e7eb; }
.bd-callout--brand   { --bd-callout-accent: var(--bd-brand, #3f7d1e); --bd-callout-bg: var(--bd-brand-soft, #eaf3e0); --bd-callout-border: color-mix(in srgb, var(--bd-brand, #3f7d1e) 30%, transparent); }
.bd-callout--success { --bd-callout-accent: #1a7f37; --bd-callout-bg: #e8f5ec; --bd-callout-border: #bfe3c9; }
.bd-callout--danger  { --bd-callout-accent: #b3261e; --bd-callout-bg: #fdecec; --bd-callout-border: #f5c2c2; }
.bd-callout--warning { --bd-callout-accent: #a15c07; --bd-callout-bg: #fdf2e1; --bd-callout-border: #f5d9a8; }

/* ----- Card (replaces <wa-card>): white surface, hairline border, soft shadow ----- */
.bd-card {
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 0.75rem;
    padding: 1.25rem;
    box-shadow: 0 1px 2px rgba(16, 24, 40, 0.04);
}

/* ----- Tool tiles: a grid of big, tappable choices -------------------------------------------
   Used by the commissioner tools (as <a>) and the "join a league" picker on /create-new-entry (as
   <button>). GLOBAL because of that second caller: these lived in Commissioner.razor.css, a scoped
   sheet, so the league picker rendered them completely unstyled -- bare bordered boxes. */
.bd-tools {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
    gap: 1rem;
}

.bd-tool {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    padding: 1.1rem 1.2rem;
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 0.8rem;
    text-decoration: none;
    color: inherit;
    transition: border-color .15s, box-shadow .15s, transform .05s;
    /* Normalize the <button> caller against the <a> one: a button otherwise centres its text,
       shrink-wraps, and inherits none of the page's typography. */
    width: 100%;
    text-align: left;
    font: inherit;
    cursor: pointer;
}

.bd-tool:hover {
    border-color: var(--bd-brand);
    box-shadow: 0 2px 10px rgba(16, 34, 11, 0.06);
}

.bd-tool:active { transform: translateY(1px); }
.bd-tool:focus-visible { outline: 2px solid var(--bd-brand); outline-offset: 2px; }

.bd-tool__icon {
    display: inline-grid;
    place-items: center;
    width: 2.6rem;
    height: 2.6rem;
    flex: none;
    border-radius: 0.6rem;
    background: var(--bd-brand-soft);
    color: var(--bd-brand-strong);
    font-size: 1.1rem;
}

.bd-tool__body { display: flex; flex-direction: column; gap: 0.15rem; flex: 1; min-width: 0; }
.bd-tool__title { font-weight: 700; color: var(--bd-ink); }
.bd-tool__desc { font-size: 0.85rem; color: #6b7280; line-height: 1.3; }
.bd-tool__go { color: #c2c9d2; font-size: 0.9rem; flex: none; }

/* The picker's current choice. Ringed rather than merely tinted so it stays obvious against the
   hover state on its neighbours. */
.bd-tool.is-selected {
    border-color: var(--bd-brand);
    background: var(--bd-brand-soft);
    box-shadow: inset 0 0 0 1px var(--bd-brand);
}

.bd-tool.is-selected .bd-tool__icon { background: #fff; }
.bd-tool.is-selected .bd-tool__go { color: var(--bd-brand-strong); }

/* Unavailable tools (not yet built) and unjoinable leagues (full / locked / at your cap) render
   muted and non-interactive. */
.bd-tool.is-soon { opacity: 0.6; cursor: default; }
.bd-tool.is-soon:hover { border-color: #e5e7eb; box-shadow: none; }

.bd-tool__soon {
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: #9aa5b4;
    white-space: nowrap;
}

/* ==========================================================================
   Primitives promoted out of scoped stylesheets
   --------------------------------------------------------------------------
   Each of these was defined inside one component's .razor.css while other
   components used the same class name -- and a scoped sheet only ever reaches
   its own component, so those other pages rendered the markup unstyled. (That's
   what left the league picker as bare boxes and the leagues directory without
   table headers.) Promoting them here is safe for the components that already
   had their own copy: a scoped rule carries an extra attribute selector and
   loads after this file, so it still wins. Anything genuinely page-specific
   deliberately stays scoped.
   ========================================================================== */

/* ----- Tables ----- */
.bd-table { margin: 0; }

.bd-table thead th {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: #8a94a3;
    border-bottom: 2px solid #e5e7eb;
}

/* Figures line up column-wise; used in table cells and stat rows alike. */
.bd-num { font-variant-numeric: tabular-nums; font-weight: 600; }

/* ----- Text tones ----- */
.bd-muted { color: #6b7280; }
.bd-strong { font-weight: 700; color: var(--bd-ink); }
.bd-hint { font-size: 0.82rem; color: #6b7280; margin-top: 0.2rem; }

/* ----- Forms ----- */
/* The width of a form is its page's business; the label treatment isn't. */
.bd-form .form-label { font-weight: 600; }

.bd-form__msg { display: block; margin-bottom: 1.25rem; }

.bd-form__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.5rem;
}

/* A standalone message block above page content. */
.bd-msg { margin-bottom: 1rem; }

/* ----- Header action cluster (buttons/selects beside a page title) ----- */
.bd-controls { display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center; }

/* ----- Pick state ("In" / "No pick yet" / missed) ----- */
.bd-pickstate { font-weight: 600; }
.bd-pickstate--in { color: var(--bd-win, #16a34a); }
.bd-pickstate--miss { color: var(--bd-loss, #dc2626); }
.bd-pickstate--out { color: #9aa5b4; }

/* ----- Invitation status pill ----- */
.bd-invites__title { font-size: 1.15rem; margin: 2rem 0 0.75rem; }

.bd-invstatus {
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    padding: 0.15rem 0.5rem;
    border-radius: 0.35rem;
}

.bd-invstatus.is-accepted { background: var(--bd-brand-soft); color: var(--bd-brand-strong); }
.bd-invstatus.is-pending { background: #fff3e0; color: var(--bd-accent-strong); }

/* ----- Card with a heading and a count beside it (league home, leagues directory) ----- */
.bd-leaguehome + .bd-leaguehome { margin-top: 1rem; }

.bd-leaguehome__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 0.5rem;
}

.bd-leaguehome__count { color: #6b7280; font-size: 0.85rem; font-weight: 600; }
.bd-leaguehome__empty { color: #999; font-style: italic; }
.bd-leaguehome__entry { font-weight: 600; }

/* ----- Section heading used on the profile, badges and NFL game pages ----- */
.bd-profile__h {
    font-size: 1.05rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    opacity: 0.8;
    margin-bottom: 0.75rem;
}

/* ----- Long-form content pages (How to Play, Contribute, Terms, Privacy, Cookies) ----- */
.bd-article { max-width: 46rem; padding-top: 2.5rem; }

/* Shared by How to Play and Contribute, so it can't live in either one's scoped sheet. */
.bd-article__cta { text-align: center; margin: 1rem 0 1rem; }

.bd-pagehead {
    background: linear-gradient(160deg, var(--bd-ink), var(--bd-ink-soft));
    color: #fff;
    padding: clamp(2.25rem, 5vw, 3.5rem) 0;
}

.bd-pagehead h1 { font-size: clamp(2rem, 4vw, 2.8rem); margin: 0.9rem 0 0.5rem; }
.bd-pagehead p { color: rgba(255, 255, 255, 0.8); font-size: 1.1rem; max-width: 38rem; margin: 0; }

.bd-rule { margin-bottom: 2.25rem; }
.bd-rule h2 { display: flex; align-items: center; gap: 0.6rem; font-size: 1.4rem; margin-bottom: 0.6rem; }
.bd-rule h2 i { color: var(--bd-brand); }
.bd-rule p { font-size: 1.05rem; line-height: 1.65; color: #33404f; margin: 0; }
.bd-rule p + p { margin-top: 0.9rem; }
/* ul as well as ol: the legal pages have always had bare <ul>s in here, which inherited nothing and
   so read a size and colour apart from the prose around them. */
.bd-rule ol,
.bd-rule ul { font-size: 1.05rem; line-height: 1.65; color: #33404f; margin: 0.75rem 0 0; padding-left: 1.5rem; }
.bd-rule ol li,
.bd-rule ul li { margin-bottom: 0.35rem; }

/* ----- Dropdown menu (replaces <wa-dropdown>): native <details> + positioned panel ----- */
/* Web Awesome's native.css skins bare <details> as a white card (background + border); the menu
   trigger is just the summary, so strip that off the container -- the panel keeps its own surface. */
.bd-menu {
    position: relative;
    background: transparent;
    border: none;
    padding: 0;
}
.bd-menu > summary {
    list-style: none;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    margin: 0;
}
/* Hide the native disclosure triangle -- the trigger's icon/label is the affordance. */
.bd-menu[open] > summary { margin: 0; }
.bd-menu > summary::-webkit-details-marker,
.bd-menu > summary::marker { display: none; content: ""; }
.bd-menu__panel {
    position: absolute;
    z-index: 1000;
    margin-top: 0.4rem;
    min-width: 12rem;
    padding: 0.35rem;
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 0.6rem;
    box-shadow: 0 8px 24px rgba(16, 24, 40, 0.12);
}
.bd-menu--end .bd-menu__panel { right: 0; }
.bd-menu:not(.bd-menu--end) .bd-menu__panel { left: 0; }
.bd-menu__item {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    width: 100%;
    padding: 0.5rem 0.7rem;
    border: none;
    background: none;
    font: inherit;
    text-align: left;
    color: var(--bd-ink, #10220b);
    text-decoration: none;
    border-radius: 0.4rem;
    cursor: pointer;
}
.bd-menu__item:hover,
.bd-menu__item:focus-visible { background: var(--bd-brand-soft, #eaf3e0); color: var(--bd-brand-strong, #2c5614); }
.bd-menu__item i { width: 1.1em; text-align: center; opacity: 0.8; }
.bd-menu__divider { margin: 0.35rem 0.2rem; border: none; border-top: 1px solid #e5e7eb; }

/* ----- Statistics section ----- */
/* Shared by the stats hub, the season page and the team page, so these live here rather than in any one
   page's scoped sheet -- a scoped rule reaches only its own component and would leave the other pages
   silently unstyled (the .bd-article__cta lesson). Only genuinely page-specific values stay scoped. */

.bd-statgrid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    gap: 1rem;
    margin-bottom: 1.25rem;
}

.bd-stat { display: flex; flex-direction: column; gap: 0.15rem; padding: 1rem 1.25rem; }
.bd-stat__value { font-size: 2rem; font-weight: 800; line-height: 1; color: var(--bd-brand-strong); }
.bd-stat__value--pos { color: var(--bd-win, #16a34a); }
.bd-stat__value--neg { color: var(--bd-loss, #dc2626); }
.bd-stat__label { font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.03em; color: #6b7280; }

.bd-stats2 {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(22rem, 1fr));
    gap: 1rem;
    align-items: start;
}

.bd-statlist { padding: 1rem 1.25rem 0.75rem; }
.bd-statlist__head { display: flex; align-items: center; gap: 0.5rem; font-size: 1.1rem; margin: 0 0 0.6rem; }
.bd-statlist__head i { color: var(--bd-brand); }
.bd-statlist__empty { color: #6b7280; font-size: 0.9rem; margin: 0 0 0.5rem; }

/* list-style:none rather than ordinals: the ranking is already conveyed by order plus the value on the
   right, and a second number in the row reads as data. */
.bd-statlist__rows { list-style: none; margin: 0; padding: 0; }

.bd-statrow {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    padding: 0.45rem 0;
    border-top: 1px solid #eef0f4;
}
.bd-statrow:first-child { border-top: none; }

.bd-statrow__logo { flex: 0 0 auto; width: 2rem; height: 2rem; display: inline-flex; align-items: center; }
.bd-statrow__logo img { width: 100%; height: auto; }

/* Occupies the same slot as __logo, for a list whose rows are entries rather than teams and so have no
   crest to show. Fixed width, not intrinsic: a two-digit rank must not shift the names beside it. */
.bd-statrow__rank {
    flex: 0 0 auto;
    width: 2rem;
    text-align: center;
    font-variant-numeric: tabular-nums;
    font-weight: 800;
    color: #6b7280;
}

/* min-width:0 so a long opponent list truncates instead of pushing the number out of the card. */
.bd-statrow__body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; line-height: 1.25; }
.bd-statrow__name { font-weight: 700; text-decoration: none; color: var(--bd-ink); }
.bd-statrow__name:hover { color: var(--bd-brand-strong); text-decoration: underline; }

/* A withheld row: still a real rank and a real count, just no name to show. Muted and italic so it reads
   as an absence rather than as an entry actually called "Private entry". */
.bd-statrow__name--muted { font-style: italic; font-weight: 600; color: #6b7280; }
.bd-statrow__name--muted:hover { color: #6b7280; text-decoration: none; }

.bd-statrow__detail {
    font-size: 0.8rem;
    color: #6b7280;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.bd-statrow__detail a { color: #6b7280; }

.bd-statrow__tag {
    margin-left: 0.35rem;
    padding: 0.05rem 0.35rem;
    border-radius: 0.3rem;
    background: var(--bd-brand-soft);
    color: var(--bd-brand-strong);
    font-size: 0.7rem;
    font-weight: 700;
}

/* "You had this one." Sits inline after a row's name, deliberately quiet: it marks a row the reader has
   a stake in without competing with the number the list is actually ranked on. Shares the brand-soft
   background with __tag so the two read as the same class of annotation. */
.bd-yours {
    margin-left: 0.4rem;
    padding: 0.05rem 0.4rem;
    border-radius: 0.3rem;
    background: var(--bd-brand-soft);
    color: var(--bd-brand-strong);
    font-size: 0.7rem;
    font-weight: 700;
    white-space: nowrap;
    vertical-align: middle;
}
.bd-yours i { margin-right: 0.2rem; }

.bd-statrow__num {
    flex: 0 0 auto;
    font-variant-numeric: tabular-nums;
    font-weight: 800;
    font-size: 1.05rem;
}
.bd-statrow__num--pos { color: var(--bd-win, #16a34a); }
.bd-statrow__num--neg { color: var(--bd-loss, #dc2626); }

/* Section navigation cards on the stats hub. */
.bd-statnav {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: 1rem;
    margin-bottom: 1.5rem;
}

.bd-statnav__card {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    padding: 1.1rem 1.25rem;
    text-decoration: none;
    color: var(--bd-ink);
    transition: border-color .12s ease, transform .12s ease;
}
.bd-statnav__card:hover { color: var(--bd-ink); border-color: var(--bd-brand); transform: translateY(-1px); }
.bd-statnav__title { display: flex; align-items: center; gap: 0.5rem; font-weight: 700; font-size: 1.05rem; }
.bd-statnav__title i { color: var(--bd-brand); }
.bd-statnav__blurb { font-size: 0.85rem; color: #6b7280; }

/* ----- Floating toast (Components/Shared/Toast.razor) ----- */
/* Was duplicated in EntryWeek.razor.css and EntrySeason.razor.css, scoped to each -- and the two copies
   had already drifted: one had success/warning variants, the other a bare class with a hardcoded green
   icon. Global here because three pages now render it, and a scoped rule reaches only its own component,
   so a third caller would have been silently unstyled. */
.bd-toast {
    position: fixed;
    bottom: 1.5rem;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    align-items: center;
    gap: 0.5rem;
    max-width: min(92vw, 44rem);
    background: var(--bd-ink, #10220b);
    color: #fff;
    font-weight: 600;
    padding: 0.6rem 1.25rem;
    border-radius: 0.6rem;
    box-shadow: 0 10px 28px rgba(0, 0, 0, 0.3);
    z-index: 1000;
    animation: bd-toast-in 0.18s ease-out;
}

.bd-toast--success i { color: #7ed957; }
.bd-toast--warning { background: #7a4d05; }
.bd-toast--warning i { color: #ffce54; }
.bd-toast--info { background: #0b3a52; }
.bd-toast--info i { color: #7cc7ea; }

.bd-toast__text { min-width: 0; }

/* Actions live inside the toast for a sticky one (e.g. pending changes: Save / Discard), so the prompt
   and the way to answer it are the same object rather than the toast pointing at a button elsewhere. */
.bd-toast__actions { display: flex; align-items: center; gap: 0.4rem; margin-left: 0.35rem; }
.bd-toast__actions .btn { --bs-btn-padding-y: 0.2rem; --bs-btn-padding-x: 0.6rem; font-size: 0.85rem; }

@keyframes bd-toast-in {
    from { opacity: 0; transform: translate(-50%, 10px); }
    to { opacity: 1; transform: translate(-50%, 0); }
}

@media (prefers-reduced-motion: reduce) {
    .bd-toast { animation: none; }
}

/* ----- Draft matrix (Components/Shared/TeamDraftMatrix.razor) ----- */
/* Global rather than scoped: the component is shared, and scoped CSS belongs to the page that declares
   it, not to a component rendered inside several. */
.bd-matrix { padding: 1rem 1.25rem 0.5rem; margin-top: 1.25rem; scroll-margin-top: 5rem; }
.bd-matrix__head { margin-bottom: 0.5rem; }
.bd-matrix__head h2 { display: flex; align-items: center; gap: 0.5rem; font-size: 1.15rem; margin: 0; }
.bd-matrix__head h2 i { color: var(--bd-brand); }
.bd-matrix__sub { display: block; font-size: 0.85rem; color: #6b7280; margin-top: 0.15rem; }

.bd-matrix__table { margin-bottom: 0; }
.bd-matrix__table th,
.bd-matrix__table td { vertical-align: middle; }

/* Entry columns are narrow and repetitive, so the header carries the entry over its league, stacked. */
.bd-matrix__entry { min-width: 7.5rem; }
.bd-matrix__entry a { text-decoration: none; font-weight: 700; color: var(--bd-ink); }
.bd-matrix__entry a:hover { color: var(--bd-brand-strong); text-decoration: underline; }
.bd-matrix__league { display: block; font-size: 0.72rem; font-weight: 400; color: #6b7280; }

.bd-matrix__wk { white-space: nowrap; font-weight: 600; }
.bd-matrix__opp { display: block; font-size: 0.72rem; font-weight: 400; color: #6b7280; }

.bd-matrix__cell { text-align: center; }
.bd-matrix__row--locked .bd-matrix__wk { color: #9aa5b4; }
.bd-matrix__row--none { background: #f8fafc; }

/* The whole cell is the hit target, not just the 13px radio -- this is a grid of small controls and a
   near-miss either does nothing or, worse, hits the neighbour. */
.bd-matrix__pick {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.1rem;
    padding: 0.3rem 0.2rem;
    border-radius: 0.4rem;
    cursor: pointer;
}
.bd-matrix__pick:hover { background: var(--bd-brand-soft, #eaf3e0); }
.bd-matrix__pick input { cursor: pointer; }

/* A staged choice is visibly not-yet-saved, matching the sticky toast that says so. */
.bd-matrix__pick--staged { background: #fff7e6; box-shadow: inset 0 0 0 2px #d99a00; }

.bd-matrix__hint { font-size: 0.66rem; line-height: 1.15; color: #6b7280; text-align: center; }
.bd-matrix__hint--warn { color: #9a3412; font-weight: 700; }

.bd-matrix__na { color: #cbd5e1; }
.bd-matrix__spent { font-size: 0.72rem; color: #6b7280; white-space: nowrap; }
.bd-matrix__spent .res { margin-left: 0.2rem; }
.bd-matrix__locked-pick { color: var(--bd-win, #16a34a); }

/* ----- Week-by-week and single-week tables ----- */
.bd-weeks { padding: 0.25rem 0.5rem; }
.bd-weeks__wk { white-space: nowrap; font-weight: 600; }
.bd-weeks__wk a { text-decoration: none; }
.bd-weeks__wk a:hover { text-decoration: underline; }

/* A second line under the primary cell content: the denominator, the opponent, the pick count. Small and
   grey so the figure above it stays the thing you read first. */
.bd-weeks__sub { display: block; font-size: 0.72rem; font-weight: 400; color: #6b7280; }
.bd-weeks__sub a { color: #6b7280; }
.bd-weeks__num { font-variant-numeric: tabular-nums; font-weight: 800; color: var(--bd-win, #16a34a); }

/* "12/16 games" -- the total is context, not a headline, so it doesn't get the full size. */
.bd-stat__of { font-size: 1.1rem; font-weight: 600; color: #9aa5b4; }

/* ----- Team + logo link (schedule tables, stats tables) ----- */
/* Global because FOUR pages render this markup -- the team page's schedule plus all three stats tables. It
   lived in NflTeamSeason.razor.css, which meant the other three got no flex, no link colour and no width on
   the logo, so logos rendered at their natural 100px and upscaled on any HiDPI display. Scoped CSS reaches
   only its own component; this is the third time that has bitten in this section. */
.bd-teamsched__opp { display: inline-flex; align-items: center; gap: 0.45rem; text-decoration: none; color: var(--bd-ink); }
.bd-teamsched__opp:hover { color: var(--bd-brand-strong); text-decoration: underline; }
.bd-teamsched__opp img { width: 1.5rem; height: auto; flex: 0 0 auto; }

/* ----- Stacked per-week bars (season table) ----- */
/* One block per week laid end to end, so the bar's LENGTH is the season total. The two columns carry
   deliberately different ceilings -- see the note under the table -- so they're only ever compared down a
   column, never across. */
.bd-wbar { display: flex; align-items: center; gap: 0.5rem; }

.bd-wbar__track {
    flex: 1 1 auto;
    display: flex;
    height: 0.85rem;
    min-width: 4rem;
    background: #f1f3f6;
    border-radius: 0.15rem;
    overflow: hidden;
}

/* min-width so one pick is a visible sliver rather than rounding to nothing: the gap between nobody and one
   person is the interesting end of this chart. */
.bd-wbar__seg { display: block; height: 100%; min-width: 1px; }

/* Alternating shades mark the week boundaries. Only non-zero weeks render, so these alternate across weeks
   that actually had picks rather than across all 18 slots. */
.bd-wbar--for .bd-wbar__seg { background: #16a34a; }
.bd-wbar--for .bd-wbar__seg:nth-child(even) { background: #29c46a; }
.bd-wbar--against .bd-wbar__seg { background: #dc2626; }
.bd-wbar--against .bd-wbar__seg:nth-child(even) { background: #f04444; }

.bd-wbar__total {
    flex: 0 0 auto;
    font-size: 0.78rem;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    color: var(--bd-ink);
    white-space: nowrap;
}
.bd-wbar__of { font-weight: 400; color: #9aa5b4; }
