/* ────────────────────────────────────────────────────────────────────────────
   1. TOKENS
   ──────────────────────────────────────────────────────────────────────────── */
:root {
  /* Foundation values that do not vary by theme. The full semantic palette,
     spacing, type, shape, elevation, and motion contracts are defined once in
     the Precision in Motion token layer below. */
  --ds-font: 'Inter', 'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --ds-font-display: 'Bebas Neue', 'Arial Narrow', sans-serif;
  --ds-ease: cubic-bezier(0.2, 0.6, 0.2, 1);
  --ds-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ds-dur: var(--ds-motion-fast);
  --ds-dur-slow: var(--ds-motion-standard);
}

/* ────────────────────────────────────────────────────────────────────────────
   2. BASE — canvas, type, links, focus, motion
   ──────────────────────────────────────────────────────────────────────────── */
html { scroll-padding-top: calc(var(--ds-space-20) + var(--ds-space-4)); }

body {
  font-family: var(--ds-font);
  color: var(--ds-ink-700);
  background-color: var(--sport-page-bg);
  gap: 0;                       /* replace the 4rem flex gap with deliberate spacing */
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
main#mainContent { padding-top: var(--ds-space-5); }
footer.footer { margin-top: var(--ds-space-16); }

h1, h2, h3, h4, h5, h6 {
  font-family: var(--ds-font);
  color: var(--ds-ink-900);
  font-weight: 700;
  letter-spacing: -0.015em;
  line-height: 1.25;
  text-wrap: balance; /* no single-word widows on wrapped headings */
}
h1 { font-size: var(--ds-type-heading-1); }
/* Bebas Neue is the shared product display face on web, iOS, and Android.
   The deliberately stronger selector keeps route-local legacy heading weights
   from silently replacing the canonical display treatment. */
html body h1,
html body .page-title,
html body .auth-title,
html body .pim-title {
  font-family: var(--ds-font-display);
  font-weight: 400;
  letter-spacing: 0.025em;
  line-height: 1.12;
  text-transform: uppercase;
}
h2 { font-size: var(--ds-type-heading-2); }
h3 { font-size: var(--ds-type-heading-3); }
.lead { color: var(--ds-ink-600); font-size: var(--ds-type-body-large); font-weight: 400; }
small, .small { font-size: var(--ds-type-body-small); }
.text-muted { color: var(--ds-ink-500) !important; }

a { color: var(--ds-brand); }
a:hover { color: var(--ds-brand-strong); }

::selection { background: var(--ds-brand-ring); }

/* Focus — visible, on-brand, dark-safe. Secondary is dark in every theme. */
:focus-visible {
  outline: 2px solid var(--ds-brand);
  outline-offset: 2px;
  border-radius: 4px;
}
.navbar :focus-visible, .footer :focus-visible, .page-header :focus-visible {
  outline-color: var(--ds-accent);
}
/* …but navbar DROPDOWN panels are white — a white outline vanishes there. */
.navbar .dropdown-menu:not(.sport-picker-panel) :focus-visible {
  outline-color: var(--ds-brand);
}

/* Footer body copy: text-white-50 fails AA on several sport-primary footers
   (tennis composite ≈3.7:1). 78% white clears 4.5:1 on every theme. */
.footer a, .footer .text-white-50 { color: var(--ds-ink-500) !important; }
.footer a:hover { color: var(--ds-brand) !important; }

/* Global guard against mobile "zoom-out": if ANY element is briefly wider than
   the viewport (e.g. a flex/grid child during a width transition, like returning
   from a cross-origin OAuth redirect), a mobile browser shrinks the whole page
   to fit AND keeps it zoomed out. Clip horizontal overflow at the root so that
   can never happen. `clip` (not `hidden`) does NOT create a scroll container, so
   position:sticky headers keep working. Vertical scrolling is unaffected. */
html, body { overflow-x: hidden; overflow-x: clip; max-width: 100%; }

/* Responsive width utilities Bootstrap 5 doesn't ship (pages already use them). */
@media (min-width: 576px) { .w-sm-auto { width: auto !important; } }
@media (min-width: 768px) { .w-md-auto { width: auto !important; } }

/* LIVE indicator — one shared treatment (was 3 divergent per-page versions). */
.live-pill, .live-pill-final {
  display: inline-flex; align-items: center; gap: var(--ds-space-2);
  font-size: var(--ds-type-caption); font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  padding: var(--ds-space-1) var(--ds-space-2); border-radius: 999px;
}
.live-pill { background: var(--ds-error-surface); color: var(--ds-error); }
.live-pill .live-dot {
  width: var(--ds-space-2); height: var(--ds-space-2); border-radius: 50%; background: var(--ds-error);
  animation: ds-live-pulse 1.5s ease-in-out infinite;
}
.live-pill-final { background: var(--ds-surface-2); color: var(--ds-ink-600); }
@keyframes ds-live-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: .45; transform: scale(.85); }
}
/* Legacy pages animate `pulse` by name; alias it so inline styles work. */
@keyframes pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: .45; transform: scale(.85); }
}

/* ── Motion system ──────────────────────────────────────────────────────────
   One orchestrated moment per navigation: the page content arrives with a
   short fade-up. Plus two opt-in utilities for views: .ds-animate-in for a
   staggered card entrance (set --ds-anim-i per card), .ds-hover-lift for
   interactive cards. transform/opacity only (compositor-friendly); the
   reduced-motion kill-switch below flattens all of it. */
@keyframes ds-fade-up {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
/* fill-mode backwards, NOT both/forwards: a filling transform animation keeps a
   resolved matrix() on the element forever (even for the `none` end state), which
   makes <main> the containing block for every position:fixed overlay inside it —
   lightboxes/modals then anchor to the page instead of the viewport. The end
   state equals the base style, so nothing visual changes. */
main#mainContent { animation: ds-fade-up var(--ds-dur-slow) var(--ds-ease-out) backwards; }
.ds-animate-in {
  animation: ds-fade-up var(--ds-dur-slow) var(--ds-ease-out) both;
  animation-delay: calc(var(--ds-anim-i, 0) * 45ms);
}
.ds-hover-lift {
  transition: transform var(--ds-dur) var(--ds-ease), box-shadow var(--ds-dur) var(--ds-ease);
}
.ds-hover-lift:hover { transform: translateY(-2px); box-shadow: var(--ds-shadow-md); }

/* The navbar chrome still resolved Roboto via the legacy --font-heading in
   site.css (a loose file zip-deploy can't update) — pin it to the DS font so
   the Roboto request can be dropped from the Google Fonts URL entirely. */
.navbar-brand, .navbar .nav-link { font-family: var(--ds-font); }

/* Respect reduced-motion everywhere */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* Print styles for the legal/doc pages (was copy-pasted per view). */
@media print {
  .page-header { background: none !important; box-shadow: none; padding: 0 0 var(--ds-space-4); animation: none; }
  .page-header::before, .page-header::after { display: none; }
  .page-header h1, .page-header p { color: var(--ds-text-primary) !important; }
  .legal-toc { display: none; }
  .ds-doc { border: none; box-shadow: none; padding: 0; }
}

/* Subtle, consistent scrollbars (WebKit) */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: var(--ds-border-strong); border-radius: var(--ds-radius-sm); border: 2px solid transparent; background-clip: content-box; }
::-webkit-scrollbar-thumb:hover { background-color: var(--ds-border-strong); background-color: color-mix(in srgb, var(--ds-border-strong) 82%, var(--ds-ink-500)); }
::-webkit-scrollbar-track { background: transparent; }

/* ────────────────────────────────────────────────────────────────────────────
   3. BRAND-UNIFIED BOOTSTRAP UTILITIES
   text-primary / bg-primary etc. otherwise render Bootstrap blue. Unify them
   onto the shared Precision in Motion brand palette.
   ──────────────────────────────────────────────────────────────────────────── */
.text-primary { color: var(--ds-brand) !important; }
.bg-primary { background-color: var(--ds-brand) !important; }
.border-primary { border-color: var(--ds-brand) !important; }
.link-primary { color: var(--ds-brand) !important; }
.btn-link { color: var(--ds-brand); text-decoration: none; }
.btn-link:hover { color: var(--ds-brand-strong); }
.spinner-border.text-primary { color: var(--ds-brand) !important; }
.form-check-input:checked { background-color: var(--ds-brand); border-color: var(--ds-brand); }
.form-check-input:focus { border-color: var(--ds-brand); box-shadow: 0 0 0 3px var(--ds-brand-ring); }
.nav-pills .nav-link.active { background-color: var(--ds-brand); }
.progress-bar { background-color: var(--ds-brand); }
/* Bootstrap 5.1 ships no .fw-semibold (it arrived in 5.3); ~97 "primary text"
   spans across 32 views rendered at body weight. Defined here — a compiled
   partial — so it survives the loose-static-file deploy gotcha. */
.fw-semibold { font-weight: 600 !important; }

/* ────────────────────────────────────────────────────────────────────────────
   4. BUTTONS — sentence case, consistent heights, calm depth
   ──────────────────────────────────────────────────────────────────────────── */
.btn {
  font-family: var(--ds-font);
  font-weight: 600;
  text-transform: none;
  letter-spacing: 0;
  font-size: var(--ds-type-button);
  line-height: 1.25;
  padding: var(--ds-space-2) var(--ds-space-5);
  min-width: 44px;
  min-height: 44px;
  border-radius: var(--ds-radius-md);
  border: 1px solid transparent;
  /* Inline-flex + gap gives every button the SAME icon↔label spacing whether
     the view wrote an icon margin, a bare space, or nothing — and vertically
     centers Font Awesome glyphs that otherwise sit off-baseline. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--ds-space-2);
  transition: transform var(--ds-dur) var(--ds-ease), box-shadow var(--ds-dur) var(--ds-ease),
              background-color var(--ds-dur) var(--ds-ease), border-color var(--ds-dur) var(--ds-ease),
              color var(--ds-dur) var(--ds-ease);
}
/* The flex gap replaces per-view icon margins (me-1/me-2/ms-2) — zero them so
   buttons that carried them don't render a double-wide gap. Direct children
   only; icon-only buttons are unaffected (gap needs two items to exist). */
.btn > :where(i[class*="fa-"], .spinner-border, .spinner-grow) {
  margin-left: 0 !important;
  margin-right: 0 !important;
}
.btn:active { transform: translateY(0) scale(0.985); }
.btn:disabled, .btn.disabled { transform: none; box-shadow: none; opacity: 0.55; }
.btn:focus-visible { outline: 2px solid var(--ds-brand); outline-offset: 2px; box-shadow: none; }

.btn-sm { min-height: 44px; padding: var(--ds-space-2) var(--ds-space-3); font-size: var(--ds-type-label); border-radius: var(--ds-radius-sm); gap: var(--ds-space-2); }
.btn-lg { padding: var(--ds-space-3) var(--ds-space-6); font-size: var(--ds-type-body); border-radius: var(--ds-radius-lg); gap: var(--ds-space-2); }

.btn-primary {
  background: var(--ds-brand);
  border-color: var(--ds-brand);
  color: var(--ds-on-accent);
  box-shadow: var(--ds-shadow-xs), inset 0 1px 0 transparent;
  box-shadow: var(--ds-shadow-xs), inset 0 1px 0 color-mix(in srgb, var(--ds-text-inverse) 8%, transparent);
}
.btn-primary:hover, .btn-primary:focus {
  background: var(--ds-brand-strong);
  border-color: var(--ds-brand-strong);
  color: var(--ds-on-accent);
  transform: translateY(-1px);
  box-shadow: var(--ds-shadow-md);
}
.btn-primary:active { background: var(--ds-brand-pressed); border-color: var(--ds-brand-pressed); color: var(--ds-on-accent); }

.btn-secondary {
  background: var(--ds-surface);
  border-color: var(--ds-border-strong);
  color: var(--ds-ink-700);
  box-shadow: var(--ds-shadow-xs);
}
.btn-secondary:hover, .btn-secondary:focus {
  background: var(--ds-surface-2);
  border-color: var(--ds-border-strong);
  color: var(--ds-ink-900);
  transform: translateY(-1px);
}
.btn-secondary:active { background: var(--ds-surface-2); border-color: var(--ds-border-strong); color: var(--ds-ink-900); }

.btn-outline-primary {
  color: var(--ds-brand);
  border-color: var(--ds-border-strong);
  border-color: color-mix(in srgb, var(--sport-secondary) 45%, var(--ds-border-strong));
  background: transparent;
}
.btn-outline-primary:hover, .btn-outline-primary:focus {
  background: var(--ds-brand-soft);
  border-color: var(--ds-brand);
  color: var(--ds-brand-strong);
  transform: translateY(-1px);
}
.btn-outline-primary:active { background: var(--ds-brand-soft); border-color: var(--ds-brand); color: var(--ds-brand-strong); }

.btn-outline-secondary {
  color: var(--ds-ink-600);
  border-color: var(--ds-border-strong);
  background: transparent;
}
.btn-outline-secondary:hover, .btn-outline-secondary:focus {
  background: var(--ds-surface-2);
  border-color: var(--ds-border-strong);
  color: var(--ds-ink-900);
  transform: translateY(-1px);
}
.btn-outline-secondary:active { background: var(--ds-surface-2); color: var(--ds-ink-900); }

.btn-outline-danger { border-color: var(--ds-border-strong); border-color: color-mix(in srgb, var(--ds-error) 45%, var(--ds-border-strong)); }
.btn-outline-danger:hover { transform: translateY(-1px); }
.btn-danger, .btn-success, .btn-warning, .btn-info, .btn-dark, .btn-light {
  box-shadow: var(--ds-shadow-xs);
}
.btn-danger:hover, .btn-success:hover, .btn-warning:hover, .btn-info:hover, .btn-dark:hover, .btn-light:hover {
  transform: translateY(-1px);
  box-shadow: var(--ds-shadow-md);
}

.btn-accent {
  background: var(--sport-accent);
  border-color: var(--sport-accent);
  color: var(--sport-primary);   /* accent can be light — never white text */
  box-shadow: var(--ds-shadow-xs);
}
.btn-accent:hover {
  background: var(--sport-accent);
  background: color-mix(in srgb, var(--sport-accent) 88%, black 12%);
  border-color: var(--sport-accent);
  border-color: color-mix(in srgb, var(--sport-accent) 88%, black 12%);
  color: var(--sport-primary);
  transform: translateY(-1px);
  box-shadow: var(--ds-shadow-md);
}
.btn-gradient {
  background: linear-gradient(135deg, var(--sport-secondary), var(--sport-primary));
  border: none;
  border-radius: var(--ds-radius-md);
  color: var(--ds-on-sport);
  font-weight: 600;
}
.btn-gradient:hover { transform: translateY(-1px); box-shadow: var(--ds-shadow-md); color: var(--ds-on-sport); }

/* ────────────────────────────────────────────────────────────────────────────
   5. CARDS
   ──────────────────────────────────────────────────────────────────────────── */
.card {
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-lg);
  box-shadow: var(--ds-shadow-xs);
  background: var(--ds-surface);
}
.card > .card-header {
  background: var(--ds-surface);
  border-bottom: 1px solid var(--ds-border);
  padding: var(--ds-space-4) var(--ds-space-5);
  font-weight: 600;
  color: var(--ds-ink-900);
  border-top-left-radius: var(--ds-radius-lg) !important;
  border-top-right-radius: var(--ds-radius-lg) !important;
}
.card > .card-footer {
  background: var(--ds-surface);
  border-top: 1px solid var(--ds-border);
  border-bottom-left-radius: var(--ds-radius-lg) !important;
  border-bottom-right-radius: var(--ds-radius-lg) !important;
}
.content-card {
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-lg);
  box-shadow: var(--ds-shadow-xs);
  background: var(--ds-surface);
}
/* Elevation on hover ONLY for explicitly interactive cards */
.card-interactive, a > .card, a.card {
  transition: transform var(--ds-dur) var(--ds-ease), box-shadow var(--ds-dur) var(--ds-ease), border-color var(--ds-dur) var(--ds-ease);
}
.card-interactive:hover, a > .card:hover, a.card:hover {
  transform: translateY(-2px);
  box-shadow: var(--ds-shadow-md);
  border-color: var(--ds-border-strong);
}

/* ────────────────────────────────────────────────────────────────────────────
   6. PAGE HEADER — keep the sport-gradient identity, refine the execution
   ──────────────────────────────────────────────────────────────────────────── */
