
/* ================= TOKENS (from CSSConfig) ================= */






/* ================= DESIGN TOKENS (generated from models.config.CSSConfig) ================= */
:root {
    /* Colours: surfaces */
    --color-bg               : #000000;
    /* Team colours (V3-46) */
    --team-crimson: #ef4444;
    --team-sky: #38bdf8;
    --team-green: #22c55e;
    --team-purple: #a855f7;
    --team-orange: #f97316;
    --team-teal: #14b8a6;
    --team-pink: #f472b6;
    --team-blue: #3b82f6;
    --team-lime: #84cc16;
    --team-magenta: #d946ef;
    --team-cyan: #06b6d4;
    --team-indigo: #818cf8;
    --team-rose: #fb7185;
    --team-emerald: #10b981;
    --team-violet: #8b5cf6;
    --team-coral: #ff8a65;
    --team-powder: #93c5fd;
    --team-olive: #65a30d;
    --team-blush: #f9a8d4;
    --team-seafoam: #2dd4bf;
    --team-ruby: #e11d48;
    --team-mint: #6ee7b7;
    --team-lavender: #c4b5fd;
    --team-aqua: #67e8f9;
    --team-forest: #16a34a;
    --team-royal: #2563eb;
    --team-orchid: #e879f9;
    --team-steel: #94a3b8;
    --team-brick: #c2410c;
    --team-wine: #db2777;
    
    --color-bg-top           : #1a1a1a;
    --color-surface-1        : #111111;
    --color-surface-2        : #1b1b1e;
    --color-surface-3        : #26262a;
    --color-header-bg        : rgba(0, 0, 0, 0.85);
    --color-overlay          : rgba(0, 0, 0, 0.6);
    /* Colours: lines */
    --color-border           : #2e2e33;
    --color-border-strong    : #47474d;
    /* Colours: text */
    --color-text             : #ffffff;
    --color-text-muted       : #a3a3ab;
    --color-text-inverse     : #111111;
    /* Colours: accent */
    --color-accent           : #ffc107;
    --color-accent-hover     : #ffcd39;
    --color-accent-soft      : rgba(255, 193, 7, 0.14);
    --color-accent-glow      : rgba(255, 193, 7, 0.45);
    --color-brand            : #fecb00;
    /* Colours: semantic */
    --color-success          : #22c55e;
    --color-success-soft     : rgba(34, 197, 94, 0.15);
    --color-success-glow     : rgba(34, 197, 94, 0.6);
    --color-danger           : #ef4444;
    --color-danger-soft      : rgba(239, 68, 68, 0.15);
    --color-info             : #60a5fa;
    --color-info-soft        : rgba(96, 165, 250, 0.15);
    --color-whatsapp         : #00d757;
    --color-shadow           : rgba(0, 0, 0, 0.5);
    /* Colours: paper (printable lists) */
    --print-paper            : #ffffff;
    --print-ink              : #111111;
    --print-ink-muted        : #555555;
    --print-rule             : #d4d4d8;

    /* Typography */
    --font-family-base       : 'Poppins', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --font-family-heading    : 'Poppins', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --font-family-mono       : ui-monospace, SFMono-Regular, Consolas, 'Liberation Mono', monospace;
    --font-size-xs           : 0.75rem;
    --font-size-sm           : 0.875rem;
    --font-size-md           : 1rem;
    --font-size-lg           : 1.25rem;
    --font-size-xl           : 1.5rem;
    --font-size-xxl          : 2rem;
    --font-size-display      : 2.5rem;
    --font-size-display-sm   : 2rem;
    --font-weight-light      : 300;
    --font-weight-regular    : 400;
    --font-weight-medium     : 500;
    --font-weight-semibold   : 600;
    --font-weight-bold       : 700;
    --line-height-base       : 1.5;
    --line-height-tight      : 1.2;

    /* Spacing */
    --space-1                : 0.25rem;
    --space-2                : 0.5rem;
    --space-3                : 0.75rem;
    --space-4                : 1rem;
    --space-5                : 1.5rem;
    --space-6                : 2rem;
    --space-7                : 3rem;
    --tap-target             : 44px;
    --overlay-unit           : 1vw;
    --overlay-unit-v         : 1vh;
    --header-height          : 70px;

    /* Shape */
    --radius-sm              : 8px;
    --radius-md              : 12px;
    --radius-lg              : 16px;
    --radius-pill            : 999px;
    --border-width           : 1px;
    --focus-ring-width       : 2px;

    /* Elevation */
    --shadow-sm              : 0 1px 2px rgba(0, 0, 0, 0.4);
    --shadow-md              : 0 8px 24px rgba(0, 0, 0, 0.45);
    --shadow-lg              : 0 20px 40px rgba(0, 0, 0, 0.6);
    --glow                   : 0 0 18px var(--color-accent-glow);
    --glow-success           : 0 0 18px var(--color-success-glow);

    /* Motion */
    --motion-fast            : 150ms;
    --motion-base            : 300ms;
    --motion-slow            : 500ms;
    --ease-out               : cubic-bezier(0.2, 0.8, 0.2, 1);
    --ease-in                : cubic-bezier(0.4, 0, 1, 1);
    --ease-in-out            : cubic-bezier(0.4, 0, 0.2, 1);
    --reveal-distance        : 24px;
    --motion-stagger         : 60ms;
    --motion-stagger-max     : 4;
    --hover-lift             : -4px;
}

/* ---------- Bootstrap mapped onto our tokens (html has data-bs-theme="dark") ---------- */
:root,
[data-bs-theme=dark] {
    --bs-body-font-family    : var(--font-family-base);
    --bs-body-bg             : var(--color-bg);
    --bs-body-color          : var(--color-text);
    --bs-emphasis-color      : var(--color-text);
    --bs-secondary-color     : var(--color-text-muted);
    --bs-secondary-bg        : var(--color-surface-2);
    --bs-tertiary-bg         : var(--color-surface-2);
    --bs-border-color        : var(--color-border);
    --bs-border-radius       : var(--radius-sm);
    --bs-link-color          : var(--color-accent);
    --bs-link-hover-color    : var(--color-accent-hover);
    --bs-focus-ring-color    : var(--color-accent-glow);
}



/* ================= GLOBAL ================= */
html, body {
  height: 100%;
  margin: 0;
}

/* ================= LAYOUT ================= */
.app-container {
  display: flex;
  flex-direction: column;
  height: 100vh;
}


/* ================= HEADER (app shell; markup in v3/html/headers/main) ================= */
.app-header {
  flex: 0 0 auto;
  position: relative;
  z-index: 10;
  background: var(--color-header-bg);
  border-bottom: var(--border-width) solid var(--color-border);
  box-shadow: var(--shadow-sm);
}

.app-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  min-height: var(--header-height);
  padding: var(--space-2) var(--space-4);
}

.app-brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
  color: var(--color-text);
  font-family: var(--font-family-heading);
  font-size: var(--font-size-lg);
  font-weight: var(--font-weight-semibold);
  text-decoration: none;
  white-space: nowrap;
}
.app-brand:hover { color: var(--color-text); }
.app-brand img   { flex-shrink: 0; }
.app-brand span  { overflow: hidden; text-overflow: ellipsis; }   /* very narrow phones: shorten the name, never wrap */

.app-nav__desktop { display: none; flex: 1; align-items: center; justify-content: space-between; gap: var(--space-5); }

/* Mobile menu button: your avatar (or a person icon for guests) with a small ☰ badge, so it reads as "account + menu" */
.app-menu-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: var(--tap-target);
  height: var(--tap-target);
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--color-text);
}
.app-menu-btn__guest { font-size: var(--font-size-xxl); line-height: 1; }
.app-menu-btn__badge {
  position: absolute;
  right: calc(-1 * var(--space-1));
  bottom: calc(-1 * var(--space-1));
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--space-5);
  height: var(--space-5);
  border: var(--border-width) solid var(--color-header-bg);
  border-radius: 50%;
  background: var(--color-accent);
  color: var(--color-text-inverse);
  font-size: var(--font-size-xs);
  line-height: 1;
}

@media (min-width: 768px) {
  .app-nav__desktop { display: flex; }
  .app-menu-btn     { display: none; }
}

.app-nav__links,
.app-offcanvas__links { display: flex; gap: var(--space-1); list-style: none; margin: 0; padding: 0; }

.app-nav__link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--tap-target);
  padding: 0 var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--color-text-muted);
  font-weight: var(--font-weight-medium);
  text-decoration: none;
  transition: color var(--motion-fast) var(--ease-out), background-color var(--motion-fast) var(--ease-out);
}
.app-nav__link[aria-current="page"] { color: var(--color-accent); }
@media (hover: hover) {
  .app-nav__link:hover { color: var(--color-text); background: var(--color-surface-2); }
  .app-nav__link[aria-current="page"]:hover { color: var(--color-accent); }
}

.app-nav__actions { display: flex; align-items: center; gap: var(--space-3); }

.app-avatar-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tap-target);
  height: var(--tap-target);
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
}

/* Account dropdown (Bootstrap dropdown, themed via its variables) */
.app-menu {
  --bs-dropdown-bg: var(--color-surface-1);
  --bs-dropdown-color: var(--color-text);
  --bs-dropdown-border-color: var(--color-border);
  --bs-dropdown-border-radius: var(--radius-sm);
  --bs-dropdown-font-size: var(--font-size-sm);
  --bs-dropdown-link-color: var(--color-text);
  --bs-dropdown-link-hover-color: var(--color-text);
  --bs-dropdown-link-hover-bg: var(--color-surface-2);
  --bs-dropdown-link-active-color: var(--color-text-inverse);
  --bs-dropdown-link-active-bg: var(--color-accent);
  --bs-dropdown-divider-bg: var(--color-border);
  --bs-dropdown-item-padding-y: var(--space-2);
  --bs-dropdown-item-padding-x: var(--space-4);
  box-shadow: var(--shadow-md);
}
.app-menu .dropdown-item { display: flex; align-items: center; gap: var(--space-2); }
.app-menu .dropdown-item[aria-current="page"] { color: var(--color-accent); }
.app-menu__danger,
.app-menu .app-menu__danger { color: var(--color-danger); }

/* Mobile off-canvas (Bootstrap offcanvas, themed via its variables) */
.app-offcanvas {
  --bs-offcanvas-bg: var(--color-surface-1);   /* opaque: --color-header-bg is translucent */
  --bs-offcanvas-color: var(--color-text);
  --bs-offcanvas-border-color: var(--color-border);
  --bs-offcanvas-width: min(85vw, calc(var(--space-7) * 6));
  --bs-offcanvas-padding-x: var(--space-4);
  --bs-offcanvas-padding-y: var(--space-4);
}
.app-offcanvas .offcanvas-header { gap: var(--space-3); border-bottom: var(--border-width) solid var(--color-border); }
.app-offcanvas__me      { display: flex; align-items: center; gap: var(--space-3); min-width: 0; flex: 1; }
.app-offcanvas__me-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.app-offcanvas__me-id   { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--font-size-sm); color: var(--color-text-muted); }
.app-offcanvas__me-link { font-weight: var(--font-weight-semibold); }
.app-offcanvas__me-link[aria-current="page"] { color: var(--color-accent); }
.app-offcanvas__body    { display: flex; flex-direction: column; gap: var(--space-5); }
.app-offcanvas__links   { flex-direction: column; }
.app-offcanvas__links .app-nav__link { width: 100%; }
.app-offcanvas__account { padding-top: var(--space-4); border-top: var(--border-width) solid var(--color-border); }



/* ================= BODY (the app scrolls inside .app-body, not the window) ================= */
.app-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  overflow-x: hidden;
  background: radial-gradient(circle at top, var(--color-bg-top), var(--color-bg));
  color: var(--color-text);
  scroll-behavior: smooth;
}
.app-body > .app-content { flex: 1 0 auto; }
.app-body:focus { outline: none; }   /* focused by the skip link (tabindex="-1"); the ring would frame the whole page */

/* ================= SCROLLBAR ================= */
.app-body::-webkit-scrollbar       { width: 6px; }
.app-body::-webkit-scrollbar-thumb { background: var(--color-accent); border-radius: var(--radius-pill); }
.app-body::-webkit-scrollbar-track { background: var(--color-surface-1); }

/* Links default to the accent colour (Bootstrap's link vars are mapped in tokens) */
a { color: var(--color-accent); text-decoration: none; }



/* ================= FOOTER (app shell; inside .app-body, so it scrolls with the content) ================= */
.app-footer {
  flex: 0 0 auto;
  padding: var(--space-5) var(--space-4);
  border-top: var(--border-width) solid var(--color-border);
  background: var(--color-surface-1);
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}
.app-footer__inner  { display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--space-5); padding-bottom: var(--space-4); }
.app-footer__brand  { display: flex; flex-direction: column; gap: var(--space-2); max-width: 40ch; }
.app-footer__name   { display: inline-flex; align-items: center; gap: var(--space-3); color: var(--color-text); font-weight: var(--font-weight-semibold); }
.app-footer__text   { margin: 0; }
.app-footer__links  { display: flex; flex-wrap: wrap; gap: 0 var(--space-5); list-style: none; margin: 0; padding: 0; }
.app-footer__links a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-target);
  color: var(--color-text-muted);
  text-decoration: none;
  transition: color var(--motion-fast) var(--ease-out);
}
@media (hover: hover) {
  .app-footer__links a:hover { color: var(--color-accent); }
}
.app-footer__copy   { margin: 0; text-align: center; }
.app-footer__copy a { color: var(--color-text-muted); text-decoration: underline; text-underline-offset: 2px; }
@media (hover: hover) {
  .app-footer__copy a:hover { color: var(--color-accent); }
}


/* ================= NPROGRESS BAR ================= */
/* Fixed at the top of the window above everything (header, dialogs, the busy overlay), thick enough to notice, with a glow */
#nprogress .bar {
  background: var(--color-accent);
  height: calc(var(--focus-ring-width) * 2);
  z-index: 2000;
  box-shadow: 0 0 var(--space-2) var(--color-accent);
}
#nprogress .peg { box-shadow: 0 0 var(--space-3) var(--color-accent), 0 0 var(--space-1) var(--color-accent); }


/* ================= LOADER DIALOG (showLoader in app.js) =================
   Legacy V3 effects (slide-left/right, data-animate-*, flip, glow, pulse) were removed with the design-system migration:
   use data-reveal, the ui-fade / ui-slide transitions and the ui-* hover states instead. */
.custom-loader-wrapper {
  display: flex;
  justify-content: center;
  align-items: center;
  margin-top: var(--space-3);
}

.custom-loader {
  width: var(--space-7);
  height: var(--space-7);
  border: var(--space-1) solid var(--color-accent-soft);
  border-top-color: var(--color-accent);
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  100% { transform: rotate(360deg); }
}






/* ================= DESIGN SYSTEM (base + ui-* components) ================= */

/* ================= BASE (design system) ================= */
html, body {
  font-family: var(--font-family-base);
  font-size: var(--font-size-md);
  line-height: var(--line-height-base);
  color: var(--color-text);
  background: var(--color-bg);
}

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-family-heading);
  line-height: var(--line-height-tight);
}

::selection {
  background: var(--color-accent);
  color: var(--color-text-inverse);
}

/* Visible focus for keyboard users (UX guideline §10). Pointer clicks don't show it. */
:focus-visible {
  outline: var(--focus-ring-width) solid var(--color-accent);
  outline-offset: 2px;
}

/* Vue: hide templates until mounted */
[v-cloak] {
  display: none !important;
}

/* Scroll reveal (design system).
   Usage: <div data-reveal> … ; initReveal() adds .is-visible once in view.
   Implemented as an animation (not a transition) so it never conflicts with a component's own
   `transition` (e.g. .ui-card), and with fill-mode `backwards` so hover transforms work afterwards. */
[data-reveal]:not(.is-visible) {
  opacity: 0;
}

[data-reveal].is-visible {
  animation: ui-reveal var(--motion-slow) var(--ease-out) backwards;
  /* --reveal-index is only set inside a [data-reveal-stagger] container (see initReveal); default 0 = no delay */
  animation-delay: calc(var(--reveal-index, 0) * var(--motion-stagger));
}

@keyframes ui-reveal {
  from { opacity: 0; transform: translateY(var(--reveal-distance)); }
  to   { opacity: 1; transform: none; }
}

/* Reduced motion: no movement, no looping, near-instant transitions (UX guideline §7.2) */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }

  [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
  }
}



/* =====================================================================================
   UI COMPONENTS (design system). Prefix: ui-. Tokens only — no literal colours/sizes.
   Reference & live examples: /v3/styleguide, docs/technical/design-system.md
   ===================================================================================== */

/* ================= LAYOUT HELPERS ================= */
.ui-section          { padding-block: var(--space-7); }
.ui-section__title   { font-size: var(--font-size-xxl); font-weight: var(--font-weight-semibold); margin-bottom: var(--space-5); }
.ui-section__lead    { color: var(--color-text-muted); margin-top: calc(-1 * var(--space-4)); margin-bottom: var(--space-5); }
.ui-stack            { display: flex; flex-direction: column; gap: var(--space-4); }
.ui-cluster          { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }
.ui-grid             { display: grid; gap: var(--space-5); grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }
.ui-muted            { color: var(--color-text-muted); }
.ui-measure          { max-width: 72ch; }   /* readable line length for text and media (fixed component geometry) */
.ui-display          { font-size: var(--font-size-display); font-weight: var(--font-weight-bold); line-height: var(--line-height-tight); }
@media (max-width: 767.98px) {
  .ui-display        { font-size: var(--font-size-display-sm); }
}