.page-header {
  background: var(--sport-hero-gradient, linear-gradient(135deg, var(--sport-secondary) 0%, var(--sport-primary) 100%));
  border-radius: var(--ds-radius-xl);
  padding: var(--ds-space-6) var(--ds-space-8);
  margin-bottom: var(--ds-space-6);
  box-shadow: var(--ds-shadow-sm);
  animation: none;
}
.page-header::before {
  top: auto; right: -10%; bottom: -60%;
  width: 340px; height: 340px;
  opacity: 0.55;
}
.page-header::after {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: 2px;
  background: linear-gradient(90deg, var(--sport-accent), transparent 60%);
  opacity: 0.85;
}
.page-header h1, .page-header .page-title {
  font-size: var(--ds-type-heading-2);
  font-weight: 700;
  letter-spacing: -0.015em;
  margin-bottom: var(--ds-space-1);
}
.page-header p, .page-header .page-subtitle {
  color: var(--ds-on-sport);
  font-size: var(--ds-type-body);
}
.page-header .header-btn, .page-header .back-btn {
  border-radius: var(--ds-radius-md);
  font-size: var(--ds-type-body-small);
  font-weight: 600;
  padding: var(--ds-space-2) var(--ds-space-4);
  transition: background var(--ds-dur) var(--ds-ease), transform var(--ds-dur) var(--ds-ease);
}
.page-header .header-btn:hover, .page-header .back-btn:hover { transform: translateY(-1px); }
@media (max-width: 576px) {
  .page-header { padding: var(--ds-space-5); border-radius: var(--ds-radius-lg); }
  .page-header h1, .page-header .page-title { font-size: var(--ds-type-heading-3); }
}

/* ────────────────────────────────────────────────────────────────────────────
   7. FORMS — 44px targets, calm borders, on-brand focus, clear validation
   ──────────────────────────────────────────────────────────────────────────── */
.form-label {
  font-size: var(--ds-type-label);
  font-weight: 600;
  color: var(--ds-ink-700);
  margin-bottom: var(--ds-space-2);
}
.form-control, .form-select {
  font-family: var(--ds-font);
  font-size: var(--ds-type-body);
  color: var(--ds-ink-900);
  /* WebKit/Blink paint input glyphs from -webkit-text-fill-color, NOT from
     `color`, and silently prefer it when both are present — so a UA or autofill
     fill left the typed text dark-on-dark in dark mode even though the computed
     `color` read correctly. Five views (Chat, Friends x2, Coaching, Admin
     ratings) had each patched this locally with an !important pair; pinning it
     here, to the SAME token `color` already uses, fixes every input at once and
     stops the next one regressing. Token-based, so light mode is unchanged. */
  -webkit-text-fill-color: var(--ds-ink-900);
  background-color: var(--ds-surface);
  border: 1px solid var(--ds-border-strong);
  border-radius: var(--ds-radius-md);
  padding: var(--ds-space-2) var(--ds-space-3);
  min-height: 44px;
  transition: border-color var(--ds-dur) var(--ds-ease), box-shadow var(--ds-dur) var(--ds-ease);
}
.form-control:hover:not(:focus):not(:disabled), .form-select:hover:not(:focus):not(:disabled) {
  border-color: var(--ds-border-strong);
}
.form-control:focus, .form-select:focus {
  border-color: var(--ds-brand);
  box-shadow: 0 0 0 3px var(--ds-brand-ring);
  outline: none;
}
.form-control::placeholder { color: var(--ds-ink-400); }
.form-control:disabled, .form-select:disabled { background-color: var(--ds-surface-2); color: var(--ds-ink-500); -webkit-text-fill-color: var(--ds-ink-500); }
.form-control-sm { min-height: 44px; padding: var(--ds-space-2) var(--ds-space-3); border-radius: var(--ds-radius-sm); }
.form-text { color: var(--ds-ink-500); font-size: var(--ds-type-label); }
textarea.form-control { min-height: auto; }

/* File pickers: theme the native "Choose File" button (Bootstrap leaves it a
   stark near-white block that clashes hard in dark mode). The filename text
   inherits the input's ink automatically. */
.form-control[type="file"] { color: var(--ds-ink-600); -webkit-text-fill-color: var(--ds-ink-600); }
.form-control[type="file"]::file-selector-button {
  background: var(--ds-surface-2);
  border: 1px solid var(--ds-border-strong);
  color: var(--ds-ink-700);
  font-family: var(--ds-font);
  font-size: var(--ds-type-body-small);
  font-weight: 600;
  border-radius: var(--ds-radius-sm);
  padding: var(--ds-space-2) var(--ds-space-3);
  margin-right: var(--ds-space-3);
  cursor: pointer;
  transition: background-color var(--ds-dur) var(--ds-ease), color var(--ds-dur) var(--ds-ease);
}
.form-control[type="file"]:hover:not(:disabled)::file-selector-button {
  background: var(--ds-surface-3);
  color: var(--ds-ink-900);
}
.input-group-text {
  background: var(--ds-surface-2);
  border: 1px solid var(--ds-border-strong);
  color: var(--ds-ink-500);
  border-radius: var(--ds-radius-md);
  font-size: var(--ds-type-body-small);
}

/* jQuery-validate + ModelState error styling */
.input-validation-error, .form-control.is-invalid, .form-select.is-invalid {
  border-color: var(--ds-error) !important;
}
.input-validation-error:focus, .form-control.is-invalid:focus, .form-select.is-invalid:focus {
  box-shadow: 0 0 0 3px transparent !important;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--ds-error) 18%, transparent) !important;
}
.field-validation-error, .text-danger > .field-validation-error {
  display: inline-block;
  font-size: var(--ds-type-label);
  font-weight: 500;
  margin-top: var(--ds-space-1);
}
.validation-summary-errors {
  background: var(--ds-error-surface);
  border: 1px solid var(--ds-error-border);
  border-radius: var(--ds-radius-md);
  padding: var(--ds-space-3) var(--ds-space-4);
  font-size: var(--ds-type-body-small);
  margin-bottom: var(--ds-space-4);
}
.validation-summary-errors ul { margin: 0; padding-left: var(--ds-space-5); }

/* ────────────────────────────────────────────────────────────────────────────
   8. TABLES
   ──────────────────────────────────────────────────────────────────────────── */
.table { color: var(--ds-ink-700); }
.table thead th, .table > :not(caption) > * > th {
  font-size: var(--ds-type-caption);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ds-ink-500);
  background: var(--ds-surface-2);
  border-bottom: 1px solid var(--ds-border);
  padding: var(--ds-space-3) var(--ds-space-4);
  white-space: nowrap;
}
.table tbody td { padding: var(--ds-space-3) var(--ds-space-4); border-color: var(--ds-border-subtle); vertical-align: middle; }
.table-hover tbody tr:hover { background: var(--sport-table-hover); }
.table-striped > tbody > tr:nth-of-type(odd) > * { background-color: var(--ds-surface-2); box-shadow: none; }
.card .table-responsive { border-radius: 0 0 var(--ds-radius-lg) var(--ds-radius-lg); overflow: hidden; }

/* ────────────────────────────────────────────────────────────────────────────
   9. BADGES / CHIPS
   ──────────────────────────────────────────────────────────────────────────── */
.badge {
  font-family: var(--ds-font);
  font-weight: 600;
  font-size: var(--ds-type-caption);
  letter-spacing: 0.01em;
  padding: var(--ds-space-1) var(--ds-space-2);
  border-radius: var(--ds-radius-xs);
}
.badge.rounded-pill { border-radius: 999px; }
/* Soft badge variants — subdued fills with readable ink */
.badge-soft-success { background: var(--ds-success-surface); color: var(--ds-success); border: 1px solid var(--ds-success-border); }
.badge-soft-danger  { background: var(--ds-error-surface); color: var(--ds-error); border: 1px solid var(--ds-error-border); }
.badge-soft-warning { background: var(--ds-warning-surface); color: var(--ds-warning); border: 1px solid var(--ds-warning-border); }
.badge-soft-info    { background: var(--ds-info-surface); color: var(--ds-info); border: 1px solid var(--ds-info-border); }
.badge-soft-neutral { background: var(--ds-surface-2); color: var(--ds-ink-700); border: 1px solid var(--ds-border); }
.badge-soft-brand   { background: var(--ds-brand-soft); color: var(--ds-brand-strong); border: 1px solid transparent; border: 1px solid color-mix(in srgb, var(--sport-secondary) 25%, transparent); }

/* ────────────────────────────────────────────────────────────────────────────
   10. DROPDOWNS, TABS, PILLS, LIST GROUPS, PAGINATION, BREADCRUMBS
   ──────────────────────────────────────────────────────────────────────────── */
.dropdown-menu {
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-lg);
  box-shadow: var(--ds-shadow-lg);
  padding: var(--ds-space-2);
  font-size: var(--ds-type-body-small);
}
.dropdown-item {
  border-radius: var(--ds-radius-sm);
  padding: var(--ds-space-2) var(--ds-space-3);
  font-weight: 500;
  color: var(--ds-ink-700);
}
.dropdown-item:hover, .dropdown-item:focus { background: var(--ds-surface-2); color: var(--ds-ink-900); }
.dropdown-item.active { background: var(--ds-brand-soft); color: var(--ds-brand-strong); }
.dropdown-divider { border-color: var(--ds-border); margin: var(--ds-space-2) var(--ds-space-1); }

.nav-tabs { border-bottom: 1px solid var(--ds-border); gap: var(--ds-space-1); }
/* !important + extra specificity: the legacy site.css ships a BARE
   `.nav-link { color: rgba(255,255,255,.85) !important }` (navbar intent,
   global reach) that turns content tabs white-on-white — and zip-deploy
   can't update that loose file, so this compiled layer must out-rank it. */
.nav-tabs .nav-link {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  border: none;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  color: var(--ds-ink-500) !important;
  font-family: inherit;
  font-weight: 600;
  font-size: var(--ds-type-body-small);
  padding: var(--ds-space-2) var(--ds-space-3) !important;
  margin-bottom: 0;
}
.nav-tabs .nav-link:hover { color: var(--ds-ink-900) !important; border-color: var(--ds-border-strong); }
.nav-tabs .nav-link.active { color: var(--ds-brand) !important; border-color: var(--ds-brand); background: transparent; }

.nav-pills .nav-link { min-height: 44px; display: inline-flex; align-items: center; border-radius: var(--ds-radius-md); font-weight: 600; font-size: var(--ds-type-body-small); color: var(--ds-ink-600); }
.nav-pills .nav-link:not(.active) { color: var(--ds-ink-600) !important; } /* same site.css bleed */
.nav-pills .nav-link:not(.active):hover { background: var(--ds-surface-2); color: var(--ds-ink-900) !important; }

.list-group { border-radius: var(--ds-radius-lg); }
.list-group-item { border-color: var(--ds-border); padding: var(--ds-space-3) var(--ds-space-5); color: var(--ds-ink-700); }
.list-group-item-action:hover { background: var(--ds-surface-2); }

.pagination { gap: var(--ds-space-1); }
.page-link {
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-sm) !important;
  color: var(--ds-ink-600);
  font-weight: 500;
  font-size: var(--ds-type-body-small);
  padding: var(--ds-space-2) var(--ds-space-3);
}
.page-link:hover { background: var(--ds-surface-2); color: var(--ds-ink-900); border-color: var(--ds-border-strong); }
.page-item.active .page-link { background: var(--ds-accent); border-color: var(--ds-accent); color: var(--ds-on-accent); }

.breadcrumb { font-size: var(--ds-type-label); margin-bottom: var(--ds-space-3); }
.breadcrumb-item a { color: var(--ds-ink-500); font-weight: 500; }
.breadcrumb-item a:hover { color: var(--ds-brand); }
.breadcrumb-item.active { color: var(--ds-ink-700); font-weight: 600; }

/* ────────────────────────────────────────────────────────────────────────────
   11. ALERTS + MODALS + TOASTS
   ──────────────────────────────────────────────────────────────────────────── */
.alert {
  border: 1px solid transparent;
  border-radius: var(--ds-radius-md);
  font-size: var(--ds-type-body-small);
  padding: var(--ds-space-3) var(--ds-space-5);
}
.alert-success { background: var(--ds-success-surface); border-color: var(--ds-success-border); color: var(--ds-success); }
.alert-danger  { background: var(--ds-error-surface); border-color: var(--ds-error-border); color: var(--ds-error); }
.alert-warning { background: var(--ds-warning-surface); border-color: var(--ds-warning-border); color: var(--ds-warning); }
.alert-info    { background: var(--ds-info-surface); border-color: var(--ds-info-border); color: var(--ds-info); }

.modal-content {
  border: none;
  border-radius: var(--ds-radius-xl);
  box-shadow: var(--ds-shadow-xl);
}
.modal-backdrop.show { opacity: 0.4; }

.custom-toast {
  border-radius: var(--ds-radius-lg);
  box-shadow: var(--ds-shadow-lg);
  font-size: var(--ds-type-body-small);
  font-weight: 500;
}
/* Toast stack: the polite (role=status) and assertive (role=alert) containers are
   siblings, so the STACK takes the fixed corner position and the containers flow
   inside it — two fixed containers at the same corner would overlap. */
.toast-stack {
  position: fixed;
  top: var(--ds-space-5);
  right: var(--ds-space-5);
  z-index: 9999;
  display: flex;
  flex-direction: column;
  gap: var(--ds-space-3);
  pointer-events: none;
}
/* Both live regions stay rendered (never display:none) so screen readers have
   registered them before the first toast is inserted. */
.toast-stack .toast-container { position: static; top: auto; right: auto; left: auto; bottom: auto; }

/* ────────────────────────────────────────────────────────────────────────────
   12. NAVBAR — sticky Precision in Motion product shell
   ──────────────────────────────────────────────────────────────────────────── */
/* Scoped to the layout shell's navbar header only — content pages legitimately
   use semantic <header> elements (dashboard hero, bracket banner) which must
   never inherit sticky overlay behavior. */
header.site-shell-header {
  position: sticky;
  top: 0;
  z-index: 1030;
}
.navbar {
  background-color: var(--pim-nav);
  -webkit-backdrop-filter: saturate(160%) blur(10px);
  backdrop-filter: saturate(160%) blur(10px);
  border-bottom: 1px solid var(--ds-border);
  box-shadow: var(--ds-shadow-sm);
  padding: var(--ds-space-2) 0;
}

/* Raw feature controls still receive the same minimum target contract even
   when a legacy view has not yet adopted Bootstrap's .btn/.form-control. */
button {
  min-width: 44px;
  min-height: 44px;
}
input:is([type="text"], [type="search"], [type="email"], [type="password"], [type="tel"], [type="url"], [type="number"], [type="date"], [type="time"], [type="datetime-local"]) {
  min-height: 44px;
}
input[type="checkbox"] + label,
input[type="radio"] + label,
label:has(> input[type="checkbox"]),
label:has(> input[type="radio"]) {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}
.navbar .nav-link {
  color: var(--ds-ink-600);
  font-size: var(--ds-type-body-small);
  font-weight: 500;
  padding: var(--ds-space-2) var(--ds-space-3);
  min-height: 44px;
  display: flex;
  align-items: center;
  border-radius: var(--ds-radius-sm);
  transition: color var(--ds-dur) var(--ds-ease), background-color var(--ds-dur) var(--ds-ease);
}
.navbar .nav-link:hover { color: var(--ds-ink-900); background: var(--ds-surface-2); }
.navbar .nav-link.active {
  color: var(--ds-brand);
  background: var(--ds-brand-soft);
  font-weight: 600;
}
.navbar .brand-text { font-weight: 800; letter-spacing: -0.01em; }
.navbar .dropdown-menu { margin-top: var(--ds-space-2); }
/* Collapse panel: comfortable 44px rows without dead air. Covers the WHOLE
   hamburger range — _Layout keeps the toggler until 1850px, not Bootstrap's
   1200/1400. (Rows previously stacked link padding on top of stray item
   padding and hit ~67px, which read as huge gaps in the drawer.) */
@media (max-width: 1199.98px) {
  /* Phones/tablets only: a sticky header plus a tall open drawer eats the
     viewport, so let it scroll away. Desktops (including the 1200-1849px
     forced-hamburger band) keep the sticky header. */
  header.site-shell-header { position: static; }
}
@media (max-width: 1849.98px) {
  .navbar-collapse {
    padding: var(--ds-space-2) var(--ds-space-1);
    max-height: calc(100vh - 80px);
    overflow-y: auto;
  }
  .navbar .navbar-nav .nav-item { padding: 0 !important; margin: 0 !important; }
  .navbar .navbar-nav .nav-link {
    padding: var(--ds-space-2) var(--ds-space-3) !important;
    min-height: 44px;
    font-size: var(--ds-type-body);
  }
  .sport-selector-wrapper { margin: var(--ds-space-2) 0; }
}
.navbar-toggler { min-width: 44px; min-height: 44px; border: 1px solid var(--ds-border-strong); border-radius: var(--ds-radius-sm); padding: var(--ds-space-2); }
.navbar-toggler:focus { box-shadow: 0 0 0 3px var(--ds-focus-ring); }