/* ================= PROSE (long-form text: legal pages, tutorials) ================= */
/* Readable measure (fixed component geometry), headings in the type scale, muted body, gold links. */
.ui-prose            { max-width: 72ch; /* = ui-measure */ color: var(--color-text-muted); line-height: var(--line-height-base); overflow-wrap: anywhere; }
.ui-prose > * + *    { margin-top: var(--space-4); }
.ui-prose h1, .ui-prose h2, .ui-prose h3, .ui-prose h4 { color: var(--color-text); font-weight: var(--font-weight-semibold); line-height: var(--line-height-tight); margin-bottom: 0; }
.ui-prose h1         { font-size: var(--font-size-xxl); }
.ui-prose h2         { font-size: var(--font-size-xl); margin-top: var(--space-6); }
.ui-prose h3, .ui-prose h4 { font-size: var(--font-size-lg); margin-top: var(--space-5); }
.ui-prose p          { margin-bottom: 0; }
.ui-prose ul, .ui-prose ol { margin-bottom: 0; padding-left: var(--space-5); }
.ui-prose li + li    { margin-top: var(--space-2); }
.ui-prose li::marker { color: var(--color-accent); }
.ui-prose strong     { color: var(--color-text); font-weight: var(--font-weight-semibold); }
.ui-prose a:not(.ui-btn) { color: var(--color-accent); text-decoration: underline; text-underline-offset: 0.2em; }
.ui-prose__updated   { color: var(--color-text-muted); font-size: var(--font-size-sm); }

/* ================= BUTTONS ================= */
.ui-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--tap-target);
  padding: var(--space-2) var(--space-5);
  border: var(--border-width) solid transparent;
  border-radius: var(--radius-sm);
  font-family: inherit;
  font-size: var(--font-size-md);
  font-weight: var(--font-weight-semibold);
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--motion-fast) var(--ease-out),
              border-color var(--motion-fast) var(--ease-out),
              color var(--motion-fast) var(--ease-out),
              box-shadow var(--motion-base) var(--ease-out),
              transform var(--motion-fast) var(--ease-out);
}
.ui-btn:active:not([disabled]) { transform: translateY(1px); }
.ui-btn[disabled],
.ui-btn.is-disabled { opacity: 0.45; cursor: not-allowed; box-shadow: none; }

.ui-btn--primary            { background: var(--color-accent); color: var(--color-text-inverse); }
.ui-btn--secondary          { background: transparent; border-color: var(--color-accent); color: var(--color-accent); }
.ui-btn--ghost              { background: transparent; color: var(--color-text); }
.ui-btn--danger             { background: transparent; border-color: var(--color-danger); color: var(--color-danger); }
.ui-btn--whatsapp           { background: var(--color-whatsapp); color: var(--color-text-inverse); }

@media (hover: hover) {
  .ui-btn--primary:hover:not([disabled])   { background: var(--color-accent-hover); box-shadow: var(--glow); }
  .ui-btn--secondary:hover:not([disabled]) { background: var(--color-accent-soft); box-shadow: var(--glow); }
  .ui-btn--ghost:hover:not([disabled])     { background: var(--color-surface-3); }
  .ui-btn--danger:hover:not([disabled])    { background: var(--color-danger-soft); }
}

.ui-btn--sm    { min-height: 36px; padding: var(--space-1) var(--space-3); font-size: var(--font-size-sm); }
.ui-btn--lg    { min-height: 52px; padding: var(--space-3) var(--space-6); font-size: var(--font-size-lg); }
.ui-btn--block { display: flex; width: 100%; }
.ui-btn--icon  { padding: 0; width: var(--tap-target); }

/* Busy (saving, checking, loading more): :class="{ 'is-loading': saving }" :aria-busy="saving ? 'true' : null". The label
   is hidden behind a spinner in the button's own colours; the button keeps full opacity even while also [disabled], so
   the spinner stays visible. Never put the page spinner (.ui-spinner) inside a button. */
.ui-btn.is-loading           { position: relative; color: transparent !important; pointer-events: none; }
.ui-btn.is-loading[disabled] { opacity: 1; cursor: progress; }
.ui-btn.is-loading > *       { visibility: hidden; }
.ui-btn.is-loading::after {
  content: "";
  position: absolute;
  width: 1.1em;
  height: 1.1em;
  border: 2px solid currentColor;
  border-color: var(--color-text-inverse) transparent var(--color-text-inverse) transparent;
  border-radius: 50%;
  animation: ui-spin 0.8s linear infinite;
}
.ui-btn--secondary.is-loading::after,
.ui-btn--ghost.is-loading::after { border-color: var(--color-accent) transparent var(--color-accent) transparent; }

/* Stack big buttons on very small screens */
@media (max-width: 399.98px) {
  .ui-btn-row > .ui-btn { flex: 1 1 100%; }
}

/* ================= BADGES ================= */
/* Bid clock (V3-57): label, seconds and a draining bar; phases is-running / is-once / is-twice / is-last (accent → danger).
   <div class="ui-clock is-once" role="timer"><span class="ui-clock__label">Going once</span><span class="ui-clock__time">8</span><span class="ui-clock__bar"><span style="width:40%"></span></span></div> */
.ui-clock {
  display: inline-grid; grid-template-columns: auto auto; align-items: baseline; gap: 0 var(--space-2);
  padding: var(--space-1) var(--space-3); border-radius: var(--radius-pill);
  background: var(--color-surface-2); border: var(--border-width) solid var(--color-border-strong);
}
.ui-clock__label  { font-size: var(--font-size-xs); font-weight: var(--font-weight-semibold); letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-text-muted); }
.ui-clock__time   { font-size: var(--font-size-md); font-weight: var(--font-weight-bold); font-variant-numeric: tabular-nums; }
.ui-clock__bar    { grid-column: 1 / -1; height: calc(var(--border-width) * 3); margin-top: var(--space-1); border-radius: var(--radius-pill); background: var(--color-surface-3); overflow: hidden; }
.ui-clock__bar > span { display: block; height: 100%; background: var(--color-accent); transition: width var(--motion-base) linear; }
.ui-clock.is-once  .ui-clock__label { color: var(--color-accent); }
.ui-clock.is-twice { border-color: var(--color-danger); }
.ui-clock.is-twice .ui-clock__label, .ui-clock.is-last .ui-clock__label { color: var(--color-danger); }
.ui-clock.is-twice .ui-clock__bar > span, .ui-clock.is-last .ui-clock__bar > span { background: var(--color-danger); }
.ui-clock.is-last  { border-color: var(--color-danger); animation: ui-clock-pulse var(--motion-slow) var(--ease-in-out) infinite alternate; }
@keyframes ui-clock-pulse { from { box-shadow: none; } to { box-shadow: 0 0 0 var(--space-1) var(--color-danger-soft); } }
@media (prefers-reduced-motion: reduce) { .ui-clock.is-last { animation: none; } .ui-clock__bar > span { transition: none; } }

/* Keyboard key (shortcut hints): <kbd class="ui-kbd">S</kbd>. Next to the label it triggers; never the only label. */
.ui-kbd {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: calc(var(--font-size-xs) * 1.8); padding: 0 var(--space-1);
  border: var(--border-width) solid var(--color-border-strong); border-bottom-width: calc(var(--border-width) * 2);
  border-radius: var(--radius-sm); background: var(--color-surface-2); color: var(--color-text-muted);
  font-family: inherit; font-size: var(--font-size-xs); font-weight: var(--font-weight-semibold); line-height: 1.5;
}
.ui-btn .ui-kbd { margin-left: var(--space-1); }

.ui-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-2);
  border-radius: var(--radius-pill);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-semibold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  line-height: 1.6;
  white-space: nowrap;
  background: var(--color-surface-3);
  color: var(--color-text-muted);
}
.ui-badge--live    { background: var(--color-success-soft); color: var(--color-success); }
.ui-badge--live::before {
  content: "";
  width: 0.5em;
  height: 0.5em;
  border-radius: 50%;
  background: var(--color-success);
  animation: ui-live-pulse 1.6s var(--ease-out) infinite;
}
.ui-badge--upcoming { background: var(--color-accent-soft); color: var(--color-accent); }
.ui-badge--info     { background: var(--color-info-soft); color: var(--color-info); }
.ui-badge--danger   { background: var(--color-danger-soft); color: var(--color-danger); }
.ui-badge--muted    { background: var(--color-surface-3); color: var(--color-text-muted); }

/* ================= CHIPS (filters) ================= */
.ui-chip-group { display: flex; flex-wrap: wrap; gap: var(--space-2); }
/* --scroll: below 992 px (phones, tablets) one swipeable row instead of wrapping onto two lines; wider screens wrap as usual.
   On phones the row also bleeds to the screen edges. */
@media (max-width: 991.98px) {
  .ui-chip-group--scroll {
    position: relative;   /* see .ui-pillstrip__track */
    flex-wrap: nowrap;
    min-width: 0;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
    padding-block: var(--space-1);
  }
  .ui-chip-group--scroll::-webkit-scrollbar { display: none; }
  .ui-chip-group--scroll > * { flex: 0 0 auto; scroll-snap-align: start; }
}
@media (max-width: 575.98px) {
  .ui-chip-group--scroll { margin-inline: calc(-1 * var(--space-3)); padding-inline: var(--space-3); }
}
.ui-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 36px;
  padding: var(--space-1) var(--space-4);
  border: var(--border-width) solid var(--color-border-strong);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--color-text);
  font-family: inherit;
  font-size: var(--font-size-sm);
  cursor: pointer;
  transition: background-color var(--motion-fast) var(--ease-out), border-color var(--motion-fast) var(--ease-out), color var(--motion-fast) var(--ease-out);
}
@media (hover: hover) {
  .ui-chip:hover { border-color: var(--color-accent); }
}
.ui-chip[aria-pressed="true"],
.ui-chip.is-active { background: var(--color-accent); border-color: var(--color-accent); color: var(--color-text-inverse); font-weight: var(--font-weight-semibold); }
.ui-chip__count { opacity: 0.7; font-size: var(--font-size-xs); }