/* Sport context bar: slimmer, quieter */
.sport-context-bar { font-size: var(--ds-type-label); }

/* ────────────────────────────────────────────────────────────────────────────
   13. FOOTER
   ──────────────────────────────────────────────────────────────────────────── */
.footer {
  background: var(--ds-surface) !important;
  border-top: 1px solid var(--ds-border);
}
/* Section headings render as <h2 class="footer-heading"> (h5→h2 in an a11y
   pass), so the old `.footer h5` white never applied — headings inherited the
   dark body ink and went near-invisible. Style the real element as a light
   uppercase eyebrow (AA on every sport-primary footer). */
.footer .footer-heading {
  color: var(--ds-ink-900);
  font-size: var(--ds-type-caption);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.footer a { color: var(--ds-ink-500); transition: color var(--ds-dur) var(--ds-ease), transform var(--ds-dur) var(--ds-ease); }
.footer a.hover-light:hover { color: var(--ds-brand) !important; }
.footer .footer-links a:hover, .footer .footer-bottom a:hover { transform: translateX(2px); display: inline-block; }

/* Brand column */
.footer-logo { border-radius: var(--ds-radius-sm); flex-shrink: 0; box-shadow: var(--ds-shadow-sm); }
.footer-wordmark { color: var(--ds-ink-900); font-weight: 800; font-size: var(--ds-type-heading-4); letter-spacing: -0.01em; }
.footer-tagline, .footer-apps { color: var(--ds-ink-500); line-height: 1.6; }
.footer-tagline { max-width: 34ch; }

/* Sport pills — subtle rounded chips that wrap */
.footer-pills { display: flex; flex-wrap: wrap; gap: var(--ds-space-2); }
.footer-pill {
  display: inline-flex;
  align-items: center;
  font-size: var(--ds-type-caption);
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--ds-ink-600);
  background: var(--ds-surface-2);
  border: 1px solid var(--ds-border);
  border-radius: 999px;
  padding: var(--ds-space-1) var(--ds-space-2);
}
/* Footer pills are real controls (they submit the sport switcher's POST), so
   reset the button UA styles and give them hover/focus/active states. */
.footer-pill--link {
  font-family: inherit;
  line-height: inherit;
  cursor: pointer;
  min-height: 32px;
  padding-inline: var(--ds-space-3);
  transition: border-color var(--ds-motion-fast) var(--ds-ease), color var(--ds-motion-fast) var(--ds-ease);
}
.footer-pill--link:hover, .footer-pill--link:focus-visible, .footer-pill--active { border-color: var(--ds-brand); }
.footer-pill--link:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--ds-focus-ring); }

.footer .social-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: var(--ds-radius-md);
  background: var(--ds-surface-2);
  border: 1px solid var(--ds-border);
  transition: background var(--ds-dur) var(--ds-ease), transform var(--ds-dur) var(--ds-ease), border-color var(--ds-dur) var(--ds-ease);
}
.footer .social-link:hover {
  background: var(--ds-brand-soft);
  border-color: var(--ds-border);
  border-color: color-mix(in srgb, var(--ds-accent) 45%, var(--ds-border));
  transform: translateY(-2px);
}
.footer .footer-hr { border-color: var(--ds-border); opacity: 1; margin: var(--ds-space-10) 0 var(--ds-space-5); }
.footer .footer-bottom { color: var(--ds-ink-500); }

/* ────────────────────────────────────────────────────────────────────────────
   14. DS COMPONENTS — empty states, stat cards, section headers, icon tiles
   ──────────────────────────────────────────────────────────────────────────── */
.ds-empty { text-align: center; padding: var(--ds-space-16) var(--ds-space-6); }
.ds-empty-icon {
  width: var(--ds-space-16); height: var(--ds-space-16);
  border-radius: var(--ds-radius-xl);
  background: var(--sport-feature-bg);
  color: var(--ds-brand);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: var(--ds-type-heading-2);
  margin-bottom: var(--ds-space-4);
}
.ds-empty-title { font-weight: 700; font-size: var(--ds-type-title); color: var(--ds-ink-900); margin-bottom: var(--ds-space-2); }
.ds-empty-sub { color: var(--ds-ink-500); font-size: var(--ds-type-body); max-width: 420px; margin: 0 auto var(--ds-space-5); }

.ds-stat {
  background: var(--ds-surface);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-lg);
  padding: var(--ds-space-5);
  height: 100%;
  box-shadow: var(--ds-shadow-xs);
}
.ds-stat-label {
  font-size: var(--ds-type-caption); font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--ds-ink-500);
  margin-bottom: var(--ds-space-2);
}
.ds-stat-value {
  font-size: var(--ds-type-heading-1); font-weight: 700; line-height: 1.15;
  color: var(--ds-ink-900);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}
.ds-stat-sub { font-size: var(--ds-type-label); color: var(--ds-ink-500); margin-top: var(--ds-space-1); }
.ds-stat-icon {
  width: var(--ds-space-10); height: var(--ds-space-10);
  border-radius: var(--ds-radius-md);
  background: var(--sport-feature-bg);
  color: var(--ds-brand);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: var(--ds-type-body);
}

.ds-section-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--ds-space-4);
  margin-bottom: var(--ds-space-4);
}
.ds-section-title { font-size: var(--ds-type-title); font-weight: 700; letter-spacing: -0.01em; margin: 0; color: var(--ds-ink-900); }
.ds-section-sub { font-size: var(--ds-type-body-small); color: var(--ds-ink-500); margin: var(--ds-space-1) 0 0; }

.ds-icon-tile {
  width: 44px; height: 44px;
  border-radius: var(--ds-radius-md);
  background: var(--sport-icon-gradient);
  color: var(--ds-on-sport);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: var(--ds-type-heading-4);
  flex-shrink: 0;
}

/* Avatars */
.ds-avatar { border-radius: 50%; object-fit: cover; background: var(--ds-surface-2); border: 1px solid var(--ds-border); }

/* ────────────────────────────────────────────────────────────────────────────
   15. UTILITIES
   ──────────────────────────────────────────────────────────────────────────── */
.ds-tnum { font-variant-numeric: tabular-nums; }
.ds-measure { max-width: 68ch; }
.hover-lift { transition: transform var(--ds-dur) var(--ds-ease), box-shadow var(--ds-dur) var(--ds-ease); }
.hover-lift:hover { transform: translateY(-2px); box-shadow: var(--ds-shadow-md); }
.ds-divider { border: 0; border-top: 1px solid var(--ds-border); margin: var(--ds-space-6) 0; }
.ds-truncate-2 {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
[id] { scroll-margin-top: calc(var(--ds-space-20) + var(--ds-space-4)); }

/* Legal / long-form document pattern */
.ds-doc { background: var(--ds-surface); border: 1px solid var(--ds-border); border-radius: var(--ds-radius-xl); padding: var(--ds-space-10); }
.ds-doc h2 { font-size: var(--ds-type-heading-3); margin-top: var(--ds-space-8); margin-bottom: var(--ds-space-3); }
.ds-doc h3 { font-size: var(--ds-type-heading-4); margin-top: var(--ds-space-6); margin-bottom: var(--ds-space-2); }
.ds-doc p, .ds-doc li { color: var(--ds-ink-600); font-size: var(--ds-type-body); line-height: 1.7; }
.ds-doc-meta { font-size: var(--ds-type-label); color: var(--ds-ink-500); }
@media (max-width: 576px) { .ds-doc { padding: var(--ds-space-6) var(--ds-space-5); } }

/* Skip link restyle (keeps the existing behavior) */
/* Keyboard skip-link: explicit accent pairing — the previous brand-on-accent
   combination rendered orange-on-orange (~1.2:1) when focused. */
.skip-link {
  background: var(--ds-accent);
  color: var(--ds-on-accent) !important;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  border-radius: 0 0 var(--ds-radius-sm) var(--ds-radius-sm);
}

/* NProgress on brand */
#nprogress .bar { background: var(--sport-accent); }
#nprogress .peg { box-shadow: 0 0 10px var(--sport-accent), 0 0 5px var(--sport-accent); }

/* ────────────────────────────────────────────────────────────────────────────
   16. UNIFIED BOOTSTRAP RGB BRIDGE
   Bootstrap utilities use the same signal-orange primary in every sport.
   Sport selection changes content and iconography, not interface color.
   ──────────────────────────────────────────────────────────────────────────── */
:root, [data-sport] { --bs-primary-rgb: 255, 85, 0; }

/* ────────────────────────────────────────────────────────────────────────────
   17. RESPONSIVE LAYER — the design system's own mobile/tablet rules.
   Layered after everything above; page-level styles can still override.
   ──────────────────────────────────────────────────────────────────────────── */
.ds-section-head { flex-wrap: wrap; }
.page-header .header-btn, .page-header .back-btn { min-height: 44px; }

/* Shared social/map interaction targets. The visual glyph may remain compact,
   but the interactive box always meets the 44px pointer/touch contract. */
.fb-action-btn { min-height: 44px; }
.group-match-row .btn-group .btn-sm { min-width: 44px; }
.fb-reaction-counts .reaction-counts-inner {
  min-width: 44px;
  min-height: 44px;
  padding-inline: var(--ds-space-2);
  justify-content: center;
}
.footer .footer-links a,
.footer .footer-bottom a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}
.leaflet-control-zoom a,
.leaflet-touch .leaflet-control-zoom a {
  width: 44px !important;
  height: 44px !important;
  line-height: 44px !important;
}

/* Collapsed nav: dark sheet panel — same 1850px boundary as the toggler. */
@media (max-width: 1849.98px) {
  .navbar-collapse {
    margin-top: var(--ds-space-2);
    padding: var(--ds-space-3);
    background: var(--ds-surface);
    border: 1px solid var(--ds-border);
    border-radius: var(--ds-radius-lg);
  }
  .navbar .navbar-nav .nav-link { min-height: 44px; display: flex; align-items: center; }
  .navbar-collapse .sport-selector-wrapper {
    border-top: 1px solid var(--ds-border);
    padding-top: var(--ds-space-3);
    margin-top: var(--ds-space-2);
  }
  /* Dropdowns inside the sheet render as part of it, not floating panels */
  .navbar-collapse .dropdown-menu {
    background: var(--ds-surface-2);
    border: 1px solid var(--ds-border);
    box-shadow: none;
    margin: var(--ds-space-1) 0 var(--ds-space-2);
  }
  .navbar-collapse .dropdown-menu .dropdown-item { color: var(--ds-ink-700); }
  .navbar-collapse .dropdown-menu .dropdown-item:hover,
  .navbar-collapse .dropdown-menu .dropdown-item:focus { background: var(--ds-brand-soft); color: var(--ds-brand); }
}

/* Small tablets and down */
@media (max-width: 767.98px) {
  main#mainContent { padding-top: var(--ds-space-3); }
  footer.footer { margin-top: var(--ds-space-10); }
  .card { border-radius: var(--ds-radius-lg); }
  .table thead th, .table > :not(caption) > * > th { padding: var(--ds-space-2) var(--ds-space-3); }
  .table tbody td { padding: var(--ds-space-2) var(--ds-space-3); font-size: var(--ds-type-body-small); }
}

/* Phones */
@media (max-width: 575.98px) {
  .page-header { margin-bottom: var(--ds-space-5); }
  /* Header action buttons become comfortable equal-width rows */
  .page-header .header-btn, .page-header .back-btn {
    flex: 1 1 auto;
    justify-content: center;
    min-height: 44px;
  }

  /* Soften desktop-scale card padding utilities for the small viewport */
  .card .p-5, .card .card-body.p-5 { padding: var(--ds-space-6) !important; }
  .card .p-4, .card .card-body.p-4 { padding: var(--ds-space-5) !important; }
  .card .p-md-5 { padding: var(--ds-space-6) !important; }

  .ds-stat { padding: var(--ds-space-4); }
  .ds-stat-value { font-size: var(--ds-type-heading-2); }
  .ds-empty { padding: var(--ds-space-10) var(--ds-space-4); }
  .ds-empty-icon { width: var(--ds-space-12); height: var(--ds-space-12); font-size: var(--ds-type-heading-3); }

  .btn-lg { padding: var(--ds-space-3) var(--ds-space-5); font-size: var(--ds-type-button); }

  /* Toasts anchor to the bottom, full width, above the AI chat bubble */
  .toast-container {
    top: auto !important;
    right: 12px !important;
    left: 12px !important;
    bottom: 88px;
    align-items: stretch;
  }
  /* The stack (not the containers) is the positioned box now. */
  .toast-stack {
    top: auto;
    right: var(--ds-space-3);
    left: var(--ds-space-3);
    bottom: 88px;
    align-items: stretch;
  }
  .toast-stack .toast-container { position: static; align-items: stretch; }
  .custom-toast { width: 100%; max-width: none; }

  .modal-dialog { margin: var(--ds-space-3); }
  .modal-content { border-radius: var(--ds-radius-lg); }

  .sport-context-bar { font-size: var(--ds-type-caption); }

  /* Grid rhythm: desktop gutters read as gaps on phones */
  .row.g-4 { --bs-gutter-x: var(--ds-space-3); --bs-gutter-y: var(--ds-space-3); }

  .footer { text-align: left; }
  .footer .row > div { margin-bottom: var(--ds-space-2); }
}

/* ────────────────────────────────────────────────────────────────────────────
   18. § AUTH FAMILY — single source; per-view copies removed 2026-07-03.
   Shared shell for ALL Views/Account/* screens (Login, Register, CreateProfile,
   CheckEmail, ConfirmEmail, Forgot/Reset Password + confirmations, Lockout).
   Edit HERE, never re-copy into a view. Page-specific rules stay in their view
   (Login: minor-link/remember; Register: consent; CreateProfile: wide-card/
   grids/photo/submit-offset; CheckEmail: resend box).
   ──────────────────────────────────────────────────────────────────────────── */
.auth-shell {
  display: flex;
  justify-content: center;
  padding: var(--ds-space-8) var(--ds-space-4) var(--ds-space-16);
}

.auth-card {
  width: 100%;
  max-width: 440px;
  background: var(--ds-surface);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-2xl);
  box-shadow: var(--ds-shadow-lg);
  padding: var(--ds-space-10);
}

.auth-card--status { text-align: center; }

.auth-head {
  text-align: center;
  margin-bottom: var(--ds-space-6);
}

/* Onboarding step dots (Register → CheckEmail → ConfirmEmail/CreateProfile) */
.auth-steps {
  display: flex;
  justify-content: center;
  gap: var(--ds-space-2);
  margin-bottom: var(--ds-space-4);
}

.auth-steps span {
  width: 24px;
  height: 4px;
  border-radius: 999px;
  background: var(--ds-border);
}

.auth-steps .is-done { background: var(--ds-border); background: color-mix(in srgb, var(--ds-brand) 45%, var(--ds-border)); }
.auth-steps .is-active { background: var(--ds-brand); }

/* Badge: sport-gradient by default (form screens); status modifiers go flat
   (box-shadow: none preserves the pre-extraction flat look) */
.auth-badge {
  width: var(--ds-space-16);
  height: var(--ds-space-16);
  margin: 0 auto var(--ds-space-5);
  border-radius: var(--ds-radius-xl);
  background: var(--sport-icon-gradient, linear-gradient(135deg, var(--sport-secondary), var(--sport-primary)));
  color: var(--ds-on-sport);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: var(--ds-type-heading-2);
  box-shadow: var(--ds-shadow-sm);
}

.auth-badge--brand {
  background: var(--sport-feature-bg, var(--ds-brand-soft));
  color: var(--ds-brand);
  border: 1px solid var(--ds-border);
  box-shadow: none;
}

.auth-badge--success {
  background: var(--ds-success-surface);
  color: var(--ds-success);
  border: 1px solid var(--ds-success-border);
  box-shadow: none;
}

.auth-badge--warning {
  background: var(--ds-warning-surface);
  color: var(--ds-warning);
  border: 1px solid var(--ds-warning-border);
  box-shadow: none;
}

.auth-badge--danger {
  background: var(--ds-error-surface);
  color: var(--ds-error);
  border: 1px solid var(--ds-error-border);
  box-shadow: none;
}

.auth-title {
  font-size: var(--ds-type-heading-2);
  margin-bottom: var(--ds-space-2);
}

.auth-sub {
  color: var(--ds-ink-500);
  font-size: var(--ds-type-body);
  line-height: 1.6;
  margin: 0;
}

.auth-field { margin-bottom: var(--ds-space-5); }

.auth-field-error {
  display: block;
  color: var(--ds-error);
  font-size: var(--ds-type-label);
  font-weight: 500;
  margin-top: var(--ds-space-1);
}

.auth-field-error:empty { margin-top: 0; }

/* Password input + show/hide toggle */
.auth-pw-wrap { position: relative; }
.auth-pw-wrap .form-control { padding-right: calc(var(--ds-space-12) + var(--ds-space-1)); }

.auth-pw-toggle {
  position: absolute;
  top: 50%;
  right: 1px;
  transform: translateY(-50%);
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: calc(var(--ds-radius-md) - 2px);
  background: transparent;
  color: var(--ds-ink-500);
  font-size: var(--ds-type-body);
  cursor: pointer;
  transition: color var(--ds-dur) var(--ds-ease), background-color var(--ds-dur) var(--ds-ease);
}

.auth-pw-toggle:hover {
  color: var(--ds-ink-700);
  background: var(--ds-surface-2);
}

/* Live password-requirements checklist */
.auth-pw-rules {
  list-style: none;
  margin: var(--ds-space-2) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--ds-space-1) var(--ds-space-4);
}

.auth-pw-rules li {
  display: flex;
  align-items: center;
  gap: var(--ds-space-2);
  font-size: var(--ds-type-label);
  color: var(--ds-ink-500);
}

.auth-pw-rules li i {
  font-size: var(--ds-type-caption);
  color: var(--ds-ink-400);
  width: 12px;
  text-align: center;
  flex-shrink: 0;
}

.auth-pw-rules li.is-met { color: var(--ds-success); }
.auth-pw-rules li.is-met i { color: var(--ds-success); font-size: var(--ds-type-caption); }

.auth-foot {
  text-align: center;
  margin-top: var(--ds-space-6);
  padding-top: var(--ds-space-5);
  border-top: 1px solid var(--ds-border);
  color: var(--ds-ink-500);
  font-size: var(--ds-type-body-small);
}

.auth-foot a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-weight: 600;
  text-decoration: none;
}
.auth-foot a:hover { text-decoration: underline; }

.auth-logo {
  display: block;
  width: var(--ds-space-16);
  height: var(--ds-space-16);
  margin: 0 auto var(--ds-space-4);
  border-radius: var(--ds-radius-lg);
  transform-origin: 50% 0%;
  animation: auth-logo-fold var(--ds-motion-page) var(--ds-ease-out) both;
}

@keyframes auth-logo-fold {
  0% { transform: perspective(600px) rotateX(-78deg); opacity: 0; }
  60% { transform: perspective(600px) rotateX(10deg); opacity: 1; }
  100% { transform: perspective(600px) rotateX(0deg); }
}

.auth-minor-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-size: var(--ds-type-label);
  font-weight: 600;
  text-decoration: none;
}
.auth-minor-link:hover { text-decoration: underline; }

.auth-remember {
  min-height: 44px;
  margin: 0 0 var(--ds-space-5);
  display: flex;
  align-items: center;
}
.auth-remember .form-check-input {
  width: var(--ds-space-5);
  height: var(--ds-space-5);
  margin-top: 0;
  cursor: pointer;
}
.auth-remember .form-check-label {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  padding-left: var(--ds-space-1);
  color: var(--ds-ink-600);
  font-size: var(--ds-type-label);
  cursor: pointer;
}

/* Info hint box */
.auth-hint {
  display: flex;
  gap: var(--ds-space-3);
  align-items: flex-start;
  text-align: left;
  background: var(--ds-surface-2);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-md);
  padding: var(--ds-space-3) var(--ds-space-4);
  margin-top: var(--ds-space-6);
}

.auth-hint i {
  color: var(--ds-brand);
  font-size: var(--ds-type-body);
  margin-top: var(--ds-space-1);
  flex-shrink: 0;
}

.auth-hint p {
  margin: 0;
  font-size: var(--ds-type-body-small);
  color: var(--ds-ink-600);
  line-height: 1.55;
}

.auth-hint a { font-weight: 600; }

/* Stacked call-to-action buttons on status screens */
.auth-cta {
  display: flex;
  flex-direction: column;
  gap: var(--ds-space-2);
  margin-top: var(--ds-space-6);
}

/* Hide the empty ASP.NET validation summary on auth forms */
.auth-card .validation-summary-valid { display: none; }

/* Social sign-in buttons (Login / Register / ExternalRegister) — brand-correct
   fills per provider guidelines: white Google, black Apple, #1877F2 Facebook. */
.auth-social {
  display: flex;
  flex-direction: column;
  gap: var(--ds-space-2);
}

.auth-social form { margin: 0; }

.auth-social-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--ds-space-2);
  width: 100%;
  min-height: 44px;
  padding: var(--ds-space-2) var(--ds-space-4);
  border: 1px solid transparent;
  border-radius: var(--ds-radius-md);
  font-size: var(--ds-type-body);
  font-weight: 600;
  line-height: 1.2;
  cursor: pointer;
  transition: background-color var(--ds-dur) var(--ds-ease),
              box-shadow var(--ds-dur) var(--ds-ease);
}

.auth-social-btn svg {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}

.auth-social-btn:focus-visible {
  outline: 2px solid var(--ds-brand);
  outline-offset: 2px;
}

.auth-social-btn:disabled { opacity: 0.75; cursor: default; }

.auth-social-btn--google { background: var(--ds-provider-google-surface); color: var(--ds-provider-google-text); border-color: var(--ds-provider-google-border); }
.auth-social-btn--google:hover { background: var(--ds-provider-google-hover); box-shadow: var(--ds-shadow-sm); }

.auth-social-btn--apple { background: var(--ds-provider-apple-surface); color: var(--ds-provider-on-dark); }
.auth-social-btn--apple:hover { background: var(--ds-provider-apple-hover); }

.auth-social-btn--facebook { background: var(--ds-provider-facebook-surface); color: var(--ds-provider-on-dark); }
.auth-social-btn--facebook:hover { background: var(--ds-provider-facebook-hover); }

/* "or" separator between the social stack and the email/password form */
.auth-divider {
  display: flex;
  align-items: center;
  gap: var(--ds-space-3);
  margin: var(--ds-space-5) 0;
  color: var(--ds-ink-500);
  font-size: var(--ds-type-label);
  font-weight: 500;
}

.auth-divider::before,
.auth-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--ds-border);
}

@media (max-width: 575.98px) {
  .auth-shell { padding: var(--ds-space-4) var(--ds-space-3) var(--ds-space-10); }

  .auth-card {
    padding: var(--ds-space-6) var(--ds-space-5);
    border-radius: var(--ds-radius-xl);
  }

  .auth-card .form-control,
  .auth-card .form-select { font-size: var(--ds-type-body); } /* prevent iOS focus zoom */

  .auth-pw-rules { grid-template-columns: 1fr; }
}

/* ────────────────────────────────────────────────────────────────────────────
   19. § POP LAYER — modern vibrancy pass (2026-07-03)
   Purely additive: gradient brand fills, brand-tinted elevation, glass nav,
   light mesh hero. No selector is renamed or removed; earlier sections keep
   their contracts. Everything animated is reduced-motion safe (§2 global kill
   switch still applies; new transitions are additionally gated).
   ──────────────────────────────────────────────────────────────────────────── */

/* 19.1 Compatibility glow tokens. Palette, elevation, and surface tokens live
   only in the Precision in Motion contract below. */
:root {
  --ds-glow-sm: var(--ds-shadow-sm);
  --ds-glow-md: var(--ds-shadow-md);
}
@supports (color: color-mix(in srgb, red, blue)) { :root { --ds-glow-sm: 0 4px 14px color-mix(in srgb, var(--ds-accent) 24%, transparent); --ds-glow-md: 0 8px 28px color-mix(in srgb, var(--ds-accent) 22%, transparent); } }

/* 19.2 Global — smooth in-page scrolling (motion-gated; §2 covers reduce) */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

/* Gradient display-text utility. Fallback-first: solid sport-primary (passes
   AA on white), gradient only where background-clip:text is supported. Use on
   LARGE bold headings (>=24px) on light surfaces only — both sport stops are
   dark, so 3:1 large-text contrast holds on white for all 7 palettes. */
.ds-text-gradient { color: var(--sport-primary); }
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .ds-text-gradient {
    background-image: var(--ds-grad-brand);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
}

/* 19.3 Buttons — primary goes gradient with an inner highlight + hover glow.
   !important is required: sport-themes.css paints .btn-primary with its own
   !important gradient/glow, which was silently winning over §4. */
.btn-primary,
.btn-primary:hover, .btn-primary:focus, .btn-primary:active,
.btn-primary:disabled, .btn-primary.disabled {
  background: var(--ds-grad-brand) !important;
  border-color: transparent !important; /* keep 1px border-box so height is unchanged */
  color: var(--ds-on-accent);
}
.btn-primary {
  box-shadow: var(--ds-shadow-xs), inset 0 1px 0 transparent !important;
  box-shadow: var(--ds-shadow-xs), inset 0 1px 0 color-mix(in srgb, var(--ds-text-inverse) 18%, transparent) !important;
}
.btn-primary:hover, .btn-primary:focus {
  /* translateY(-1px) comes from §4; glow replaces the flat hover shadow */
  box-shadow: var(--ds-glow-sm), inset 0 1px 0 transparent !important;
  box-shadow: var(--ds-glow-sm), inset 0 1px 0 color-mix(in srgb, var(--ds-text-inverse) 18%, transparent) !important;
  filter: brightness(1.06);
}
.btn-primary:active {
  box-shadow: var(--ds-shadow-xs), inset 0 1px 0 transparent !important;
  box-shadow: var(--ds-shadow-xs), inset 0 1px 0 color-mix(in srgb, var(--ds-text-inverse) 12%, transparent) !important;
  transform: translateY(0) scale(0.985);
  filter: none;
}
.btn-primary:disabled, .btn-primary.disabled { filter: none; box-shadow: none !important; }
.btn-primary:focus-visible { outline: 2px solid var(--ds-brand); outline-offset: 2px; }

/* 19.4 Navbar — shared translucent product shell. */
.navbar {
  border-bottom: 1px solid var(--ds-border) !important;
}
@supports ((-webkit-backdrop-filter: blur(14px)) or (backdrop-filter: blur(14px))) {
  .navbar {
    background-color: var(--pim-nav) !important;
    -webkit-backdrop-filter: blur(14px) saturate(1.4);
    backdrop-filter: blur(14px) saturate(1.4);
  }
}
/* Animated gradient underline on desktop nav links (accent pops on the dark
   shell for every sport). Desktop-EXPANDED only (the hamburger persists until
   1850px — see _Layout's navbar-fit block), and NEVER on .dropdown-toggle:
   Bootstrap draws the caret with the same ::after, so styling it here turns
   the caret into an orange bar (the "broken glyph next to Community" bug). */
@media (min-width: 1850px) {
  .navbar .navbar-nav .nav-link:not(.dropdown-toggle) { position: relative; }
  .navbar .navbar-nav .nav-link:not(.dropdown-toggle)::after {
    content: '';
    position: absolute;
    left: var(--ds-space-3); right: var(--ds-space-3); bottom: 1px;
    height: 2px;
    border-radius: 999px;
    background: var(--ds-accent);
    transform: scaleX(0);
    transform-origin: left center;
  }
  .navbar .navbar-nav .nav-link:not(.dropdown-toggle):hover::after,
  .navbar .navbar-nav .nav-link:not(.dropdown-toggle):focus-visible::after,
  .navbar .navbar-nav .nav-link:not(.dropdown-toggle).active::after { transform: scaleX(1); }
}
@media (min-width: 1850px) and (prefers-reduced-motion: no-preference) {
  .navbar .navbar-nav .nav-link:not(.dropdown-toggle)::after { transition: transform var(--ds-motion-standard) var(--ds-ease); }
}

/* 19.5 Page headers — brand glow under the banner + gradient accent bar under
   the title. (Art-direction note: gradient TEXT is skipped here — the banner
   is a dark sport gradient with white h1, dark gradient text would vanish;
   .ds-text-gradient above is the light-surface equivalent.) */
.page-header {
  box-shadow: var(--ds-shadow-sm), var(--ds-glow-md);
}
.page-header h1:not(.d-flex):not(.d-inline-flex)::after,
.page-header .page-title:not(.d-flex):not(.d-inline-flex)::after {
  content: '';
  display: block;
  width: 48px;
  height: 4px;
  border-radius: 999px;
  margin-top: var(--ds-space-2);
  background: linear-gradient(90deg, var(--sport-accent), transparent);
  background: linear-gradient(90deg, var(--sport-accent), color-mix(in srgb, var(--sport-accent) 12%, transparent));
}
.page-header.text-center h1::after,
.page-header.text-center .page-title::after { margin-left: auto; margin-right: auto; }

/* 19.6 Cards — brand-tinted lift for interactive cards only; --ds-shadow-lg
   is now brand-tinted via 19.1, so plain shadows remain the fallback. */
.card-interactive:hover, a > .card:hover, a.card:hover {
  box-shadow: var(--ds-shadow-lg);
}
.card[role="button"] {
  transition: transform var(--ds-dur) var(--ds-ease), box-shadow var(--ds-dur) var(--ds-ease), border-color var(--ds-dur) var(--ds-ease);
}
.card[role="button"]:hover {
  transform: translateY(-2px);
  box-shadow: var(--ds-shadow-lg);
  border-color: var(--ds-border-strong);
}
/* :has kept in its own rules so non-supporting engines drop only these. */
.card:has(.stretched-link) {
  transition: transform var(--ds-dur) var(--ds-ease), box-shadow var(--ds-dur) var(--ds-ease), border-color var(--ds-dur) var(--ds-ease);
}
.card:has(.stretched-link):hover {
  transform: translateY(-2px);
  box-shadow: var(--ds-shadow-lg);
  border-color: var(--ds-border-strong);
}
/* Opt-in flourish: 3px gradient top strip */
.card-pop { position: relative; overflow: hidden; }
.card-pop::before {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: 3px;
  background: var(--ds-grad-brand);
  z-index: 1;
}

/* 19.7 Badges — solid primary badges go gradient (white text; both sport
   stops are dark on every palette). Soft badge AA pairs already carry their
   1px color-mix borders (§9) — untouched. */
.badge.bg-primary { background: var(--ds-grad-brand) !important; }

/* 19.8 Tables + lists — row hover becomes the brand surface tint (replaces
   the plain gray wash; also feeds Bootstrap's cell-level hover variable). */
.table-hover tbody tr:hover { background: var(--ds-surface-tint); }
.table-hover > tbody > tr:hover > * { --bs-table-accent-bg: var(--ds-surface-tint); }
.list-group-item-action:hover, .list-group-item-action:focus { background: var(--ds-surface-tint); }
.dropdown-item:hover, .dropdown-item:focus { background: var(--ds-surface-tint); }

/* 19.9 Footer — quiet divider shared by light and dark modes. */
.footer {
  border-top: 1px solid var(--ds-border) !important;
  border-image: none;
}

/* 19.10 Forms — re-assert the brand focus ring. §7 already defines it, but
   sport-themes.css was overriding with a 4px accent-light ring (!important);
   accent rings are near-invisible on white for the light-accent sports. */
.form-control:focus, .form-select:focus,
.form-modern .form-control:focus, .form-modern .form-select:focus {
  border-color: var(--ds-brand) !important;
  box-shadow: 0 0 0 3px var(--ds-brand-ring) !important;
}

/* 19.11 HERO (opt-in via .hero-pop on Home) — dark animated gradient becomes
   a light mesh: layered sport radials at 7–12% alpha over the surface tint,
   gradient display headline, re-inked copy and chrome. Scoped to .hero-pop so
   no other surface changes. !important beats sport-themes' hero !important
   (higher specificity, later in cascade — covers the mobile override too). */
.hero-section.hero-pop {
  background: radial-gradient(52rem 34rem at 14% -12%, transparent, transparent 62%),
    radial-gradient(44rem 30rem at 86% -4%, transparent, transparent 58%),
    radial-gradient(40rem 30rem at 50% 112%, transparent, transparent 62%),
    var(--ds-surface-tint) !important;
  background:
    radial-gradient(52rem 34rem at 14% -12%, color-mix(in srgb, var(--sport-secondary) 12%, transparent), transparent 62%),
    radial-gradient(44rem 30rem at 86% -4%, color-mix(in srgb, var(--sport-accent) 10%, transparent), transparent 58%),
    radial-gradient(40rem 30rem at 50% 112%, color-mix(in srgb, var(--sport-primary) 7%, transparent), transparent 62%),
    var(--ds-surface-tint) !important;
  color: var(--ds-ink-700);
  animation: none; /* the 300% gradient-shift loop reads as noise on a mesh */
  border-bottom: 1px solid var(--ds-border);
  box-shadow: 0 24px 60px transparent;
  box-shadow: 0 24px 60px color-mix(in srgb, var(--sport-secondary) 10%, transparent);
}