/* ================= FORM FIELDS ================= */
.ui-field          { display: flex; flex-direction: column; gap: var(--space-1); }
.ui-field__label   { font-size: var(--font-size-xs); color: var(--color-text-muted); font-weight: var(--font-weight-semibold); letter-spacing: 0.02em; }
.ui-field__label .ui-required { color: var(--color-accent); }
.ui-field__help    { font-size: var(--font-size-xs); color: var(--color-text-muted); }
.ui-field__error   { font-size: var(--font-size-xs); color: var(--color-danger); display: flex; gap: var(--space-1); align-items: center; }

.ui-input,
.ui-select,
.ui-textarea {
  width: 100%;
  max-width: none;
  min-height: var(--tap-target);
  padding: var(--space-2) var(--space-3);
  border: var(--border-width) solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background: var(--color-surface-2);
  color: var(--color-text);
  font-family: inherit;
  font-size: var(--font-size-md);
  transition: border-color var(--motion-fast) var(--ease-out), box-shadow var(--motion-fast) var(--ease-out);
  color-scheme: dark;
}
.ui-input::placeholder,
.ui-textarea::placeholder { color: var(--color-text-muted); opacity: 1; }
.ui-input:focus,
.ui-select:focus,
.ui-textarea:focus { outline: none; border-color: var(--color-accent); box-shadow: 0 0 0 3px var(--color-accent-soft); }
.ui-input[disabled],
.ui-select[disabled],
.ui-textarea[disabled] { opacity: 0.5; cursor: not-allowed; }
.ui-field.has-error .ui-input,
.ui-field.has-error .ui-select,
.ui-field.has-error .ui-textarea { border-color: var(--color-danger); }

/* Search: icon + input + clear button */
.ui-search { position: relative; }
.ui-search .ui-input { padding-left: calc(var(--space-3) * 2 + 1em); padding-right: calc(var(--tap-target)); }
.ui-search__icon { position: absolute; left: var(--space-3); top: 50%; transform: translateY(-50%); color: var(--color-text-muted); pointer-events: none; }
.ui-search__clear {
  position: absolute; right: 0; top: 0; height: 100%; width: var(--tap-target);
  border: none; background: transparent; color: var(--color-text-muted); cursor: pointer; border-radius: var(--radius-sm);
}
@media (hover: hover) {
  .ui-search__clear:hover { color: var(--color-text); }
}