/* Headline: gradient text with solid sport-primary fallback. text-shadow must
   go — it would paint behind the clipped transparent glyphs. */
.hero-section.hero-pop .hero-title { color: var(--sport-primary); text-shadow: none; }
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .hero-section.hero-pop .hero-title {
    background-image: var(--ds-grad-brand);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
}

.hero-section.hero-pop .hero-badge {
  background: var(--ds-surface);
  background: color-mix(in srgb, var(--sport-secondary) 7%, var(--ds-surface));
  border-color: transparent;
  border-color: color-mix(in srgb, var(--sport-secondary) 28%, transparent);
  color: var(--ds-brand-strong);
}

.hero-section.hero-pop .hero-btn-secondary {
  background: var(--ds-surface);
  color: var(--ds-ink-700);
  border-color: var(--ds-border-strong);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  box-shadow: var(--ds-shadow-xs);
}
.hero-section.hero-pop .hero-btn-secondary:hover,
.hero-section.hero-pop .hero-btn-secondary:focus-visible {
  background: var(--ds-surface-tint);
  color: var(--ds-ink-900);
  border-color: var(--ds-border-strong);
  border-color: color-mix(in srgb, var(--sport-secondary) 35%, var(--ds-border-strong));
  box-shadow: var(--ds-shadow-md);
}

.hero-section.hero-pop .hero-apps-label { color: var(--ds-ink-500); }

/* Decorative layer re-tinted for the light mesh (floats/pulses are existing
   animations, already killed globally under prefers-reduced-motion). Orb 1
   needs !important — sport-themes re-paints it with !important. */
.hero-section.hero-pop .hero-orb-1 {
  background: radial-gradient(circle, transparent 0%, transparent 70%) !important;
  background: radial-gradient(circle, color-mix(in srgb, var(--sport-secondary) 20%, transparent) 0%, transparent 70%) !important;
}
.hero-section.hero-pop .hero-orb-2 {
  background: radial-gradient(circle, transparent 0%, transparent 70%);
  background: radial-gradient(circle, color-mix(in srgb, var(--sport-accent) 16%, transparent) 0%, transparent 70%);
}
.hero-section.hero-pop .hero-orb-3 {
  background: radial-gradient(circle, transparent 0%, transparent 70%);
  background: radial-gradient(circle, color-mix(in srgb, var(--sport-primary) 10%, transparent) 0%, transparent 70%);
}
.hero-section.hero-pop .hero-orb-4 {
  background: radial-gradient(circle, transparent 0%, transparent 70%);
  background: radial-gradient(circle, color-mix(in srgb, var(--sport-secondary) 12%, transparent) 0%, transparent 70%);
}
.hero-section.hero-pop .hero-ring { border-color: transparent; border-color: color-mix(in srgb, var(--sport-primary) 12%, transparent); }
.hero-section.hero-pop .hero-ring-3 { border-color: transparent; border-color: color-mix(in srgb, var(--sport-accent) 30%, transparent); }
.hero-section.hero-pop .hero-dot-grid {
  background-image: radial-gradient(transparent 1px, transparent 1px);
  background-image: radial-gradient(color-mix(in srgb, var(--sport-primary) 14%, transparent) 1px, transparent 1px);
}

/* ────────────────────────────────────────────────────────────────────────────
   20. PRECISION IN MOTION — unified light/dark product language (2026-07-15)

   One semantic layer drives every Razor view. Sports remain identifiable by
   their name and icon while all product actions and focus use MySetMatch
   signal orange. Theme selection is resolved in _Layout before CSS
   loads; the media-query fallback keeps OS dark mode working without script.
   ──────────────────────────────────────────────────────────────────────────── */
:root {
  color-scheme: light;

  /* Physical palette. Components consume only the semantic --ds-* aliases. */
  --pim-canvas: #f7f7f9;
  --pim-canvas-2: #efeff3;
  --pim-canvas-3: #e7e8ed;
  --pim-surface: #ffffff;
  --pim-surface-2: #eff0f3;
  --pim-surface-3: #f3f4f6;
  --pim-surface-interactive: #f5f5f7;
  --pim-border-subtle: #e8e8ec;
  --pim-border: #d8d9df;
  /* Strong control boundaries meet WCAG 1.4.11 (3:1) against both the light
     canvas and primary surface. Subtle/default borders remain intentionally
     quieter for non-interactive grouping. */
  --pim-border-strong: #8d8d98;
  --pim-text: #17171c;
  --pim-text-2: #50505a;
  --pim-text-3: #5f5f6b; /* darkened to clear 4.5:1 AA on --ds-surface-2 (#eff0f3) for table headers + input labels */
  --pim-text-4: #6e6e78; /* stays lighter than text-3 → ink-400 reads as the lightest tier */
  --pim-text-inverse: #ffffff;
  --pim-nav: rgba(255, 255, 255, 0.94);
  --pim-accent: #ff5500;
  --pim-accent-hover: #df4a00;
  --pim-accent-pressed: #c63e00;
  --pim-brand-secondary: #17171c;
  --pim-link: #b83d00;
  --pim-link-strong: #8f3000;
  --pim-ring: rgba(255, 85, 0, 0.25);
  --pim-overlay: rgba(16, 16, 20, 0.56);
  --pim-shadow-color: rgba(12, 16, 24, 0.12);
  --pim-success: #087443;
  --pim-success-bg: #eaf8f0;
  --pim-success-border: #a9dfbf;
  --pim-danger: #b42318;
  --pim-danger-bg: #fff0ef;
  --pim-danger-border: #f3b9b4;
  --pim-warning: #8a5100;
  --pim-warning-bg: #fff5df;
  --pim-warning-border: #f4ce82;
  --pim-info: #1556a3;
  --pim-info-bg: #edf6ff;
  --pim-info-border: #b8d9fa;
  /* Provider-owned authentication colors are centralized exceptions and do
     not change with product theme. */
  --ds-provider-google-surface: #ffffff;
  --ds-provider-google-text: #3c4043;
  --ds-provider-google-border: #dadce0;
  --ds-provider-google-hover: #f8f9fa;
  --ds-provider-apple-surface: #000000;
  --ds-provider-apple-hover: #1d1d1f;
  --ds-provider-facebook-surface: #1877f2;
  --ds-provider-facebook-hover: #166fe5;
  --ds-provider-on-dark: #ffffff;

  /* Semantic contract shared by legacy, Bootstrap, and new components. */
  --ds-canvas: var(--pim-canvas);
  --ds-surface: var(--pim-surface);
  --ds-background-primary: var(--pim-canvas);
  --ds-background-secondary: var(--pim-canvas-2);
  --ds-background-tertiary: var(--pim-canvas-3);
  --ds-surface-primary: var(--pim-surface);
  --ds-surface-secondary: var(--pim-surface-2);
  --ds-surface-elevated: var(--pim-surface-3);
  --ds-surface-interactive: var(--pim-surface-interactive);
  --ds-text-primary: var(--pim-text);
  --ds-text-secondary: var(--pim-text-2);
  --ds-text-muted: var(--pim-text-3);
  /* Fixed foreground for dark media, sport gradients, scrims and lightboxes.
     The old mapping followed the active theme and therefore became near-black
     in dark mode even though those emphasis surfaces stayed dark. */
  --ds-on-dark: #ffffff;
  --ds-emphasis-surface: #101014;
  --ds-on-dark-warning: #ffc46b;
  --ds-on-emphasis: var(--ds-on-dark);
  --ds-text-inverse: var(--ds-on-emphasis);
  /* Paired ink for a neutral fill that follows the active theme (for example,
     --ds-ink-900 as a tooltip surface or --ds-text-muted as a badge fill). */
  --ds-on-neutral-strong: var(--pim-text-inverse);
  --ds-border-subtle: var(--pim-border-subtle);
  --ds-border-default: var(--pim-border);
  --ds-brand-primary: var(--pim-accent);
  --ds-brand-secondary: var(--pim-brand-secondary);
  --ds-brand-hover: var(--pim-accent-hover);
  --ds-brand-pressed: var(--pim-accent-pressed);
  --ds-focus-ring: var(--pim-ring);
  --ds-overlay: var(--pim-overlay);
  --ds-success: var(--pim-success);
  --ds-success-surface: var(--pim-success-bg);
  --ds-success-border: var(--pim-success-border);
  --ds-warning: var(--pim-warning);
  --ds-warning-surface: var(--pim-warning-bg);
  --ds-warning-border: var(--pim-warning-border);
  --ds-error: var(--pim-danger);
  --ds-error-surface: var(--pim-danger-bg);
  --ds-error-border: var(--pim-danger-border);
  --ds-info: var(--pim-info);
  --ds-info-surface: var(--pim-info-bg);
  --ds-info-border: var(--pim-info-border);
  /* Compatibility aliases used by older feature views. Keep these semantic so
     their meaning survives a theme change; do not add page-local fallbacks. */
  --ds-surface-1: var(--pim-surface);
  --ds-surface-2: var(--pim-surface-2);
  --ds-surface-3: var(--pim-surface-3);
  --ds-border: var(--pim-border);
  --ds-border-strong: var(--pim-border-strong);
  --ds-ink-900: var(--pim-text);
  --ds-ink-800: var(--pim-text);
  --ds-ink-700: var(--pim-text-2);
  --ds-ink-600: var(--pim-text-3);
  --ds-ink-500: var(--pim-text-3);
  --ds-ink-400: var(--pim-text-4);
  --ds-text: var(--pim-text-2);
  --ds-brand: var(--pim-link);
  --ds-brand-strong: var(--pim-link-strong);
  --ds-brand-soft: rgba(255, 85, 0, 0.1);
  --ds-brand-ring: var(--pim-ring);
  --ds-accent: var(--pim-accent);
  --ds-accent-hover: var(--pim-accent-hover);
  /* Foregrounds are paired with the surface they sit on, not with the page
     theme. Signal orange always takes dark ink; sport media always takes white.
     Solid semantic/brand colors deliberately follow --pim-text-inverse because
     those colors become lighter in dark mode. */
  --ds-on-accent: #101014;
  --ds-on-sport: var(--ds-on-dark);
  --ds-on-brand: var(--pim-text-inverse);
  --ds-on-success: var(--pim-text-inverse);
  --ds-on-warning: var(--pim-text-inverse);
  --ds-on-error: var(--pim-text-inverse);
  --ds-on-info: var(--pim-text-inverse);
  --ds-grad-brand: linear-gradient(135deg, #ff6a1a 0%, var(--pim-accent) 58%, #ed3f00 100%);
  --ds-surface-tint: var(--pim-surface);
  --ds-ink-brand: var(--pim-text);
  --ds-shadow-xs: 0 1px 2px rgba(12, 16, 24, 0.06);
  --ds-shadow-sm: 0 1px 2px rgba(12, 16, 24, 0.06), 0 4px 12px rgba(12, 16, 24, 0.05);
  --ds-shadow-md: 0 2px 6px rgba(12, 16, 24, 0.06), 0 12px 26px rgba(12, 16, 24, 0.08);
  --ds-shadow-lg: 0 8px 24px var(--pim-shadow-color);
  --ds-shadow-xl: 0 18px 48px rgba(12, 16, 24, 0.2);
  --ds-radius-xs: 2px;
  --ds-radius-sm: 4px;
  --ds-radius-md: 6px;
  --ds-radius-lg: 8px;
  --ds-radius-xl: 12px;
  --ds-radius-2xl: 16px;

  /* Shared layout, typography, and motion contracts. The names deliberately
     match the mobile theme even where the platform-appropriate values differ. */
  --ds-space-1: 4px;
  --ds-space-2: 8px;
  --ds-space-3: 12px;
  --ds-space-4: 16px;
  --ds-space-5: 20px;
  --ds-space-6: 24px;
  --ds-space-8: 32px;
  --ds-space-10: 40px;
  --ds-space-12: 48px;
  --ds-space-16: 64px;
  --ds-space-20: 80px;
  --ds-type-display-large: clamp(2.25rem, 5vw, 4rem);
  --ds-type-display-small: clamp(2rem, 4vw, 3rem);
  --ds-type-heading-1: clamp(1.75rem, 3.5vw, 2.5rem);
  --ds-type-heading-2: clamp(1.5rem, 2.5vw, 2rem);
  --ds-type-heading-3: 1.25rem;
  --ds-type-heading-4: 1.125rem;
  --ds-type-title-large: 1.25rem;
  --ds-type-title: 1.0625rem;
  --ds-type-body-large: 1.0625rem;
  --ds-type-body: 1rem;
  --ds-type-body-small: .875rem;
  --ds-type-label-large: .875rem;
  --ds-type-label: .8125rem;
  --ds-type-caption: .75rem;
  --ds-type-button: .875rem;
  --ds-motion-fast: 150ms;
  --ds-motion-standard: 250ms;
  --ds-motion-modal: 250ms;
  --ds-motion-page: 400ms;
  --ds-motion-loading: 400ms;
}
@supports (color: color-mix(in srgb, red, blue)) { :root { --ds-brand-soft: color-mix(in srgb, var(--pim-accent) 10%, transparent); --ds-surface-tint: color-mix(in srgb, var(--pim-accent) 4%, var(--pim-surface)); --ds-ink-brand: color-mix(in srgb, var(--pim-accent) 10%, var(--pim-text)); } }

html[data-theme="dark"] {
  color-scheme: dark;
  --pim-canvas: #101014;
  --pim-canvas-2: #141419;
  --pim-canvas-3: #18181e;
  --pim-surface: #1c1c22;
  --pim-surface-2: #16161b;
  --pim-surface-3: #26262e;
  --pim-surface-interactive: #24242b;
  --pim-border-subtle: #28282f;
  --pim-border: #2e2e36;
  --pim-border-strong: #696974;
  --pim-text: #f2f2f4;
  --pim-text-2: #c4c4cc;
  --pim-text-3: #92929d;
  --pim-text-4: #92929d;
  --pim-text-inverse: #17171c;
  --pim-nav: rgba(16, 16, 20, 0.94);
  --pim-link: #ff7733;
  --pim-link-strong: #ff9a66;
  --pim-accent-pressed: #e14900;
  --pim-brand-secondary: #f2f2f4;
  --pim-ring: rgba(255, 85, 0, 0.34);
  --pim-overlay: rgba(0, 0, 0, 0.72);
  --pim-shadow-color: rgba(0, 0, 0, 0.42);
  --pim-success: #63d793;
  --pim-success-bg: #10291d;
  --pim-success-border: #245c3d;
  --pim-danger: #ff8b82;
  --pim-danger-bg: #321817;
  --pim-danger-border: #69302d;
  --pim-warning: #ffc46b;
  --pim-warning-bg: #302413;
  --pim-warning-border: #684b20;
  --pim-info: #80baff;
  --pim-info-bg: #12243a;
  --pim-info-border: #27517d;
  --ds-shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.35);
  --ds-shadow-sm: 0 4px 14px rgba(0, 0, 0, 0.28);
  --ds-shadow-md: 0 12px 28px rgba(0, 0, 0, 0.34);
  --ds-shadow-lg: 0 18px 42px rgba(0, 0, 0, 0.42);
  --ds-shadow-xl: 0 26px 70px rgba(0, 0, 0, 0.56);
}

/* No-script / blocked-storage fallback: honor the operating system. */
@media (prefers-color-scheme: dark) {
  html:not([data-theme]) {
    color-scheme: dark;
    --pim-canvas: #101014;
    --pim-canvas-2: #141419;
    --pim-canvas-3: #18181e;
    --pim-surface: #1c1c22;
    --pim-surface-2: #16161b;
    --pim-surface-3: #26262e;
    --pim-surface-interactive: #24242b;
    --pim-border-subtle: #28282f;
    --pim-border: #2e2e36;
    --pim-border-strong: #696974;
    --pim-text: #f2f2f4;
    --pim-text-2: #c4c4cc;
    --pim-text-3: #92929d;
    --pim-text-4: #92929d;
    --pim-text-inverse: #17171c;
    --pim-nav: rgba(16, 16, 20, 0.94);
    --pim-link: #ff7733;
    --pim-link-strong: #ff9a66;
    --pim-accent-pressed: #e14900;
    --pim-brand-secondary: #f2f2f4;
    --pim-ring: rgba(255, 85, 0, 0.34);
    --pim-overlay: rgba(0, 0, 0, 0.72);
    --pim-shadow-color: rgba(0, 0, 0, 0.42);
    --pim-success: #63d793;
    --pim-success-bg: #10291d;
    --pim-success-border: #245c3d;
    --pim-danger: #ff8b82;
    --pim-danger-bg: #321817;
    --pim-danger-border: #69302d;
    --pim-warning: #ffc46b;
    --pim-warning-bg: #302413;
    --pim-warning-border: #684b20;
    --pim-info: #80baff;
    --pim-info-bg: #12243a;
    --pim-info-border: #27517d;
    --ds-shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.35);
    --ds-shadow-sm: 0 4px 14px rgba(0, 0, 0, 0.28);
    --ds-shadow-md: 0 12px 28px rgba(0, 0, 0, 0.34);
    --ds-shadow-lg: 0 18px 42px rgba(0, 0, 0, 0.42);
    --ds-shadow-xl: 0 26px 70px rgba(0, 0, 0, 0.56);
  }
}