/* Segmented control (radio group) */
.ui-segmented {
  display: flex;
  border: var(--border-width) solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
/* The option is a flex column and its label (span) grows to fill it, so a selected option is highlighted edge to edge even
   when a neighbour's longer label wraps onto two lines and makes the row taller. */
.ui-segmented__option { flex: 1; position: relative; display: flex; flex-direction: column; }
.ui-segmented__option input { position: absolute; opacity: 0; inset: 0; cursor: pointer; }
.ui-segmented__option span {
  flex: 1;
  display: flex; align-items: center; justify-content: center; gap: var(--space-1);
  min-height: var(--tap-target);
  padding: var(--space-2) var(--space-3);
  font-size: var(--font-size-sm);
  text-align: center;
  color: var(--color-text);
  transition: background-color var(--motion-fast) var(--ease-out), color var(--motion-fast) var(--ease-out);
}
.ui-segmented__option + .ui-segmented__option span { border-left: var(--border-width) solid var(--color-border-strong); }
.ui-segmented__option input:checked + span { background: var(--color-accent); color: var(--color-text-inverse); font-weight: var(--font-weight-semibold); }
.ui-segmented__option input:focus-visible + span { outline: var(--focus-ring-width) solid var(--color-accent); outline-offset: -4px; }

/* Choice list: checkboxes or radio buttons as full-width rows (several options, or one option among many with long text).
   <div class="ui-choices" role="group"><label class="ui-choice"><input type="checkbox"><span>Text</span></label>…</div> */
.ui-choices { display: flex; flex-direction: column; gap: var(--space-2); }
.ui-choice {
  display: flex; align-items: center; gap: var(--space-3);
  min-height: var(--tap-target);
  padding: var(--space-2) var(--space-3);
  border: var(--border-width) solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background: var(--color-surface-2);
  cursor: pointer;
  transition: border-color var(--motion-fast) var(--ease-out), background-color var(--motion-fast) var(--ease-out);
}
.ui-choice input { flex: none; width: var(--space-4); height: var(--space-4); margin: 0; accent-color: var(--color-accent); cursor: pointer; }
.ui-choice input:focus-visible { outline: var(--focus-ring-width) solid var(--color-accent); outline-offset: 2px; }
.ui-choice:has(input:checked) { border-color: var(--color-accent); background: var(--color-accent-soft); }
.ui-field.has-error .ui-choice { border-color: var(--color-danger); }
@media (hover: hover) {
  .ui-choice:hover { border-color: var(--color-accent); }
}

/* File field: a picked image (or none) with Choose / Replace and Remove. The real <input type="file"> is visually hidden and
   the Choose button is its <label>, so keyboard and screen readers use the native control.
   <div class="ui-file"><img class="ui-file__preview">|<span class="ui-file__empty"><i></i></span>
     <div class="ui-file__body"><span class="ui-file__name">…</span><div class="ui-cluster">…buttons…</div></div></div> */
.ui-file {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-3);
  border: var(--border-width) dashed var(--color-border-strong);
  border-radius: var(--radius-sm);
  background: var(--color-surface-2);
}
.ui-file__preview,
.ui-file__empty {
  flex: none; width: calc(var(--tap-target) * 1.5); height: calc(var(--tap-target) * 1.5);
  border-radius: var(--radius-sm); object-fit: cover; background: var(--color-surface-3);
}
.ui-file__empty { display: flex; align-items: center; justify-content: center; color: var(--color-text-muted); font-size: var(--font-size-lg); }
.ui-file__body { display: flex; flex-direction: column; gap: var(--space-2); min-width: 0; flex: 1; }
.ui-file__name { font-size: var(--font-size-sm); color: var(--color-text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ui-file:focus-within { border-color: var(--color-accent); }
.ui-field.has-error .ui-file { border-color: var(--color-danger); }

/* ================= AVATARS & LOGOS ================= */
.ui-avatar, .ui-logo {
  display: inline-block;
  flex-shrink: 0;
  object-fit: cover;
  background: var(--color-surface-3);
}
.ui-avatar        { border-radius: 50%; }
.ui-logo          { border-radius: var(--radius-sm); }
.ui-avatar--sm, .ui-logo--sm { width: 32px;  height: 32px; }
.ui-avatar--md, .ui-logo--md { width: 48px;  height: 48px; }
.ui-avatar--lg, .ui-logo--lg { width: 72px;  height: 72px; }
.ui-avatar--xl, .ui-logo--xl { width: 160px; height: 160px; }
.ui-avatar--glow  { box-shadow: var(--glow); }

/* Initials logo: fallback when a tournament / team has no logo of its own. <span class="ui-logo ui-logo--md ui-logo--initials" aria-hidden="true">DP</span>
   Gold initials on a raised surface (gold stays the only accent); the name next to it carries the meaning, so it is aria-hidden. */
.ui-logo--initials {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: var(--border-width) solid var(--color-border-strong);
  color: var(--color-accent);
  font-family: var(--font-family-heading);
  font-weight: var(--font-weight-semibold);
  font-size: var(--font-size-md);
  letter-spacing: 0.02em;
  line-height: 1;
  user-select: none;
}
.ui-logo--initials.ui-logo--sm { font-size: var(--font-size-xs); }
.ui-logo--initials.ui-logo--lg { font-size: var(--font-size-xl); }
.ui-logo--initials.ui-logo--xl { font-size: var(--font-size-display); }

/* Initials avatar: a person with no photo of their own. <span class="ui-avatar ui-avatar--xl ui-avatar--initials" aria-hidden="true">AA</span> */
.ui-avatar--initials {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: var(--border-width) solid var(--color-border-strong);
  color: var(--color-accent);
  font-family: var(--font-family-heading);
  font-weight: var(--font-weight-semibold);
  font-size: var(--font-size-md);
  line-height: 1;
  user-select: none;
}
.ui-avatar--initials.ui-avatar--sm { font-size: var(--font-size-xs); }
.ui-avatar--initials.ui-avatar--lg { font-size: var(--font-size-xl); }
.ui-avatar--initials.ui-avatar--xl { font-size: var(--font-size-display); }

/* XL avatars and logos shrink on phones so a profile header doesn't fill the first screen */
@media (max-width: 575.98px) {
  .ui-avatar--xl, .ui-logo--xl { width: 112px; height: 112px; }
  .ui-avatar--initials.ui-avatar--xl, .ui-logo--initials.ui-logo--xl { font-size: var(--font-size-xxl); }
}

/* Skip link: first focusable element on every page (mainHtml); hidden until it receives keyboard focus */
.ui-skip-link {
  position: absolute;
  top: var(--space-3);
  left: var(--space-3);
  z-index: 1100;
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-sm);
  background: var(--color-accent);
  color: var(--color-text-inverse);
  font-weight: var(--font-weight-semibold);
  text-decoration: none;
  transform: translateY(calc(-100% - var(--space-5)));
}
.ui-skip-link:focus,
.ui-skip-link:focus-visible { transform: none; color: var(--color-text-inverse); outline-color: var(--color-text); }

/* ================= IMAGE CROPPER =================
   Vue <ui-image-cropper :src="…"> (app.js) in a Bootstrap modal, using Cropper.js 1.6.2 (page-level library: mainHtml
   pageLibs = Set("cropper")). The square crop box is shown as the avatar circle (.ui-cropper--circle, photos) or as a
   rounded square (.ui-cropper--square, logos and sponsor images); everything outside it is dimmed. Full screen on phones. */
.ui-cropper .modal-content {
  background: var(--color-surface-1);
  color: var(--color-text);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
}
.ui-cropper .modal-header,
.ui-cropper .modal-footer { border-color: var(--color-border); }
.ui-cropper__title  { margin: 0; font-size: var(--font-size-lg); font-weight: var(--font-weight-semibold); }
.ui-cropper__stage  {
  position: relative;
  height: min(60vh, calc(var(--space-7) * 7.5));
  overflow: hidden;
  border-radius: var(--radius-sm);
  background: var(--color-bg);
  touch-action: none;
}
.ui-cropper__stage:focus-visible { outline: var(--focus-ring-width) solid var(--color-accent); outline-offset: 2px; }
.ui-cropper__stage img { display: block; max-width: 100%; }

/* Cropper.js, themed: circular window, no grid / handles, dim outside the circle */
.ui-cropper .cropper-modal     { background: transparent; opacity: 1; }
.ui-cropper .cropper-view-box  {
  border-radius: 50%;
  outline: var(--focus-ring-width) solid var(--color-accent);
  outline-color: var(--color-accent);
  box-shadow: 0 0 0 100vmax var(--color-overlay);
}
.ui-cropper .cropper-face      { border-radius: 50%; background: transparent; }
/* JPEG output: the space around a zoomed-out photo is the avatar background, shown the same way while positioning */
.ui-cropper--filled .cropper-view-box { background: var(--color-surface-3); }
.ui-cropper--square .cropper-view-box,
.ui-cropper--square .cropper-face { border-radius: var(--radius-sm); }
.ui-cropper .cropper-line,
.ui-cropper .cropper-point,
.ui-cropper .cropper-dashed,
.ui-cropper .cropper-center    { display: none; }

.ui-cropper__controls { display: flex; align-items: center; gap: var(--space-2); margin-top: var(--space-4); }
.ui-cropper__zoom     { flex: 1; min-width: 0; accent-color: var(--color-accent); }
.ui-cropper__hint     { margin: var(--space-3) 0 0; color: var(--color-text-muted); font-size: var(--font-size-xs); text-align: center; }
.ui-cropper .modal-footer { gap: var(--space-2); }

/* ================= PICKER (select with photos) =================
   Vue <ui-picker v-model :options="[{value, label, meta?, photo?}]"> (app.js): a field-styled button that opens a list of
   options, each with an avatar (photo or initials), the name and a muted line; a search box from 8 options. The list
   opens under the button, over the content below it, and scrolls inside itself. */
.ui-picker { position: relative; min-width: 0; }
.ui-picker__button {
  display: flex; align-items: center; gap: var(--space-2);
  width: 100%; min-height: var(--tap-target);
  padding: var(--space-1) var(--space-3);
  border: var(--border-width) solid var(--color-border-strong); border-radius: var(--radius-sm);
  background: var(--color-surface-2); color: var(--color-text);
  font: inherit; font-size: var(--font-size-md); text-align: left; cursor: pointer;
  transition: border-color var(--motion-fast) var(--ease-out), box-shadow var(--motion-fast) var(--ease-out);
}
.ui-picker__button:focus-visible,
.ui-picker.is-open .ui-picker__button { outline: none; border-color: var(--color-accent); box-shadow: 0 0 0 3px var(--color-accent-soft); }
.ui-picker.is-invalid .ui-picker__button,
.ui-field.has-error .ui-picker__button { border-color: var(--color-danger); }
.ui-picker__media   { display: inline-flex; flex-shrink: 0; }
.ui-picker__text    { display: flex; flex-direction: column; flex: 1; min-width: 0; line-height: var(--line-height-tight); }
.ui-picker__label   { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ui-picker__meta    { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--font-size-xs); color: var(--color-text-muted); }
.ui-picker__placeholder { color: var(--color-text-muted); }
.ui-picker__chevron { flex-shrink: 0; color: var(--color-text-muted); transition: transform var(--motion-fast) var(--ease-out); }
.ui-picker.is-open .ui-picker__chevron { transform: rotate(180deg); }
.ui-picker__panel {
  position: absolute; z-index: 5; top: calc(100% + var(--space-1)); left: 0; right: 0;
  min-width: min(100%, calc(var(--space-7) * 6));
  padding: var(--space-1);
  border: var(--border-width) solid var(--color-border-strong); border-radius: var(--radius-md);
  background: var(--color-surface-2); box-shadow: var(--shadow-md);
}
.ui-picker__search  { margin-bottom: var(--space-1); }
.ui-picker__list    { list-style: none; margin: 0; padding: 0; max-height: calc(var(--tap-target) * 6.5); overflow-y: auto; overscroll-behavior: contain; }
.ui-picker__list:focus-visible { outline: var(--focus-ring-width) solid var(--color-accent); outline-offset: -2px; border-radius: var(--radius-sm); }
.ui-picker__option {
  display: flex; align-items: center; gap: var(--space-2);
  min-height: var(--tap-target); padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm); cursor: pointer;
}
.ui-picker__option.is-active  { background: var(--color-surface-3); }
.ui-picker__option[aria-selected="true"] { color: var(--color-accent); }
.ui-picker__option.is-none    { color: var(--color-text-muted); }
.ui-picker__check   { flex-shrink: 0; color: var(--color-accent); }
.ui-picker__empty   { padding: var(--space-2); color: var(--color-text-muted); font-size: var(--font-size-sm); }
@media (prefers-reduced-motion: reduce) {
  .ui-picker__chevron { transition: none; }
}

/* ================= FILTER BAR (search + sort + chip filters over a long list) =================
   .ui-filterbar › .ui-filterbar__row (.ui-search, .ui-filterbar__sort [label + .ui-select], .ui-filterbar__toggle)
                 › .ui-filterbar__groups › .ui-filterbar__group* (.ui-filterbar__label + .ui-chip-group--scroll, or a select)
                 › .ui-filterbar__summary ("Showing 12 of 160" + Clear filters).
   Chips are toggles (aria-pressed) with counts. The groups fold behind the Filters button at every width (saves room;
   .is-open shows them); the button shows how many filters are on, and the summary keeps "Showing x of y" + Clear filters
   visible while folded. */
.ui-filterbar          { display: flex; flex-direction: column; gap: var(--space-3); }
.ui-filterbar__row     { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); }
.ui-filterbar__row > .ui-search { flex: 1 1 calc(var(--space-7) * 5); min-width: 0; max-width: calc(var(--space-7) * 8); }
.ui-filterbar__sort    { display: flex; align-items: center; gap: var(--space-2); }
.ui-filterbar__sort .ui-select { width: auto; }
.ui-filterbar__groups  { display: none; flex-direction: column; gap: var(--space-2); }
.ui-filterbar.is-open .ui-filterbar__groups { display: flex; }
.ui-filterbar__group   { display: flex; align-items: center; gap: var(--space-3); min-width: 0; }
.ui-filterbar__group > .ui-chip-group { flex: 1; min-width: 0; }
.ui-filterbar__group > .ui-select { width: auto; max-width: 100%; }
.ui-filterbar__label {
  flex: 0 0 calc(var(--space-7) * 1.75);
  color: var(--color-text-muted); font-size: var(--font-size-xs); font-weight: var(--font-weight-semibold);
  letter-spacing: 0.06em; text-transform: uppercase;
}
.ui-filterbar__summary { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-2); }
.ui-filterbar__summary p { margin: 0; color: var(--color-text-muted); font-size: var(--font-size-sm); }
.ui-filterbar__toggle .ui-badge { margin-left: var(--space-1); }
.ui-filterbar__chevron { transition: transform var(--motion-fast) var(--ease-out); }
.ui-filterbar.is-open .ui-filterbar__chevron { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) { .ui-filterbar__chevron { transition: none; } }
@media (max-width: 767.98px) {
  .ui-filterbar__group  { flex-direction: column; align-items: stretch; gap: var(--space-1); }
  .ui-filterbar__label  { flex-basis: auto; }
  .ui-filterbar__sort   { flex: 1 1 auto; }
  .ui-filterbar__sort .ui-select { flex: 1; }
}

/* ================= SHEET (side panel: one item's details) =================
   Vue <ui-sheet :title> (app.js) on Bootstrap Offcanvas: from the right, 26rem wide; full screen below 576 px.
   Header (title + muted label + close), scrolling body, optional actions row at the bottom. */
.ui-sheet {
  --bs-offcanvas-bg: var(--color-surface-1);
  --bs-offcanvas-color: var(--color-text);
  --bs-offcanvas-border-color: var(--color-border);
  --bs-offcanvas-width: min(100vw, calc(var(--space-7) * 6.5));
  --bs-offcanvas-padding-x: var(--space-5);
  --bs-offcanvas-padding-y: var(--space-4);
  --bs-offcanvas-transition: transform var(--motion-base) var(--ease-out);
}
.ui-sheet__header  { gap: var(--space-3); align-items: flex-start; border-bottom: var(--border-width) solid var(--color-border); }
.ui-sheet__heading { min-width: 0; flex: 1; }
.ui-sheet__title   { margin: 0; font-size: var(--font-size-lg); font-weight: var(--font-weight-semibold); overflow-wrap: anywhere; }
.ui-sheet__label   { margin: var(--space-1) 0 0; color: var(--color-text-muted); font-size: var(--font-size-sm); }
.ui-sheet__body    { display: flex; flex-direction: column; gap: var(--space-5); }
.ui-sheet__actions { display: flex; flex-wrap: wrap; gap: var(--space-2); padding: var(--space-3) var(--space-5); border-top: var(--border-width) solid var(--color-border); }
.ui-sheet .btn-close { filter: invert(1) grayscale(1); }
@media (max-width: 575.98px) {
  .ui-sheet { --bs-offcanvas-width: 100vw; }
}
@media (prefers-reduced-motion: reduce) {
  .ui-sheet { --bs-offcanvas-transition: none; }
}
/* Label / value pairs (a sheet, a card): <dl class="ui-pairs"><div><dt>Age</dt><dd>27</dd></div>…</dl>. Two columns. */
.ui-pairs       { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-3) var(--space-4); margin: 0; }
.ui-pairs dt    { color: var(--color-text-muted); font-size: var(--font-size-xs); font-weight: var(--font-weight-semibold); letter-spacing: 0.04em; text-transform: uppercase; }
.ui-pairs dd    { margin: var(--space-1) 0 0; overflow-wrap: anywhere; }

/* ================= TEAM COLOURS (V3-46) =================
   A team's colour from the palette (--team-<name> tokens, CSSConfig.teamPalette). Set it with .ui-team--<name> on the
   element or a parent; always next to the team's name or logo, never colour alone.
   .ui-team-dot   a small round swatch            .ui-team-badge  a tinted label with a coloured edge
   .ui-team-edge  a coloured left edge for a card  .ui-swatches    radio swatches to choose a colour (each input labelled) */
.ui-team--crimson { --team: var(--team-crimson); }
.ui-team--sky { --team: var(--team-sky); }
.ui-team--green { --team: var(--team-green); }
.ui-team--purple { --team: var(--team-purple); }
.ui-team--orange { --team: var(--team-orange); }
.ui-team--teal { --team: var(--team-teal); }
.ui-team--pink { --team: var(--team-pink); }
.ui-team--blue { --team: var(--team-blue); }
.ui-team--lime { --team: var(--team-lime); }
.ui-team--magenta { --team: var(--team-magenta); }
.ui-team--cyan { --team: var(--team-cyan); }
.ui-team--indigo { --team: var(--team-indigo); }
.ui-team--rose { --team: var(--team-rose); }
.ui-team--emerald { --team: var(--team-emerald); }
.ui-team--violet { --team: var(--team-violet); }
.ui-team--coral { --team: var(--team-coral); }
.ui-team--powder { --team: var(--team-powder); }
.ui-team--olive { --team: var(--team-olive); }
.ui-team--blush { --team: var(--team-blush); }
.ui-team--seafoam { --team: var(--team-seafoam); }
.ui-team--ruby { --team: var(--team-ruby); }
.ui-team--mint { --team: var(--team-mint); }
.ui-team--lavender { --team: var(--team-lavender); }
.ui-team--aqua { --team: var(--team-aqua); }
.ui-team--forest { --team: var(--team-forest); }
.ui-team--royal { --team: var(--team-royal); }
.ui-team--orchid { --team: var(--team-orchid); }
.ui-team--steel { --team: var(--team-steel); }
.ui-team--brick { --team: var(--team-brick); }
.ui-team--wine { --team: var(--team-wine); }

.ui-team-dot   { display: inline-block; flex: 0 0 auto; width: 0.7em; height: 0.7em; border-radius: 50%; background: var(--team, var(--color-border-strong)); }
.ui-team-badge {
  display: inline-flex; align-items: center; gap: var(--space-1);
  padding: 2px var(--space-2); border-radius: var(--radius-sm);
  border-left: calc(var(--border-width) * 3) solid var(--team, var(--color-border-strong));
  background: color-mix(in srgb, var(--team, var(--color-border-strong)) 18%, transparent);
  color: var(--color-text); font-size: var(--font-size-xs); font-weight: var(--font-weight-semibold); white-space: nowrap;
}
.ui-team-edge  { border-left: calc(var(--border-width) * 4) solid var(--team, transparent); }
.ui-swatches   { display: flex; flex-wrap: wrap; gap: var(--space-2); border: 0; padding: 0; margin: 0; }
.ui-swatches label { position: relative; display: inline-flex; }
.ui-swatches input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
.ui-swatches span  { width: var(--tap-target); height: var(--tap-target); max-width: 36px; max-height: 36px; border-radius: 50%; background: var(--team); border: calc(var(--border-width) * 2) solid transparent; box-shadow: inset 0 0 0 2px var(--color-surface-1); }
.ui-swatches input:checked + span { border-color: var(--color-text); }
.ui-swatches input:focus-visible + span { outline: var(--focus-ring-width) solid var(--color-accent); outline-offset: 2px; }

/* ================= SECTION MENU (multi-section editors, e.g. tournament setup) ================= */
/* Vertical list from 992 px; one swipeable row below. Each item: status dot + label + status text (never colour alone).
   Dot: --done (success) · --issues (accent, solid) · --unsaved (accent ring) · --classic (muted: edited elsewhere for now).
   The current section has aria-current="step". */
.ui-secnav__list   { position: relative; display: flex; gap: var(--space-2); list-style: none; margin: 0; padding: 0; }
.ui-secnav__item {
  display: flex; align-items: center; gap: var(--space-3);
  width: 100%; min-height: var(--tap-target);
  padding: var(--space-2) var(--space-3);
  border: var(--border-width) solid transparent; border-radius: var(--radius-md);
  background: transparent; color: var(--color-text-muted);
  font: inherit; text-align: left; cursor: pointer;
  transition: background var(--motion-fast) var(--ease-out), color var(--motion-fast) var(--ease-out), border-color var(--motion-fast) var(--ease-out);
}
.ui-secnav__item[aria-current="step"] { border-color: var(--color-accent); background: var(--color-accent-soft); color: var(--color-text); }
@media (hover: hover) {
  .ui-secnav__item:hover { background: var(--color-surface-2); color: var(--color-text); }
}
.ui-secnav__dot    { flex: 0 0 auto; width: var(--space-3); height: var(--space-3); border-radius: 50%; background: var(--color-border-strong); }
.ui-secnav__dot--done    { background: var(--color-success); }
.ui-secnav__dot--issues  { background: var(--color-accent); }
.ui-secnav__dot--unsaved { background: transparent; box-shadow: inset 0 0 0 var(--focus-ring-width) var(--color-accent); }
.ui-secnav__dot--classic { background: var(--color-surface-3); }
.ui-secnav__text   { display: flex; flex-direction: column; min-width: 0; }
.ui-secnav__label  { font-weight: var(--font-weight-medium); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ui-secnav__meta   { font-size: var(--font-size-xs); color: var(--color-text-muted); white-space: nowrap; }
/* Group divider before admin-only items: <li class="ui-secnav__divider" role="presentation"><span>Setup</span></li>.
   A labelled rule above the group in the vertical list; a short vertical rule + label in the swipeable row. */
.ui-secnav__divider {
  display: flex; align-items: center; gap: var(--space-2);
  color: var(--color-text-muted); font-size: var(--font-size-xs); font-weight: var(--font-weight-semibold);
  letter-spacing: 0.06em; text-transform: uppercase; white-space: nowrap;
}
@media (min-width: 992px) {
  .ui-secnav__list { flex-direction: column; }
  .ui-secnav__divider { margin-top: var(--space-3); padding: var(--space-3) var(--space-3) var(--space-1); border-top: var(--border-width) solid var(--color-border); }
}
@media (max-width: 991.98px) {
  .ui-secnav__list { overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x proximity; scrollbar-width: none; padding-block: var(--space-1); }
  .ui-secnav__list::-webkit-scrollbar { display: none; }
  .ui-secnav__list > li { flex: 0 0 auto; scroll-snap-align: start; }
  .ui-secnav__item { width: auto; border-color: var(--color-border); }
  .ui-secnav__divider { padding-inline: var(--space-2) var(--space-1); border-left: var(--border-width) solid var(--color-border-strong); margin-left: var(--space-1); }
}

/* ================= REPEATABLE ROWS (lists edited in place: categories, pre-assigned players, sponsors) ================= */
/* .ui-rows › .ui-rows__head (column titles, from 576 px) + .ui-rows__row* (fields + a remove button) + Add button.
   Columns: set --ui-rows-cols on the .ui-rows (e.g. "2fr 1fr 1fr auto") in page CSS; last column = the remove button.
   Each field keeps its own <label class="ui-rows__label">: visible on phones (rows stack), visually hidden from 576 px
   where the head row titles the columns. */
.ui-rows          { display: flex; flex-direction: column; gap: var(--space-2); }
.ui-rows__head, .ui-rows__row { display: grid; gap: var(--space-2) var(--space-3); grid-template-columns: 1fr; align-items: start; }
.ui-rows__head    { display: none; color: var(--color-text-muted); font-size: var(--font-size-xs); font-weight: var(--font-weight-semibold); letter-spacing: 0.06em; text-transform: uppercase; }
.ui-rows__row     { padding: var(--space-3); border: var(--border-width) solid var(--color-border); border-radius: var(--radius-md); background: var(--color-surface-1); }
.ui-rows__row.has-error { border-color: var(--color-danger); }
.ui-rows__label   { font-size: var(--font-size-xs); color: var(--color-text-muted); font-weight: var(--font-weight-semibold); }
.ui-rows__remove  { justify-self: end; }
.ui-rows__add     { align-self: flex-start; }
@media (min-width: 576px) {
  .ui-rows__head, .ui-rows__row { grid-template-columns: var(--ui-rows-cols, 1fr auto); }
  .ui-rows__head  { display: grid; padding: 0 var(--space-3); }
  .ui-rows__row   { padding: var(--space-2) var(--space-3); }
  .ui-rows__label { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
  .ui-rows__remove { align-self: center; }
}

/* ================= CARDS ================= */
.ui-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-5);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface-1);
  color: var(--color-text);
  transition: transform var(--motion-base) var(--ease-out),
              border-color var(--motion-base) var(--ease-out),
              box-shadow var(--motion-base) var(--ease-out);
}
.ui-card--accent   { border-color: var(--color-accent); }
.ui-card--selected { border-color: var(--color-accent); box-shadow: var(--glow); }
.ui-card--flat     { background: transparent; }
@media (hover: hover) {
  .ui-card--interactive:hover { transform: translateY(var(--hover-lift)); border-color: var(--color-accent); box-shadow: var(--glow); }
}
.ui-card__title    { font-size: var(--font-size-lg); font-weight: var(--font-weight-semibold); margin: 0; }
.ui-card__text     { color: var(--color-text-muted); margin: 0; }
.ui-card__footer   { margin-top: auto; }