/* Canvas and legacy variable bridge. */
html, body { background-color: var(--ds-canvas); }
body {
  --bg-body: var(--ds-canvas);
  --bg-card: var(--ds-surface);
  --text-main: var(--ds-ink-700);
  --text-muted: var(--ds-ink-500);
  --border-color: var(--ds-border);
  --primary-blue: var(--ds-brand);
  --primary-dark: var(--ds-ink-900);
  --accent-orange: var(--ds-accent);
  --bs-body-bg: var(--ds-canvas);
  --bs-body-color: var(--ds-ink-700);
  --bs-secondary-color: var(--ds-ink-500);
  --bs-border-color: var(--ds-border);
  --bs-primary-rgb: 255, 85, 0;
  background: var(--ds-canvas) !important;
  color: var(--ds-ink-700);
}
/* Bootstrap's .text-body reads --bs-body-color-RGB, not --bs-body-color, and the bridge above
   can only set the latter: --ds-ink-700 resolves through a var() chain, so there is no static
   "r, g, b" triplet to hand it. The utility therefore fell through to Bootstrap's own light-theme
   default and painted near-black text in BOTH themes — invisible on a dark surface. Pointing the
   utility straight at the flipping token fixes every use of it at once; this partial is loaded
   after bootstrap.min.css, so it wins on cascade order at equal specificity. */
.text-body { color: var(--ds-ink-700) !important; }

body, input, button, select, textarea { font-size: var(--ds-type-body); }
main#mainContent { background: transparent; }
h1, h2, h3, h4, h5, h6 { color: var(--ds-ink-900); }
hr { border-color: var(--ds-border); opacity: 1; }
::selection { background: transparent; background: color-mix(in srgb, var(--ds-accent) 28%, transparent); }
::-webkit-scrollbar-thumb { background-color: var(--ds-border-strong); }

/* Signal-orange actions: stable across all sport filters. */
html .btn-primary,
html .btn-primary:hover, html .btn-primary:focus, html .btn-primary:active,
html .btn-primary:disabled, html .btn-primary.disabled,
html .btn.btn-accent, html .btn.btn-accent:hover, html .btn.btn-accent:focus,
html .hero-btn-primary, html .hero-btn-primary:hover {
  background: var(--ds-grad-brand) !important;
  border-color: transparent !important;
  color: var(--ds-on-accent) !important;
  box-shadow: 0 8px 20px transparent !important;
  box-shadow: 0 8px 20px color-mix(in srgb, var(--ds-accent) 24%, transparent) !important;
}
html .btn-primary:hover, html .btn.btn-accent:hover, html .hero-btn-primary:hover {
  filter: brightness(1.06);
  transform: translateY(-1px);
}
html .btn-outline-primary {
  color: var(--ds-brand);
  border-color: var(--ds-accent);
  border-color: color-mix(in srgb, var(--ds-accent) 55%, var(--ds-border));
  background: transparent;
}
html .btn-outline-primary:hover, html .btn-outline-primary:focus {
  color: var(--ds-on-accent);
  border-color: var(--ds-accent);
  background: var(--ds-accent);
}
html .btn-secondary, html .btn-outline-secondary, html .btn-light {
  background: var(--ds-surface);
  border-color: var(--ds-border-strong);
  color: var(--ds-ink-700);
  box-shadow: none;
}
html .btn-secondary:hover, html .btn-outline-secondary:hover, html .btn-light:hover {
  background: var(--ds-surface-2);
  border-color: var(--ds-border-strong);
  color: var(--ds-ink-900);
}
.text-primary, .link-primary, .btn-link { color: var(--ds-brand) !important; }
.bg-primary, .badge.bg-primary { background: var(--ds-accent) !important; color: var(--ds-on-accent) !important; }
.border-primary { border-color: var(--ds-accent) !important; }
.progress { background: var(--ds-surface-3); }
.progress-bar { background: var(--ds-accent); }

/* Precision shell. */
html .navbar {
  background: var(--pim-nav) !important;
  border-bottom: 1px solid var(--ds-border) !important;
  box-shadow: 0 8px 30px transparent !important;
  box-shadow: 0 8px 30px color-mix(in srgb, var(--pim-shadow-color) 62%, transparent) !important;
  position: relative;
  z-index: 2;
  overflow: visible;
  -webkit-backdrop-filter: blur(18px) saturate(145%);
  backdrop-filter: blur(18px) saturate(145%);
}
html .navbar .brand-text { color: var(--ds-ink-900); letter-spacing: 0.055em; text-transform: uppercase; }
html .navbar .nav-link { color: var(--ds-ink-500) !important; }
html .navbar .nav-link:hover, html .navbar .nav-link:focus-visible {
  color: var(--ds-ink-900) !important;
  background: var(--ds-surface-2);
}
html .navbar .nav-link.active { color: var(--ds-brand) !important; background: var(--ds-brand-soft); }
/* Underline accent only — never the .dropdown-toggle caret (shares ::after). */
html .navbar .navbar-nav .nav-link:not(.dropdown-toggle)::after { background: var(--ds-accent); }
html header.site-shell-header { isolation: isolate; }
html .navbar-toggler {
  color: var(--ds-ink-900) !important;
  background: var(--ds-surface-2);
  border-color: var(--ds-border-strong);
}
/* Draw the three bars with currentColor instead of filtering Bootstrap's
   white SVG. The old dark-mode invert turned that already-white icon black. */
html .navbar-toggler-icon {
  width: 24px;
  height: 24px;
  color: inherit;
  background-image:
    linear-gradient(currentColor, currentColor),
    linear-gradient(currentColor, currentColor),
    linear-gradient(currentColor, currentColor) !important;
  background-repeat: no-repeat;
  background-position: center 5px, center 11px, center 17px;
  background-size: 22px 2px;
  filter: none !important;
  opacity: .92;
}
@media (prefers-color-scheme: dark) {
  html:not([data-theme]) .navbar-toggler { color: var(--ds-ink-900) !important; }
  html:not([data-theme]) .navbar-toggler-icon { filter: none !important; opacity: .92; }
}
html .navbar .dropdown-menu,
html .sport-picker-panel,
html .theme-picker-panel {
  color: var(--ds-ink-700);
  background: var(--ds-surface) !important;
  border: 1px solid var(--ds-border) !important;
  box-shadow: var(--ds-shadow-lg);
}
html .navbar .dropdown-item { color: var(--ds-ink-700); }
html .navbar .dropdown-item:hover, html .navbar .dropdown-item:focus {
  color: var(--ds-ink-900);
  background: var(--ds-surface-2);
}
.navbar-logo { border: 1px solid var(--ds-border); box-shadow: none; }
.sport-context-bar {
  color: var(--ds-ink-600);
  background: var(--ds-surface-2) !important;
  border-bottom: 1px solid var(--ds-border);
  position: relative;
  z-index: 1;
}
.sport-ctx-name { color: var(--ds-ink-900) !important; }
.sport-ctx-switch {
  min-height: 44px;
  padding-inline: var(--ds-space-3);
  color: var(--ds-brand) !important;
  border-color: var(--ds-accent) !important;
  border-color: color-mix(in srgb, var(--ds-accent) 55%, var(--ds-border)) !important;
}
.sport-badge,
.features-label,
.feature-card-icon--blue,
.feature-list-icon {
  color: var(--ds-brand) !important;
  background: var(--ds-brand-soft) !important;
}
.stat-card .stat-value,
.features-title { color: var(--ds-ink-900) !important; }
.page-header .header-btn.primary,
.step-num,
.badge-primary {
  color: var(--ds-on-accent) !important;
  background: var(--ds-accent) !important;
  border-color: var(--ds-accent) !important;
}
.sport-pick-check { color: var(--ds-brand) !important; }

/* Both controls also carry Bootstrap's .dropdown-toggle class. A legacy
   navbar rule paints every dropdown toggle white !important, which produced
   white-on-light labels after the Precision shell became a light surface. */
html .navbar .btn-sport-selector,
html .navbar .theme-selector-btn {
  color: var(--ds-ink-900) !important;
  background: var(--ds-surface-2) !important;
  border: 1px solid var(--ds-border-strong) !important;
}
html .navbar .btn-sport-selector:hover,
html .navbar .btn-sport-selector:focus-visible,
html .navbar .btn-sport-selector.show,
html .navbar .theme-selector-btn:hover,
html .navbar .theme-selector-btn:focus-visible,
html .navbar .theme-selector-btn[aria-expanded="true"] {
  color: var(--ds-ink-900) !important;
  background: var(--ds-surface-3) !important;
  border-color: var(--ds-accent) !important;
  box-shadow: 0 0 0 3px var(--ds-brand-ring) !important;
}
html .navbar .btn-sport-selector .sport-name-label,
html .navbar .btn-sport-selector .sport-sel-chevron,
html .navbar .theme-selector-btn > * { color: inherit; }

/* The navbar's backdrop-filter creates a stacking context. Give that whole
   row precedence over the later sport-context sibling so search/notification
   panels cannot be overpainted by the context bar or Switch control. */
html .navbar .msm-nav-tools { z-index: 1200; }
html .navbar .msm-panel { z-index: 1300; }