/* Tournament card (light): the whole card is the link — no per-card button.
   <a class="ui-tcard" href="…"> logo · (title + meta line) · chevron </a>
   .ui-tcard--row = compact list row (inside .ui-tlist): no box, divider between rows. */
.ui-tcard {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface-1);
  color: var(--color-text);
  text-decoration: none;
  transition: border-color var(--motion-fast) var(--ease-out), background-color var(--motion-fast) var(--ease-out);
}
a.ui-tcard:hover,
a.ui-tcard:focus-visible { color: var(--color-text); }
@media (hover: hover) {
  a.ui-tcard:hover { border-color: var(--color-accent); background: var(--color-surface-2); }
  a.ui-tcard:hover .ui-tcard__chevron { color: var(--color-accent); transform: translateX(2px); }
}
.ui-tcard__body    { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.ui-tcard__title   { font-size: var(--font-size-md); font-weight: var(--font-weight-medium); line-height: var(--line-height-tight); margin: 0;
                     overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ui-tcard__meta    { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2);
                     font-size: var(--font-size-xs); color: var(--color-text-muted); }
.ui-tcard__meta > * + *::before { content: "·"; margin-right: var(--space-2); color: var(--color-border-strong); }
.ui-tcard__badges  { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1); margin-top: 2px; }   /* status (+ Private) on its own line */
.ui-tcard__badges .ui-badge { font-size: var(--font-size-xs); }
/* The meta line never wraps (every card keeps three lines): the organiser shrinks with "…", the counts keep their width */
.ui-tcard__meta    { flex-wrap: nowrap; min-width: 0; }
.ui-tcard__meta > * { flex-shrink: 0; white-space: nowrap; }
.ui-tcard__meta > .ui-tcard__organiser { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.ui-tcard__chevron { color: var(--color-text-muted); flex-shrink: 0; transition: transform var(--motion-fast) var(--ease-out), color var(--motion-fast) var(--ease-out); }
.ui-tcard--deleted { opacity: 0.55; }
.ui-tcard--deleted .ui-tcard__title { text-decoration: line-through; }

.ui-tgrid          { display: grid; gap: var(--space-3); grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); }

.ui-tlist          { display: flex; flex-direction: column; border: var(--border-width) solid var(--color-border); border-radius: var(--radius-md); overflow: hidden; }
.ui-tcard--row     { border: none; border-radius: 0; background: transparent; padding: var(--space-3) var(--space-4); }
.ui-tcard--row + .ui-tcard--row { border-top: var(--border-width) solid var(--color-border); }
@media (hover: hover) {
  a.ui-tcard--row:hover { background: var(--color-surface-2); }
}

/* Player card: avatar · (name, email, meta) with an actions row underneath. Unlike ui-tcard the card is not a link;
   its actions are real buttons / links.
   <article class="ui-pcard"> <img class="ui-avatar ui-avatar--md"> <div class="ui-pcard__body">…</div> <div class="ui-pcard__actions">…</div> </article>
   Grid of cards: .ui-pgrid. */
.ui-pcard {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface-1);
  color: var(--color-text);
  transition: border-color var(--motion-fast) var(--ease-out);
}
@media (hover: hover) {
  .ui-pcard:hover { border-color: var(--color-border-strong); }
}
.ui-pcard__body    { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.ui-pcard__title   { font-size: var(--font-size-md); font-weight: var(--font-weight-medium); line-height: var(--line-height-tight); margin: 0;
                     overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ui-pcard__sub     { font-size: var(--font-size-sm); color: var(--color-text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ui-pcard__meta    { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2); margin-top: var(--space-1);
                     font-size: var(--font-size-xs); color: var(--color-text-muted); }
.ui-pcard__actions { grid-column: 1 / -1; display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--space-2);
                     padding-top: var(--space-3); border-top: var(--border-width) solid var(--color-border); }

.ui-pgrid          { display: grid; gap: var(--space-3); grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr)); }

/* Pill strip: one swipeable row of compact links (Home "Live Now / Your Tournaments"). No automatic motion.
   Vue <ui-pillstrip label="…"> (app.js) renders the region, the <ul> track and the arrow buttons; the page puts <li> pills in it.
   Touch: swipe (scroll-snap). Mouse: arrow buttons appear when the row overflows (hover-capable devices only). */
.ui-pillstrip       { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.ui-pillstrip__track {
  position: relative;   /* containing block for absolutely positioned children (e.g. .visually-hidden labels), so they are clipped by the scroll instead of widening the page */
  display: flex;
  flex: 1;
  gap: var(--space-2);
  min-width: 0;
  margin: 0;
  padding: var(--space-1) 0;
  list-style: none;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
}
.ui-pillstrip__track::-webkit-scrollbar { display: none; }
.ui-pillstrip__track > li { flex: 0 0 auto; scroll-snap-align: start; }
.ui-pillstrip__sep  { width: var(--border-width); align-self: stretch; margin: var(--space-2) var(--space-1); background: var(--color-border); }
.ui-pillstrip .ui-pillstrip__nav { flex-shrink: 0; }
@media (hover: none) {
  .ui-pillstrip .ui-pillstrip__nav { display: none; }
}

/* Pill: compact rounded link — [logo or badge] name [muted meta]. Variants: --text (text only), --muted (empty-state hint),
   --more ("See All"), --skeleton (loading). Long names end in "…". */
.ui-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--tap-target);
  max-width: calc(var(--space-7) * 6);
  padding: var(--space-1) var(--space-4) var(--space-1) var(--space-1);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-pill);
  background: var(--color-surface-1);
  color: var(--color-text);
  font-size: var(--font-size-sm);
  text-decoration: none;
  white-space: nowrap;
  transition: border-color var(--motion-fast) var(--ease-out), background-color var(--motion-fast) var(--ease-out);
}
a.ui-pill:hover, a.ui-pill:focus-visible { color: var(--color-text); }
@media (hover: hover) {
  a.ui-pill:hover { border-color: var(--color-accent); background: var(--color-surface-2); }
}
.ui-pill > .ui-badge:first-child { margin-left: var(--space-2); }
.ui-pill .ui-logo   { border-radius: 50%; }
.ui-pill__text      { min-width: 0; overflow: hidden; text-overflow: ellipsis; font-weight: var(--font-weight-medium); }
.ui-pill__meta      { flex-shrink: 0; color: var(--color-text-muted); font-size: var(--font-size-xs); }
.ui-pill--text      { padding-inline: var(--space-4); }
.ui-pill--muted     { padding-inline: var(--space-4); border-style: dashed; color: var(--color-text-muted); }
a.ui-pill--muted:hover { color: var(--color-text); }
.ui-pill--more      { padding-inline: var(--space-4); color: var(--color-accent); font-weight: var(--font-weight-semibold); }
a.ui-pill--more:hover, a.ui-pill--more:focus-visible { color: var(--color-accent); }
.ui-pill--skeleton  { width: calc(var(--space-7) * 3); border-color: transparent; }

/* Facts: icon + value list */
.ui-facts       { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-5); list-style: none; margin: 0; padding: 0; color: var(--color-text-muted); font-size: var(--font-size-sm); }
.ui-facts li    { display: inline-flex; align-items: center; gap: var(--space-2); }
.ui-facts i     { color: var(--color-accent); }
.ui-facts strong { color: var(--color-text); font-weight: var(--font-weight-semibold); }

/* Stat (marketing numbers) */
.ui-stat        { display: inline-flex; align-items: center; gap: var(--space-2); }
.ui-stat i      { color: var(--color-accent); font-size: var(--font-size-lg); }
.ui-stat strong { font-weight: var(--font-weight-semibold); }

/* Step (numbered) */
.ui-step__number {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: 50%;
  background: var(--color-accent-soft); color: var(--color-accent);
  font-weight: var(--font-weight-bold);
}

/* ================= EMPTY STATE ================= */
.ui-empty {
  display: flex; flex-direction: column; align-items: center; text-align: center; gap: var(--space-3);
  padding: var(--space-7) var(--space-5);
  border: var(--border-width) dashed var(--color-border-strong);
  border-radius: var(--radius-md);
  color: var(--color-text-muted);
}
.ui-empty__icon  { font-size: var(--font-size-xxl); color: var(--color-accent); }
.ui-empty__title { font-size: var(--font-size-lg); font-weight: var(--font-weight-semibold); color: var(--color-text); margin: 0; }
.ui-empty__text  { margin: 0; max-width: 40ch; }

/* ================= LOADING ================= */
.ui-spinner {
  display: inline-block;
  width: 40px; height: 40px;
  border: 4px solid var(--color-accent-soft);
  border-top-color: var(--color-accent);
  border-radius: 50%;
  animation: ui-spin 1s linear infinite;
}
.ui-skeleton {
  display: block;
  border-radius: var(--radius-sm);
  background: linear-gradient(90deg, var(--color-surface-2) 25%, var(--color-surface-3) 37%, var(--color-surface-2) 63%);
  background-size: 400% 100%;
  animation: ui-shimmer 1.4s ease infinite;
}
.ui-skeleton--text  { height: 1em; }
.ui-skeleton--title { height: 1.4em; width: 70%; }
.ui-skeleton--logo  { width: 72px; height: 72px; }

/* ================= BUSY OVERLAY (showBusy / hideBusy in app.js) =================
   Covers the window while a save changes data: blocks clicks at once (transparent), dims and shows the box only after
   300 ms (.is-visible). Above the header and Bootstrap modals, below SweetAlert2 dialogs / toasts and the NProgress bar. */
.ui-busy {
  position: fixed; inset: 0; z-index: 1058;
  display: flex; align-items: center; justify-content: center;
  padding: var(--space-4);
  background: transparent;
  cursor: progress;
  transition: background-color var(--motion-base) var(--ease-out);
}
.ui-busy.is-visible { background: var(--color-overlay); }
.ui-busy__box {
  display: flex; flex-direction: column; align-items: center; gap: var(--space-3);
  padding: var(--space-5) var(--space-6);
  border: var(--border-width) solid var(--color-border); border-radius: var(--radius-md);
  background: var(--color-surface-1); color: var(--color-text); box-shadow: var(--shadow-lg);
  opacity: 0; transform: scale(0.96);
  transition: opacity var(--motion-base) var(--ease-out), transform var(--motion-base) var(--ease-out);
}
.ui-busy.is-visible .ui-busy__box { opacity: 1; transform: none; }
.ui-busy__text { margin: 0; font-weight: var(--font-weight-semibold); text-align: center; }
@media (prefers-reduced-motion: reduce) {
  .ui-busy, .ui-busy__box { transition: none; }
  .ui-busy__box { transform: none; }
}

/* ================= ALERT (inline message) ================= */
.ui-alert {
  display: flex; gap: var(--space-3); align-items: flex-start;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm);
  border-left: 3px solid var(--color-info);
  background: var(--color-info-soft);
}
.ui-alert--success { border-left-color: var(--color-success); background: var(--color-success-soft); }
.ui-alert--danger  { border-left-color: var(--color-danger);  background: var(--color-danger-soft); }
.ui-alert--warning { border-left-color: var(--color-accent);  background: var(--color-accent-soft); }

/* ================= BANNER (app-wide strip above the header) =================
   Persistent, not dismissible: for state that changes what the whole app does, e.g. "Viewing as <user>".
   Sits in .app-container (flex column), so it stays visible while .app-body scrolls. */
.ui-banner {
  flex: 0 0 auto;
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: var(--space-2) var(--space-4);
  padding: var(--space-2) var(--space-4);
  background: var(--color-accent);
  color: var(--color-text-inverse);
  font-size: var(--font-size-sm);
  text-align: center;
}
.ui-banner__text              { min-width: 0; overflow-wrap: anywhere; }
.ui-banner__form              { margin: 0; }
.ui-banner .ui-btn            { background: transparent; border-color: var(--color-text-inverse); color: var(--color-text-inverse); }
.ui-banner .ui-btn:focus-visible { outline-color: var(--color-text-inverse); }
@media (hover: hover) {
  .ui-banner .ui-btn:hover:not([disabled]) { background: var(--color-accent-hover); }
}

/* ================= MORE INFO (ui-info) =================
   Icon button next to a field label that explains the field. Rendered by the <ui-info> Vue component (app.js).
   mode="popover" (default): short text in a themed Bootstrap popover. mode="inline": disclosure panel under the label. */
.ui-field__label-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1); }
.ui-info-wrap        { display: contents; }   /* lets the inline panel wrap to its own line in the label row */
.ui-info {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5em;
  height: 1.5em;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  line-height: 1;
  cursor: pointer;
  transition: color var(--motion-fast) var(--ease-out), background-color var(--motion-fast) var(--ease-out);
}
/* Enlarge the hit area to the tap target without changing layout */
.ui-info::after { content: ""; position: absolute; inset: calc((var(--tap-target) - 1.5em) / -2); }
.ui-info[aria-expanded="true"] { color: var(--color-accent); background: var(--color-accent-soft); }
@media (hover: hover) {
  .ui-info:hover { color: var(--color-accent); }
}
.ui-info__panel {
  flex-basis: 100%;
  margin-top: var(--space-1);
  padding: var(--space-2) var(--space-3);
  border-left: 3px solid var(--color-accent);
  border-radius: var(--radius-sm);
  background: var(--color-accent-soft);
  color: var(--color-text);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-regular);
  letter-spacing: normal;
}

/* Bootstrap popover themed with tokens (customClass: 'ui-popover') */
.ui-popover {
  --bs-popover-bg: var(--color-surface-3);
  --bs-popover-border-color: var(--color-border-strong);
  --bs-popover-border-radius: var(--radius-sm);
  --bs-popover-inner-border-radius: var(--radius-sm);
  --bs-popover-header-bg: var(--color-surface-3);
  --bs-popover-header-color: var(--color-accent);
  --bs-popover-body-color: var(--color-text);
  --bs-popover-font-size: var(--font-size-sm);
  --bs-popover-max-width: 280px;
  --bs-popover-header-padding-y: var(--space-2);
  --bs-popover-body-padding-y: var(--space-2);
  box-shadow: var(--shadow-md);
}
.ui-popover .popover-header { font-weight: var(--font-weight-semibold); border-bottom-color: var(--color-border); }

/* ================= VUE TRANSITIONS (token-based) =================
   <transition name="ui-fade">  — show/hide in place
   <transition name="ui-slide"> — panels / views entering from the side */
.ui-fade-enter-active, .ui-fade-leave-active   { transition: opacity var(--motion-base) var(--ease-out); }
.ui-fade-enter, .ui-fade-leave-to               { opacity: 0; }
.ui-slide-enter-active                          { transition: opacity var(--motion-slow) var(--ease-out), transform var(--motion-slow) var(--ease-out); }
.ui-slide-leave-active                          { transition: opacity var(--motion-base) var(--ease-in), transform var(--motion-base) var(--ease-in); }
.ui-slide-enter                                 { opacity: 0; transform: translateX(calc(var(--reveal-distance) * 2)); }
.ui-slide-leave-to                              { opacity: 0; transform: translateX(calc(var(--reveal-distance) * -2)); }

/* ================= KEYFRAMES ================= */
@keyframes ui-spin        { to { transform: rotate(360deg); } }
@keyframes ui-shimmer     { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }
@keyframes ui-live-pulse  { 0% { box-shadow: 0 0 0 0 var(--color-success-glow); } 100% { box-shadow: 0 0 0 6px transparent; } }