/* Theme picker — 44px control and explicit radio-like selection state. */
.theme-selector-wrapper { display: flex; align-items: center; }
.theme-selector-btn {
  min-height: 44px;
  gap: var(--ds-space-2);
  padding: var(--ds-space-2) var(--ds-space-3);
  color: var(--ds-ink-600);
  background: var(--ds-surface-2);
  border: 1px solid var(--ds-border);
}
.theme-selector-btn:hover, .theme-selector-btn:focus, .theme-selector-btn[aria-expanded="true"] {
  color: var(--ds-ink-900);
  background: var(--ds-surface-3);
  border-color: var(--ds-border-strong);
}
.theme-picker-panel { width: 264px; max-width: calc(100vw - 2 * var(--ds-space-4)); padding: var(--ds-space-2); }
.theme-picker-heading {
  padding: var(--ds-space-1) var(--ds-space-2) var(--ds-space-2);
  color: var(--ds-ink-500);
  font-size: var(--ds-type-caption);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.theme-choice {
  display: grid;
  grid-template-columns: 1.25rem minmax(0, 1fr) 1rem;
  align-items: center;
  gap: var(--ds-space-2);
  width: 100%;
  min-height: 52px;
  /* Bootstrap's .dropdown-item forces nowrap, which clipped "Follow phone or
     computer" at the panel edge — let the description wrap instead. */
  white-space: normal;
}
.theme-choice > i:first-child { color: var(--ds-ink-500); text-align: center; }
.theme-choice span { display: flex; flex-direction: column; min-width: 0; }
.theme-choice strong { color: inherit; font-size: var(--ds-type-body-small); line-height: 1.25; }
.theme-choice small { color: var(--ds-ink-500); font-size: var(--ds-type-caption); line-height: 1.3; }
.theme-choice-check { color: var(--ds-accent); }
.theme-choice.is-selected { color: var(--ds-ink-900); background: var(--ds-brand-soft); }

/* Content surfaces used across the 111 Razor templates. */
.card, .content-card, .auth-card, .feature-card, .stat-card, .status-card,
.filter-card, .form-card, .table-card, .detail-card, .info-card, .resource-card,
.match-card, .activity-card, .venue-card, .marketplace-card, .seller-card,
.payment-card, .transaction-card, .tournament-info-card, .users-card,
.actions-card, .obs-card, .an-card, .acct-card, .co-card, .ml-card,
.rbx-card, .lh-card, .avail-card, .capacity-card, .feed-group-card,
.rankings-card, .post-card, .mobile-set-card, .mobile-player-card,
.mobile-user-card, .ms-filter-card, .my-match-card, .all-match-card {
  background-color: var(--ds-surface) !important;
  border-color: var(--ds-border) !important;
  color: var(--ds-ink-700);
  box-shadow: var(--ds-shadow-xs);
}
.card, .content-card, .auth-card, .feature-card, .stat-card, .status-card,
.filter-card, .form-card, .table-card, .detail-card, .info-card, .resource-card {
  border-radius: var(--ds-radius-lg);
}
.card > .card-header, .card > .card-footer, .modal-header, .modal-footer,
.accordion-header, .accordion-button, .offcanvas-header {
  color: var(--ds-ink-900);
  background: var(--ds-surface) !important;
  border-color: var(--ds-border) !important;
}
/* Bootstrap fill/ink utilities left on a header that THIS system renders as a
   plain surface. The rule above wins the *background* on specificity but
   declares `color` WITHOUT !important, so Bootstrap's `.text-white` survives
   and paints #ffffff on the light surface — 1.0:1 in the DEFAULT theme.
   `.bg-primary` is no better: it forces --ds-on-accent (#101014) onto the dark
   surface once the canvas flips. Header ink must follow the surface that is
   actually rendered, in both themes. */
html :is(.card > .card-header, .modal-header, .offcanvas-header, .accordion-header):is(.text-white, .text-white-50, .bg-primary, .bg-secondary, .bg-success, .bg-danger, .bg-warning, .bg-info, .bg-dark, .bg-black) {
  color: var(--ds-ink-900) !important;
}
/* A `.bg-danger` header still means destructive/live, so it keeps its semantic
   weight as the soft error surface with the ink paired to that surface in both
   themes — the same treatment Views/Admin/Locations.cshtml already applies
   locally to its delete modals. */
html :is(.card > .card-header, .modal-header).bg-danger {
  background: var(--ds-error-surface) !important;
  border-color: var(--ds-error-border) !important;
  color: var(--ds-error) !important;
}
.card-interactive:hover, a > .card:hover, a.card:hover, .ds-hover-lift:hover {
  border-color: var(--ds-border) !important;
  border-color: color-mix(in srgb, var(--ds-accent) 44%, var(--ds-border)) !important;
  box-shadow: var(--ds-shadow-md);
}
.page-header {
  position: relative;
  overflow: hidden;
  /* Precision page headers are semantic surfaces, not sport gradients. Legacy
     child styles that use the inverse alias therefore need the current surface
     foreground (dark in light mode, light in dark mode). */
  --ds-text-inverse: var(--ds-ink-900);
  color: var(--ds-ink-700);
  background: var(--ds-surface) !important;
  border: 1px solid var(--ds-border);
  box-shadow: var(--ds-shadow-xs);
}
.page-header::before { display: none; }
.page-header::after {
  inset: 0 auto 0 0;
  width: 4px;
  height: auto;
  background: var(--ds-accent);
  opacity: 1;
}
.page-header h1, .page-header .page-title { color: var(--ds-ink-900) !important; }
.page-header p, .page-header .page-subtitle { color: var(--ds-ink-500) !important; }
.page-header .header-btn:not(.primary),
.page-header .back-btn {
  color: var(--ds-ink-700) !important;
  background: var(--ds-surface-2) !important;
  border-color: var(--ds-border-strong) !important;
}
.page-header .header-btn:not(.primary):hover,
.page-header .header-btn:not(.primary):focus-visible,
.page-header .back-btn:hover,
.page-header .back-btn:focus-visible {
  color: var(--ds-ink-900) !important;
  background: var(--ds-surface-3) !important;
  border-color: var(--ds-accent) !important;
}
.page-header h1:not(.d-flex):not(.d-inline-flex)::after,
.page-header .page-title:not(.d-flex):not(.d-inline-flex)::after { display: none; }

/* Bootstrap component parity. */
.dropdown-menu, .modal-content, .offcanvas, .popover, .toast, .accordion-item,
.list-group-item, .page-link {
  color: var(--ds-ink-700);
  background-color: var(--ds-surface);
  border-color: var(--ds-border);
}
.modal-header, .modal-footer, .offcanvas-header { border-color: var(--ds-border); }
.modal-title, .offcanvas-title, .popover-header { color: var(--ds-ink-900); }
.popover-header { background: var(--ds-surface-2); border-color: var(--ds-border); }
.popover-body { color: var(--ds-ink-600); }
.list-group-item-action:hover, .list-group-item-action:focus,
.dropdown-item:hover, .dropdown-item:focus, .page-link:hover {
  color: var(--ds-ink-900);
  background: var(--ds-surface-2);
}
.page-item.disabled .page-link { color: var(--ds-ink-400); background: var(--ds-surface-2); }
.nav-tabs, .nav-tabs .nav-link { border-color: var(--ds-border); }
.nav-tabs .nav-link { min-height: 44px; display: inline-flex; align-items: center; }
.nav-tabs .nav-link.active { color: var(--ds-brand) !important; border-color: var(--ds-accent); }
.breadcrumb-item + .breadcrumb-item::before { color: var(--ds-ink-400); }
.bg-white, .bg-light, .bg-body-tertiary, .text-bg-light { background-color: var(--ds-surface) !important; color: var(--ds-ink-700) !important; }
.bg-light, .bg-body-tertiary { background-color: var(--ds-surface-2) !important; }
.text-dark { color: var(--ds-ink-900) !important; }
.text-secondary { color: var(--ds-ink-500) !important; }
.border, .border-top, .border-end, .border-bottom, .border-start { border-color: var(--ds-border) !important; }

/* Inputs and data-dense surfaces. */
.form-control, .form-select, .form-check-input, .input-group-text {
  color: var(--ds-ink-900);
  background-color: var(--ds-surface);
  border-color: var(--ds-border-strong);
}
.form-control:focus, .form-select:focus, .form-check-input:focus {
  border-color: var(--ds-accent) !important;
  box-shadow: 0 0 0 3px var(--ds-brand-ring) !important;
}
.form-check-input:checked { background-color: var(--ds-accent); border-color: var(--ds-accent); }
/* The switch TRACK is repainted for dark above, but Bootstrap bakes the OFF-state
   knob into a data-URI SVG as a fixed rgba(0,0,0,.25) circle. On the #1c1c22 dark
   track that composites to ~#151519 (about 1.09:1), so every OFF switch reads as an
   empty pill with no thumb. Repaint the knob for dark; the checked knob already sits
   on the accent fill and stays legible. */
html[data-theme="dark"] .form-switch .form-check-input:not(:checked) {
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.55%29'/%3e%3c/svg%3e");
}
@media (prefers-color-scheme: dark) {
  html:not([data-theme]) .form-switch .form-check-input:not(:checked) {
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.55%29'/%3e%3c/svg%3e");
  }
}
.form-control:disabled, .form-select:disabled, .form-control[readonly] { background: var(--ds-surface-2); color: var(--ds-ink-500); }
.form-control::placeholder { color: var(--ds-ink-400); }
select option { color: var(--ds-ink-900); background: var(--ds-surface); }
.table {
  --bs-table-bg: transparent;
  --bs-table-color: var(--ds-ink-700);
  --bs-table-border-color: var(--ds-border);
  --bs-table-striped-bg: var(--ds-surface-2);
  --bs-table-striped-color: var(--ds-ink-700);
  --bs-table-hover-bg: var(--ds-brand-soft);
  --bs-table-hover-color: var(--ds-ink-900);
  color: var(--ds-ink-700);
}
.table > :not(caption) > * > * { color: inherit; background-color: var(--bs-table-bg); border-color: var(--ds-border); }
.table thead th, .table > :not(caption) > * > th { color: var(--ds-ink-500); background: var(--ds-surface-2); }
.table-striped > tbody > tr:nth-of-type(odd) > * { background-color: var(--ds-surface-2); color: var(--ds-ink-700); }
code, pre, kbd { border-color: var(--ds-border); }

/* Leaflet's default popup dismiss target is 24px; preserve its visual glyph
   while expanding the interactive box to the product touch-target contract. */
.leaflet-popup-close-button {
  width: 44px !important;
  height: 44px !important;
  line-height: 44px !important;
}

/* Leaflet ships its popup chrome with a hardcoded white surface. Marker popups
   are authored with --ds-ink-* body copy, so in dark mode that ink lands on
   Leaflet's white and drops to ~1.5:1 (the venue popup's city line and star
   rating disappear). Theme the surface itself so every token injected into a
   popup pairs correctly — this covers all ten Leaflet-bearing views at once. */
.leaflet-popup-content-wrapper,
.leaflet-popup-tip {
  background: var(--ds-surface);
  color: var(--ds-ink-900);
}
.leaflet-popup-content-wrapper { border: 1px solid var(--ds-border); }
.leaflet-popup-close-button { color: var(--ds-ink-500) !important; }
code, pre { color: var(--ds-ink-700); background: var(--ds-surface-2); }

/* Status semantics retain meaning and contrast in both modes. */
.alert-success, .badge-soft-success { color: var(--ds-success); background: var(--ds-success-surface); border-color: var(--ds-success-border); }
.alert-danger, .badge-soft-danger { color: var(--ds-error); background: var(--ds-error-surface); border-color: var(--ds-error-border); }
.alert-warning, .badge-soft-warning { color: var(--ds-warning); background: var(--ds-warning-surface); border-color: var(--ds-warning-border); }
.alert-info, .badge-soft-info { color: var(--ds-info); background: var(--ds-info-surface); border-color: var(--ds-info-border); }
.badge-soft-neutral { color: var(--ds-ink-700); background: var(--ds-surface-2); border-color: var(--ds-border); }
.text-success { color: var(--ds-success) !important; }
.text-danger { color: var(--ds-error) !important; }
.text-warning { color: var(--ds-warning) !important; }

/* Sport-gradient hero fills: --sport-primary/secondary alias the brand tokens,
   which flip LIGHTER in dark mode (#b83d00 -> #ff7733), so the fixed white ink
   that passes AA on the light-mode rust gradient drops to ~2:1 on the dark-mode
   peach. Give dark mode a deep sport-tinted fill instead — each sport's hue is
   mixed toward near-black, so identity survives and white ink stays >= 7:1.
   .page-header consumes --sport-hero-gradient natively; page-local heroes that
   hardcode the same gradient are rescued by name below. */
html[data-theme="dark"] {
  --sport-hero-gradient: linear-gradient(135deg,
      color-mix(in srgb, var(--sport-secondary) 42%, #171210) 0%,
      color-mix(in srgb, var(--sport-primary) 36%, #141009) 100%);
}
@media (prefers-color-scheme: dark) {
  html:not([data-theme]) {
    --sport-hero-gradient: linear-gradient(135deg,
        color-mix(in srgb, var(--sport-secondary) 42%, #171210) 0%,
        color-mix(in srgb, var(--sport-primary) 36%, #141009) 100%);
  }
}
/* The tournament page's full-width sport-filled BANDS and its two selected
   controls. On the dark canvas a vivid orange band reads as glare rather than as
   identity, so they take the same muted hero gradient the leaderboard's rankings
   header already uses — one token drives all of them, so they cannot drift apart.
   Light mode is untouched: every one of these keeps its vivid sport fill there. */
html[data-theme="dark"] .match-page-header,
html[data-theme="dark"] .rankings-card > .card-header,
html[data-theme="dark"] .pl-list-header,
html[data-theme="dark"] .all-matches-header,
html[data-theme="dark"] .my-matches-header,
html[data-theme="dark"] .tournament-tab-nav .nav-link.active,
html[data-theme="dark"] .filter-tab.active {
  background: var(--sport-hero-gradient) !important;
}
@media (prefers-color-scheme: dark) {
  html:not([data-theme]) .match-page-header,
  html:not([data-theme]) .rankings-card > .card-header,
  html:not([data-theme]) .pl-list-header,
  html:not([data-theme]) .all-matches-header,
  html:not([data-theme]) .my-matches-header,
  html:not([data-theme]) .tournament-tab-nav .nav-link.active,
  html:not([data-theme]) .filter-tab.active {
    background: var(--sport-hero-gradient) !important;
  }
}
/* Ink must move with the fill. Everything above previously sat on a BRIGHT fill and
   was therefore given the dark on-brand / on-accent ink (#17171c and #101014) by the
   groups further down this file. On the muted gradient that ink is near-invisible,
   so these selectors take the light on-sport pairing instead. Higher specificity
   than the `html .selector` groups they override, and !important because those
   groups use it too. The active filter chip keeps an accent-tinted border: with the
   fill no longer vivid, the border is what still reads as "selected" beside the
   plain dark inactive chips. */
html[data-theme="dark"] .tournament-tab-nav .nav-link.active,
html[data-theme="dark"] .filter-tab.active,
html[data-theme="dark"] .all-matches-header h2,
html[data-theme="dark"] .all-matches-header p,
html[data-theme="dark"] .all-matches-stats .stat-number,
html[data-theme="dark"] .all-matches-stats .stat-label,
html[data-theme="dark"] .my-matches-header h2,
html[data-theme="dark"] .my-matches-header p,
html[data-theme="dark"] .my-matches-header .stat-number,
html[data-theme="dark"] .my-matches-header .stat-label {
  color: var(--ds-on-sport) !important;
}
html[data-theme="dark"] .tournament-tab-nav .nav-link.active {
  box-shadow: none;
}
html[data-theme="dark"] .filter-tab.active {
  border-color: transparent !important;
  border-color: color-mix(in srgb, var(--ds-accent) 45%, transparent) !important;
}
@media (prefers-color-scheme: dark) {
  html:not([data-theme]) .tournament-tab-nav .nav-link.active,
  html:not([data-theme]) .filter-tab.active,
  html:not([data-theme]) .all-matches-header h2,
  html:not([data-theme]) .all-matches-header p,
  html:not([data-theme]) .all-matches-stats .stat-number,
  html:not([data-theme]) .all-matches-stats .stat-label,
  html:not([data-theme]) .my-matches-header h2,
  html:not([data-theme]) .my-matches-header p,
  html:not([data-theme]) .my-matches-header .stat-number,
  html:not([data-theme]) .my-matches-header .stat-label {
    color: var(--ds-on-sport) !important;
  }
  html:not([data-theme]) .tournament-tab-nav .nav-link.active {
    box-shadow: none;
  }
  html:not([data-theme]) .filter-tab.active {
    border-color: transparent !important;
    border-color: color-mix(in srgb, var(--ds-accent) 45%, transparent) !important;
  }
}

/* ── The remaining sport-filled bands ──────────────────────────────────────────
   Everywhere else a full-width band is painted with the vivid sport gradient. On
   the dark canvas they read as glare, exactly like the tournament ones above, so
   they take the same muted hero gradient. One token still drives every band on
   the site.

   Two groups, and the difference is entirely about INK:

   • The registration and payment bands already sat in the on-brand ink group
     further down this file. Somebody hit the white-on-bright-orange contrast
     problem on precisely these elements and solved it by DARKENING the ink to
     #17171c, leaving the vivid fill in place — correct for that fill, invisible
     on this one. Their ink moves below.
   • .head-to-head__hero, .table-card .card-header, .content-card
     .card-header-gradient and the two bracket headers already declare light ink
     (--ds-on-sport, or --ds-text-inverse which is a fixed #ffffff), so they need
     the background and nothing else.

   ⚠️ sport-themes.css re-declares .table-card .card-header with !important, so
   this rule needs BOTH the higher specificity it has here and its own !important
   to win. .page-header is deliberately absent: it stopped being a sport gradient
   and is a semantic surface in both themes already.

   Light mode is untouched — every one of these keeps its vivid fill there. */
html[data-theme="dark"] .register-hero,
html[data-theme="dark"] .payment-card .payment-header,
html[data-theme="dark"] .payment-status-header.pending,
html[data-theme="dark"] .tournament-info-header,
html[data-theme="dark"] .head-to-head__hero,
html[data-theme="dark"] .table-card .card-header,
html[data-theme="dark"] .content-card .card-header-gradient,
html[data-theme="dark"] .bracket-header-final,
html[data-theme="dark"] .bracket-header-main {
  background: var(--sport-hero-gradient) !important;
}
/* The ink move, for the four that were given dark on-brand ink to survive the
   bright fill. Specificity clears the `html .selector` group below, and the
   !important matches the one that group uses. */
html[data-theme="dark"] :is(.register-hero, .payment-card .payment-header, .payment-status-header.pending, .tournament-info-header),
html[data-theme="dark"] :is(.register-hero, .payment-card .payment-header, .payment-status-header.pending, .tournament-info-header) :is(h1, h2, h5, p, strong, i, .tournament-name, .spinner-border) {
  color: var(--ds-on-sport) !important;
}
@media (prefers-color-scheme: dark) {
  html:not([data-theme]) .register-hero,
  html:not([data-theme]) .payment-card .payment-header,
  html:not([data-theme]) .payment-status-header.pending,
  html:not([data-theme]) .tournament-info-header,
  html:not([data-theme]) .head-to-head__hero,
  html:not([data-theme]) .table-card .card-header,
  html:not([data-theme]) .content-card .card-header-gradient,
  html:not([data-theme]) .bracket-header-final,
  html:not([data-theme]) .bracket-header-main {
    background: var(--sport-hero-gradient) !important;
  }
  html:not([data-theme]) :is(.register-hero, .payment-card .payment-header, .payment-status-header.pending, .tournament-info-header),
  html:not([data-theme]) :is(.register-hero, .payment-card .payment-header, .payment-status-header.pending, .tournament-info-header) :is(h1, h2, h5, p, strong, i, .tournament-name, .spinner-border) {
    color: var(--ds-on-sport) !important;
  }
}

/* Small solid sport-fill controls (save CTA, set-number chips) keep the vivid
   fill in dark mode but take the system's dark on-accent ink, matching how
   .btn-primary already pairs on the bright accent. */
html[data-theme="dark"] .btn-save,
html[data-theme="dark"] .add-set-btn,
html[data-theme="dark"] .set-number,
html[data-theme="dark"] .mobile-set-number,
html[data-theme="dark"] .btn-gradient,
html[data-theme="dark"] .btn-gradient:hover {
  color: var(--ds-on-accent) !important;
}
@media (prefers-color-scheme: dark) {
  html:not([data-theme]) .btn-save,
  html:not([data-theme]) .add-set-btn,
  html:not([data-theme]) .set-number,
  html:not([data-theme]) .mobile-set-number,
  html:not([data-theme]) .btn-gradient,
  html:not([data-theme]) .btn-gradient:hover {
    color: var(--ds-on-accent) !important;
  }
}

/* Bootstrap's outline-warning/danger keep literal #ffc107/#dc3545 inks that
   fail on both canvases (yellow-on-white 1.6:1; red-on-dark 3.7-4.2:1).
   Route them through the semantic status inks, soft-tint on hover. */
html .btn-outline-danger {
  color: var(--ds-error) !important;
  border-color: var(--ds-border-strong) !important;
  border-color: color-mix(in srgb, var(--ds-error) 45%, var(--ds-border-strong)) !important;
}
html .btn-outline-danger:hover, html .btn-outline-danger:focus,
html .btn-outline-danger:active {
  color: var(--ds-error) !important;
  background: var(--ds-error-surface) !important;
  border-color: var(--ds-error-border) !important;
}
html .btn-outline-warning {
  color: var(--ds-warning) !important;
  border-color: var(--ds-border-strong) !important;
  border-color: color-mix(in srgb, var(--ds-warning) 45%, var(--ds-border-strong)) !important;
}
html .btn-outline-warning:hover, html .btn-outline-warning:focus,
html .btn-outline-warning:active {
  color: var(--ds-warning) !important;
  background: var(--ds-warning-surface) !important;
  border-color: var(--ds-warning-border) !important;
}
/* Same literal-ink problem for outline-success (Bootstrap's #198754 reads
   4.0:1 on the dark canvas); used by Marketplace "Relist item" / "Mark sold". */
html .btn-outline-success {
  color: var(--ds-success) !important;
  border-color: var(--ds-border-strong) !important;
  border-color: color-mix(in srgb, var(--ds-success) 45%, var(--ds-border-strong)) !important;
}
html .btn-outline-success:hover, html .btn-outline-success:focus,
html .btn-outline-success:active {
  color: var(--ds-success) !important;
  background: var(--ds-success-surface) !important;
  border-color: var(--ds-success-border) !important;
}

/* Checked toggle tiles (btn-check + outline label, e.g. the Create-Tournament
   sport picker): Bootstrap's checked fill inherited a mismatched ink pairing
   (near-black on-accent ink over the dark rust brand fill, 2.3:1). Use the
   system CTA pairing — vivid accent fill + dark on-accent ink in both modes. */
html .btn-check:checked + .btn,
html .sport-grid-selector .btn-check:checked + .btn-outline-primary {
  background: var(--ds-accent) !important;
  border-color: var(--ds-accent) !important;
  color: var(--ds-on-accent) !important;
}

/* Bootstrap contextual background utilities predate the token layer and were
   never reskinned, so `bg-light`/`bg-white` render as fixed light islands — and
   `bg-warning` (yellow) paired with `.text-dark` flips to near-white ink — in
   dark mode. Map them onto the semantic surfaces so any remaining Bootstrap
   markup follows the theme in both modes. */
html .bg-light { background-color: var(--ds-surface-2) !important; }
html .bg-white { background-color: var(--ds-surface) !important; }
html .badge.bg-light, html .badge.bg-white { color: var(--ds-ink-700) !important; }
/* Yellow warning fills need a dark-safe pairing: bare Bootstrap yellow with
   .text-dark is unreadable once the ink flips. Use the soft-warning chip. */
html .bg-warning {
  background: var(--ds-warning-surface) !important;
  color: var(--ds-warning) !important;
  border-color: var(--ds-warning-border);
}
/* Bootstrap light table + alert skins: neutralize the fixed light variables. */
html .table-light {
  --bs-table-bg: var(--ds-surface-2);
  --bs-table-color: var(--ds-ink-700);
  --bs-table-border-color: var(--ds-border);
}
/* Contextual ROW skins (advancing/runner-up standings etc.): the bundled
   Bootstrap 5.0/5.1 compiles these with LITERAL `color:#000` on the cells
   (only 5.2+ routes ink through --bs-table-color), so black text lands on
   dark surfaces (~1.2:1). Override color/background directly with the
   semantic status pairs, which flip per theme. */
html .table-success, html .table-success > th, html .table-success > td {
  color: var(--ds-success) !important;
  background-color: var(--ds-success-surface) !important;
  border-color: var(--ds-success-border);
  --bs-table-bg: var(--ds-success-surface);
  --bs-table-color: var(--ds-success);
}
html .table-info, html .table-info > th, html .table-info > td {
  color: var(--ds-info) !important;
  background-color: var(--ds-info-surface) !important;
  border-color: var(--ds-info-border);
  --bs-table-bg: var(--ds-info-surface);
  --bs-table-color: var(--ds-info);
}
html .table-warning, html .table-warning > th, html .table-warning > td {
  color: var(--ds-warning) !important;
  background-color: var(--ds-warning-surface) !important;
  border-color: var(--ds-warning-border);
  --bs-table-bg: var(--ds-warning-surface);
  --bs-table-color: var(--ds-warning);
}
html .table-danger, html .table-danger > th, html .table-danger > td {
  color: var(--ds-error) !important;
  background-color: var(--ds-error-surface) !important;
  border-color: var(--ds-error-border);
  --bs-table-bg: var(--ds-error-surface);
  --bs-table-color: var(--ds-error);
}
html .alert-light {
  background: var(--ds-surface-2) !important;
  color: var(--ds-ink-700) !important;
  border-color: var(--ds-border) !important;
}

/* Compatibility bridge for the small set of controls that put text directly
   on a solid semantic/brand color. They must use the paired foreground rather
   than the fixed white emphasis alias introduced above. Keep these centralized
   until their feature styles are migrated to the semantic component API. */
html .ext-brand--apple {
  color: var(--ds-provider-on-dark) !important;
  background: var(--ds-provider-apple-surface) !important;
}
html .ext-brand--facebook,
html .loc-request-banner .lrb-share,
html .user-search-result .user-avatar:not(img) { color: var(--ds-on-info) !important; }
html .live-share-banner .lsb-stop { color: var(--ds-on-success) !important; }
html .sold-overlay span,
html .msm-bell-badge { color: var(--ds-on-error) !important; }
html .pl-rank.rank-3 { color: var(--ds-on-warning) !important; }
html .about-step-circle,
html .obs-btn,
html .fr-tab.active .fr-count,
html .fr-btn-primary,
html .scroll-date-badge { color: var(--ds-on-brand) !important; }
html .view-toggle .btn.active,
html .share-toast:not(.share-toast--warning) { color: var(--ds-on-brand) !important; }

/* Legacy solid status badges and metric glyphs. Their fills become lighter in
   dark mode, so a fixed white foreground is not a safe cross-theme pairing. */
html .badge-success { color: var(--ds-on-success) !important; }
html .badge-danger { color: var(--ds-on-error) !important; }
html .badge-warning { color: var(--ds-on-warning) !important; }
html .badge-info { color: var(--ds-on-info) !important; }
html .stat-card .stat-icon.blue { color: var(--ds-on-sport) !important; }
html .stat-card .stat-icon.green { color: var(--ds-on-success) !important; }
html .stat-card .stat-icon.orange { color: var(--ds-on-warning) !important; }
html .stat-card .stat-icon.purple { color: var(--ds-on-accent) !important; }
html .stat-card .stat-icon.red { color: var(--ds-on-error) !important; }
html .obs-kpi.t-blue .ic,
html .obs-kpi.t-teal .ic,
html .obs-kpi.t-indigo .ic { color: var(--ds-on-info) !important; }
html .obs-kpi.t-green .ic { color: var(--ds-on-success) !important; }
html .obs-kpi.t-amber .ic { color: var(--ds-on-warning) !important; }
html .obs-kpi.t-red .ic { color: var(--ds-on-error) !important; }
html .obs-kpi.t-purple .ic { color: var(--ds-on-accent) !important; }

/* Admin list actions use different semantic fills for the same legacy class
   names; scope each pairing to the owning list instead of styling by name. */
html .users-card .action-btn.edit:hover { color: var(--ds-on-info) !important; }
html .users-card .action-btn.delete:hover { color: var(--ds-on-error) !important; }
html .users-card .action-btn.view:hover { color: var(--ds-on-success) !important; }
html .table-card .action-btn.edit:hover { color: var(--ds-on-warning) !important; }
html .table-card .action-btn.delete:hover { color: var(--ds-on-error) !important; }
html .btn-refund:hover,
html .remove-set-btn:hover { color: var(--ds-on-error) !important; }

/* Tournament registration/payment states place copy directly on solid status
   fills. Keep soft alert surfaces on their normal semantic ink. */
html .free-badge,
html .free-badge h2,
html .payment-status-header.success,
html .payment-status-header.success h1,
html .payment-status-header.success p,
html .payment-status-header.success p strong,
html .payment-status-header.success .status-icon-wrapper i,
html .payment-status-header.success .spinner-border,
html .payment-details-header,
html .payment-details-header h5,
html .payment-container .action-btn.success,
html .payment-container .action-btn.success:hover { color: var(--ds-on-success) !important; }
html .payment-status-header.failed,
html .payment-status-header.failed h1,
html .payment-status-header.failed p,
html .payment-status-header.failed p strong,
html .payment-status-header.failed .status-icon-wrapper i,
html .payment-status-header.failed .spinner-border { color: var(--ds-on-error) !important; }
html .payment-status-header.unknown,
html .payment-status-header.unknown h1,
html .payment-status-header.unknown p,
html .payment-status-header.unknown p strong,
html .payment-status-header.unknown .status-icon-wrapper i,
html .payment-status-header.unknown .spinner-border { color: var(--ds-warning) !important; }

/* Bracket/result markers retain their medal or result semantics in both modes. */
html .match-result-badge.scheduled,
html .match-stage-icon.group,
html .match-status-badge.scheduled { color: var(--ds-on-brand) !important; }
html .position-badge,
html .points-badge { color: var(--ds-on-brand) !important; }
html .msm-presence-pin .ini,
html .msm-mappin .ini { color: var(--ds-on-neutral-strong) !important; }
html .player-photo-placeholder.you,
html .match-result-badge.victory,
html .match-player-placeholder.winner,
html .match-status-badge.completed,
html .winner-avatar:not(.champion):not(.champion-avatar):not(.bronze-avatar),
html .player-avatar-knockout.winner-avatar:not(.champion-avatar):not(.bronze-avatar) { color: var(--ds-on-success) !important; }
html .vs-circle,
html .match-result-badge.pending,
html .match-stage-icon.knockout,
html .match-vs-circle,
html .match-status-badge.in-progress,
html .bronze-avatar { color: var(--ds-on-warning) !important; }
html .player-avatar-knockout:not(.placeholder):not(.winner-avatar):not(.champion-avatar):not(.bronze-avatar) { color: var(--ds-on-sport) !important; }
html .existing-photo.marked-for-removal::after { color: var(--ds-on-error) !important; }

/* Neutral fills invert with the theme; their paired ink must do the same. */
html .badge-secondary,
html .tooltip-custom::before,
html .player-avatar-knockout.placeholder { color: var(--ds-on-neutral-strong) !important; }

/* ── Sport/brand fills paired with a non-flipping white ink ─────────────────
   --ds-text-inverse resolves to --ds-on-emphasis -> --ds-on-dark (#ffffff) and is
   deliberately fixed, but the sport gradients underneath it are not: --sport-primary
   and --sport-secondary alias --ds-brand/--ds-brand-strong, which lighten from
   #b83d00 to #ff7733 once the canvas flips. Every component below therefore painted
   white-on-bright-orange (~2.0-2.7:1) in dark mode. --ds-on-brand (= --pim-text-inverse)
   is the ink paired to exactly this fill: #ffffff in light, #17171c in dark, so one
   rule corrects dark without regressing light. */
html .tournament-info-header,
html .tournament-info-header h5,
html .payment-status-header.pending,
html .payment-status-header.pending h1,
html .payment-status-header.pending p,
html .payment-status-header.pending p strong,
html .payment-status-header.pending .status-icon-wrapper i,
html .payment-status-header.pending .spinner-border,
html .payment-container .action-btn.primary,
html .payment-container .action-btn.primary:hover,
html .register-hero,
html .register-hero h1,
html .register-hero .tournament-name,
html .payment-card .payment-header,
html .payment-card .payment-header i,
html .payment-card .payment-header h2,
html .my-matches-header h2,
html .my-matches-header p,
html .my-matches-header .stat-number,
html .my-matches-header .stat-label,
html .all-matches-header h2,
html .all-matches-header p,
html .all-matches-stats .stat-number,
html .all-matches-stats .stat-label,
html .match-stage-badge,
html .match-action-btn.primary,
html .match-action-btn.primary:hover,
html .filter-tab.active,
html .pl-rank:not(.rank-1):not(.rank-2):not(.rank-3),
html .pl-avatar-init,
html .pl-rating,
html .pl-rating i,
html .player-photo-placeholder.opponent-ph,
html .match-player-placeholder:not(.winner) { color: var(--ds-on-brand) !important; }

/* The third-place seed chip sits on an amber/red gradient rather than the brand
   fill, so it takes the warning pairing. rank-1/rank-2 already carry --ds-ink-900,
   which flips on its own and is excluded above. */
html .pl-rank.rank-3 { color: var(--ds-on-warning) !important; }
.platform-banner {
  padding: var(--ds-space-2) var(--ds-space-4);
  margin-bottom: var(--ds-space-4);
  border: 1px solid;
  border-radius: var(--ds-radius-md);
  font-size: var(--ds-type-body-small);
}
.platform-banner--maintenance { color: var(--ds-warning); background: var(--ds-warning-surface); border-color: var(--ds-warning-border); }
.platform-banner--announcement { color: var(--ds-info); background: var(--ds-info-surface); border-color: var(--ds-info-border); }
.validation-summary-errors { color: var(--ds-error); background: var(--ds-error-surface); border-color: var(--ds-error-border); }

/* Network state is a first-class product state instead of a browser-only error.
   It is hidden while online and announced politely when connectivity changes. */
.offline-banner {
  display: none;
  align-items: center;
  justify-content: center;
  gap: var(--ds-space-2);
  min-height: 44px;
  padding: var(--ds-space-2) var(--ds-space-4);
  color: var(--pim-warning);
  background: var(--pim-warning-bg);
  border-bottom: 1px solid var(--pim-warning-border);
  font-size: var(--ds-type-body-small);
  font-weight: 700;
}
.offline-banner.is-visible { display: flex; }
.ca-tab, .cs-tab, .club-tab, .ml-tab, .obs-tab { min-height: 44px; }

/* Dark-mode compatibility for legacy inline light surfaces. These selectors
   only match exact background declarations, never gradients or status colors. */
html[data-theme="dark"] [style*="background:#fff;" i],
html[data-theme="dark"] [style*="background: #fff;" i],
html[data-theme="dark"] [style*="background:#ffffff;" i],
html[data-theme="dark"] [style*="background: #ffffff;" i],
html[data-theme="dark"] [style*="background-color:#fff" i],
html[data-theme="dark"] [style*="background-color: #fff" i],
html[data-theme="dark"] [style*="background-color:#ffffff" i],
html[data-theme="dark"] [style*="background-color: #ffffff" i] {
  background-color: var(--ds-surface) !important;
  color: var(--ds-ink-700);
}
html[data-theme="dark"] .btn-close { filter: invert(1) grayscale(100%) brightness(180%); }
html[data-theme="dark"] .accordion-button::after { filter: invert(1) grayscale(100%) brightness(180%); }

/* Footer follows the selected theme while keeping the same quiet, bordered
   product-shell treatment as the header. */
html .footer {
  color: var(--ds-ink-600);
  background: var(--ds-surface) !important;
  border-top: 1px solid var(--ds-border) !important;
  border-image: none;
}
html .footer .footer-heading, html .footer .footer-wordmark { color: var(--ds-ink-900) !important; }
html .footer a, html .footer .text-white-50, html .footer .footer-tagline,
html .footer .footer-apps, html .footer .footer-bottom { color: var(--ds-ink-500) !important; }
html .footer a:hover { color: var(--ds-brand) !important; }
html .footer .footer-pill, html .footer .social-link {
  color: var(--ds-ink-600) !important;
  background: var(--ds-surface-2);
  border-color: var(--ds-border);
}
html .footer .footer-pill--link:hover, html .footer .footer-pill--link:focus-visible,
html .footer .footer-pill--active { color: var(--ds-brand) !important; border-color: var(--ds-brand); }
html .footer .footer-hr { border-color: var(--ds-border); }

@media (max-width: 1849.98px) {
  /* Inside the collapsed drawer (hamburger persists to 1850px) the selector is
     a full-width row and the panel becomes part of the sheet. */
  .theme-selector-wrapper { margin: var(--ds-space-2) 0; }
  .theme-selector-btn { width: 100%; justify-content: flex-start; min-height: 44px; }
  .theme-selector-btn::after { margin-left: auto; }
  .theme-picker-panel { width: 100%; min-width: 264px; max-width: calc(100vw - 2 * var(--ds-space-4)); }
}

/* The assistant FAB floats above everything bottom-right; get it out of the
   way while the nav drawer or a modal is open so it never covers controls.
   visibility:hidden (not just opacity) removes it from the tab order — an
   invisible-but-focusable button fails WCAG 2.4.7 and can be activated blind. */
#aiChatToggle { transition: opacity var(--ds-motion-fast) var(--ds-ease), visibility var(--ds-motion-fast) var(--ds-ease); }
/* Two rules, not one list: a browser without :has() (Firefox < 121) drops a
   whole selector list it cannot parse, which took the modal-open case with it. */
body.modal-open #aiChatToggle {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}
body:has(.navbar-collapse.show) #aiChatToggle,
body:has(.navbar-collapse.collapsing) #aiChatToggle {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

/* Custom modals (globalConfirmModal, the admin refund dialog, …). site.css restyles
   their close button with the `background` shorthand, which wiped Bootstrap's X glyph,
   and `filter: none`, which cancelled the dark-mode invert above — every custom modal
   showed a blank circle. Put the glyph back without touching the tinted fill. The
   header also stacks: Bootstrap's .modal-header is a flex ROW, so the centred icon,
   title and subtitle ran together on one line under the absolute close button. */
.custom-modal .modal-header .btn-close {
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e");
  background-position: center;
  background-size: 1em auto;
  background-repeat: no-repeat;
}
html[data-theme="dark"] .custom-modal .modal-header .btn-close {
  filter: invert(1) grayscale(100%) brightness(180%);
}
.custom-modal .modal-header {
  flex-direction: column;
  align-items: stretch;
  text-align: center;
}

/* -------------------------------------------------
   CROSS-BROWSER + PHONE FLOOR (2026-10-02)
   Browser floor: Chrome/Edge 100, Firefox 100 (ESR 115), Safari/iOS 15.4.
   Newer CSS (color-mix, :has, dvh, backdrop-filter) is always paired with a
   fallback declaration or kept out of shared selector lists.
   ------------------------------------------------- */
html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

/* Long unbroken strings (emails, IDs, URLs) wrap instead of widening the page. */
main {
  overflow-wrap: break-word;
}

/* iOS Safari zooms the whole page when a focused field's text is under 16px and
   does not zoom back out. Compact page-local inputs (13-14px) did exactly that
   on Observability, Settings, Friends, Chat and the bracket tools. */
@media (max-width: 767.98px) {
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="button"]):not([type="submit"]):not([type="reset"]):not([type="image"]),
  select,
  textarea {
    font-size: 16px !important;
  }
}

/* iOS: an empty date/time field collapses to no height and its value centres;
   its intrinsic width can also exceed a narrow column. */
input[type="date"],
input[type="time"],
input[type="datetime-local"],
input[type="month"],
input[type="week"] {
  min-width: 0;
  max-width: 100%;
}
input::-webkit-date-and-time-value {
  min-height: 1.5em;
  text-align: left;
}
