/* ── Design tokens ──────────────────────────────────────────────────────
 * Single source of truth for color, motion, and elevation. Every component
 * style below references these — bumping a token here updates the whole UI.
 */
html {
  /* Surface palette — true poker-room: midnight black with warm plum cast.
   * Designed to look like a low-lit cardroom, not a tech dashboard. */
  --ba-bg:       #0a0608;
  --ba-ink:      #f4ecdf;   /* parchment / card-back cream */
  --ba-muted:    #a89989;
  --ba-panel:    #14101a;   /* faint plum shadow */
  --ba-panel-2:  #1c1622;
  --ba-panel-3:  #251c2e;
  --ba-line:     #3a2a36;
  --ba-line-2:   #523a48;

  /* Accent palette — claret felt + chip gold + cardroom green */
  --ba-accent:    #c8273e;  /* primary — claret red (Hearts/Diamonds) */
  --ba-accent-d:  #9a1a2c;  /* hover/active darker shade */
  --ba-accent-2:  #ff5d68;  /* destructive (still red, brighter) */
  --ba-gold:      #d4a857;  /* chip gold — secondary accent */
  --ba-gold-d:    #ad8638;
  --ba-warn:      #e8a83c;  /* warning — amber */
  --ba-ok:        #3aa55a;  /* success — felt green */
  --ba-info:      #c0a07a;  /* info — sand/parchment */
  --ba-chip:      #1f1828;

  /* Glow ring colors for focus + hover */
  --ba-glow-accent: rgba(200, 39, 62, 0.34);
  --ba-glow-error:  rgba(255, 93, 104, 0.34);
  --ba-glow-info:   rgba(212, 168, 87, 0.28);
  --ba-glow-gold:   rgba(212, 168, 87, 0.32);

  /* Elevation system — soft, layered shadows */
  --ba-elev-1: 0 1px 2px rgba(0,0,0,0.25), 0 2px 4px rgba(0,0,0,0.18);
  --ba-elev-2: 0 4px 10px rgba(0,0,0,0.30), 0 2px 4px rgba(0,0,0,0.20);
  --ba-elev-3: 0 10px 24px rgba(0,0,0,0.40), 0 4px 8px rgba(0,0,0,0.25);
  --ba-elev-4: 0 20px 40px rgba(0,0,0,0.50), 0 8px 16px rgba(0,0,0,0.32);

  /* Motion — short for taps, medium for hover, long for big transitions.
   * Cubic curve is "ease-out-back" tuned for a touch of bounce. */
  --ba-dur-fast:   120ms;
  --ba-dur-med:    220ms;
  --ba-dur-slow:   380ms;
  --ba-ease:       cubic-bezier(0.22, 1, 0.36, 1);
  --ba-ease-back:  cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* ── Override Lumo dark palette ── */
html[theme~="dark"] {
  --lumo-font-family: "Avenir Next", "Segoe UI", sans-serif;

  /* Base */
  --lumo-base-color: var(--ba-bg);

  /* Contrast scale */
  --lumo-contrast-5pct:  rgba(236, 240, 248, 0.05);
  --lumo-contrast-10pct: var(--ba-line);
  --lumo-contrast-20pct: rgba(236, 240, 248, 0.18);
  --lumo-contrast-30pct: rgba(236, 240, 248, 0.28);
  --lumo-contrast-40pct: rgba(236, 240, 248, 0.38);
  --lumo-contrast-50pct: rgba(236, 240, 248, 0.50);
  --lumo-contrast-60pct: rgba(236, 240, 248, 0.60);
  --lumo-contrast-70pct: rgba(236, 240, 248, 0.70);
  --lumo-contrast-80pct: rgba(236, 240, 248, 0.80);
  --lumo-contrast-90pct: rgba(236, 240, 248, 0.90);
  --lumo-contrast:       var(--ba-ink);

  /* Text */
  --lumo-header-text-color:    var(--ba-ink);
  --lumo-body-text-color:      var(--ba-ink);
  --lumo-secondary-text-color: var(--ba-muted);
  --lumo-tertiary-text-color:  rgba(153, 164, 189, 0.65);
  --lumo-disabled-text-color:  rgba(153, 164, 189, 0.38);

  /* Primary — claret red */
  --lumo-primary-color:          var(--ba-accent);
  --lumo-primary-color-50pct:    rgba(200, 39, 62, 0.50);
  --lumo-primary-color-10pct:    rgba(200, 39, 62, 0.10);
  /* Tertiary buttons, links, active tabs read as gold — claret is reserved
   * for filled CTA backgrounds. Pink-ish text on dark bg looked sickly. */
  --lumo-primary-text-color:     var(--ba-gold);
  --lumo-primary-contrast-color: #fff8ee;

  /* Error */
  --lumo-error-color:          var(--ba-accent-2);
  --lumo-error-color-50pct:    rgba(255, 93, 104, 0.50);
  --lumo-error-color-10pct:    rgba(255, 93, 104, 0.10);
  --lumo-error-text-color:     var(--ba-accent-2);
  --lumo-error-contrast-color: #fff;

  /* Success */
  --lumo-success-color:          var(--ba-ok);
  --lumo-success-color-50pct:    rgba(87, 216, 108, 0.50);
  --lumo-success-color-10pct:    rgba(87, 216, 108, 0.10);
  --lumo-success-text-color:     var(--ba-ok);
  --lumo-success-contrast-color: #0b1a0f;

  /* Warning */
  --lumo-warning-color:          var(--ba-warn);
  --lumo-warning-color-10pct:    rgba(242, 184, 75, 0.10);
  --lumo-warning-text-color:     var(--ba-warn);
  --lumo-warning-contrast-color: #1f1a08;

  /* Border radius */
  --lumo-border-radius-l: 14px;
  --lumo-border-radius-m: 10px;
  --lumo-border-radius-s: 8px;
}

/* ── Viewport clamp — html/body bound to viewport so dialogs stay anchored
 * to the visible area, not floating at the bottom of an absurdly-tall page.
 * Body content that's actually longer than viewport (e.g. the registration
 * form) scrolls INSIDE body via its own overflow-y:auto, which doesn't move
 * fixed-position elements (dialogs) and doesn't make body.scrollHeight grow
 * unbounded. */
/* Natural-flow layout. NO `height: 100vh` chain — the page is content-sized
 * (see MainLayout + ".ba-page is content-sized" rule in CLAUDE.md). Body
 * scrolls when content exceeds viewport; nav is sticky via the .ba-nav
 * rule + MainLayout-applied `position: sticky`.
 *
 * 2026-05-17 (regression fix per user mandate "if mobile requires scrolling
 * because of extra content, thats fine, but it should not be elongated if
 * there is enough space in one page without scrolling"): body MUST be
 * content-sized — no `min-height: 100vh`. Previously body had min-height
 * 100vh which made `document.body.scrollHeight` >= viewport regardless of
 * actual content, so Playwright fullPage screenshots of short pages came
 * out elongated with ~25% empty band below the last control. The gradient
 * backdrop moved to `html` so the visual "page fills the window" effect
 * stays correct while body's scrollHeight tracks real content. */
html {
  margin: 0;
  height: auto;
  overflow-x: hidden;
  overflow-y: auto;
  background: var(--ba-bg);
}
body {
  margin: 0;
  height: auto;
  overflow-x: hidden;
  overflow-y: auto;
  background: transparent;
}
/* Fixed-position backdrop — radial gradients pinned to the viewport so the
 * cardroom-felt look covers the visible window at all times, but the
 * document height itself stays content-sized. Without this trick (using
 * `min-height: 100vh` on html/body to make the backdrop fill the window),
 * Playwright fullPage screenshots of short pages came out elongated with
 * empty space below content. User mandate 2026-05-17: *"it should not be
 * elongated if there is enough space in one page without scrolling"*. */
body::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(circle at 12% 12%, rgba(200, 39, 62, 0.16) 0, transparent 36%),
    radial-gradient(circle at 88% 22%, rgba(212, 168, 87, 0.10) 0, transparent 36%),
    radial-gradient(circle at 55% 92%, rgba(58, 165, 90, 0.08) 0, transparent 50%),
    var(--ba-bg);
}
/* MainLayout-wrapped views push internal scroll into contentSlot; the auth
 * routes (login, register, verify-email) stand alone and use body's scroll. */

/* ── Viewport simulation — dialogs/notifications/popovers respect the
 *    simulated frame ────────────────────────────────────────────────────
 * MainLayout's "🖥 Desktop →📱" toggle clamps `pageWrapper` to 390px
 * (mobile) or 768px (tablet) AND sets `--ba-sim-width` on <body> + adds
 * the .ba-vp-sim class. Dialogs / notification cards / popovers attach
 * OUTSIDE pageWrapper (directly under <body>) so without these rules
 * they'd render at full viewport, overflowing the simulated frame.
 * NO color/spacing changes — purely a max-width clamp. */
body.ba-vp-sim vaadin-dialog-overlay::part(overlay) {
  max-width: calc(var(--ba-sim-width, 100vw) - 16px) !important;
  width: min(620px, calc(var(--ba-sim-width, 100vw) - 16px)) !important;
}
body.ba-vp-sim vaadin-notification-card {
  max-width: calc(var(--ba-sim-width, 100vw) - 16px) !important;
}
body.ba-vp-sim vaadin-popover-overlay::part(overlay),
body.ba-vp-sim vaadin-context-menu-overlay::part(overlay),
body.ba-vp-sim vaadin-menu-bar-overlay::part(overlay),
body.ba-vp-sim vaadin-select-overlay::part(overlay),
body.ba-vp-sim vaadin-combo-box-overlay::part(overlay) {
  max-width: calc(var(--ba-sim-width, 100vw) - 16px) !important;
}

/* ── Compact heights — UX-DIALOG-COMPACT (2026-05-11) ──────────────────
 * User mandate: "make everything more condense smaller, more crawsed!!!!
 * Revisit ALL UI ALL VIEWS, ALL DIALOGS, to reevaluate all field sizes."
 * Also: "I DID NOT ASK FOR A SMALLER FONT!!! I ASK FOR LESS SPACING AND
 * compact fields that accommodate exactly what values needed!!!"
 * Rule: heights + padding only. NO color tokens, NO font-size shrinks. */
:where(
  vaadin-text-field, vaadin-password-field, vaadin-email-field,
  vaadin-number-field, vaadin-big-decimal-field, vaadin-integer-field,
  vaadin-select, vaadin-combo-box,
  vaadin-date-picker, vaadin-time-picker, vaadin-date-time-picker
)::part(input-field) {
  min-height: 32px;
  padding: 0 8px;
}
vaadin-text-area::part(input-field) {
  min-height: 52px;
  padding: 4px 8px;
}
/* DateTimePicker is two inputs (date + time) inside one host — slim the
 * gap between them so the row doesn't read as one HUGE control. */
vaadin-date-time-picker {
  gap: 6px;
}
/* Tabs — same height as fields, no font shrink. */
vaadin-tab {
  min-height: 32px;
  padding: 4px 12px;
}
/* Buttons — match the field height + tighter horizontal padding. */
vaadin-button {
  min-height: 32px;
  padding: 0 12px;
}
vaadin-button[theme~="small"] {
  min-height: 26px;
  padding: 0 8px;
}
/* Dialog padding — tighter, font untouched. */
vaadin-dialog-overlay::part(header),
vaadin-dialog-overlay::part(title) {
  padding: 12px 16px 6px;
}
vaadin-dialog-overlay::part(content) {
  padding: 8px 16px 10px;
}
vaadin-dialog-overlay::part(footer) {
  padding: 8px 16px 12px;
}
/* #257 — popover overlay must stay in-viewport on mobile. Vaadin's
 * PopoverPosition.BOTTOM centers the popover under the trigger; if the
 * trigger sits right of center, a 220px popover overflows the right edge
 * on a 390px viewport. Cap the overlay width to viewport-minus-padding so
 * it always fits. */
vaadin-popover-overlay::part(overlay) {
  max-width: calc(100vw - 24px);
}

/* Combo-box / multi-select overlays MUST sit above any open dialog so the
   dropdown items render where they're anchored — not behind the dialog,
   not detached at the bottom of the page. User mandate 2026-05-12:
   "member selection dropdown ... wierly not part of the dialog... FIX!!!".
   Vaadin's default z-index for overlays is just below dialog overlays (1004
   vs 1003); we bump combo-box overlays explicitly above. */
vaadin-combo-box-overlay,
vaadin-multi-select-combo-box-overlay,
vaadin-select-overlay {
  z-index: 12000 !important;
}

/* MultiSelectComboBox — always show ALL chips, never the "+N" overflow
   chip. Field grows vertically when there are many selections. User
   mandate 2026-05-12: "I want to click on the number and expand the
   members" — instead of click-to-expand, just always show them. */
vaadin-multi-select-combo-box::part(overflow),
vaadin-multi-select-combo-box::part(overflow-one),
vaadin-multi-select-combo-box::part(overflow-two),
vaadin-multi-select-combo-box::part(overflow-three) {
  display: none !important;
}
vaadin-multi-select-combo-box [slot='chip'] {
  flex-shrink: 0;
}
vaadin-multi-select-combo-box::part(input-field) {
  flex-wrap: wrap;
  height: auto;
  min-height: var(--lumo-size-m);
  padding-block: 4px;
}

/* Grid rows — shorter, content unchanged. */
vaadin-grid::part(row),
vaadin-grid::part(cell) {
  min-height: 28px;
}
vaadin-grid::part(cell) {
  padding: 2px 8px;
}
vaadin-grid::part(header-cell) {
  padding: 4px 8px;
  min-height: 28px;
}
vaadin-grid vaadin-button {
  min-height: 26px;
  padding: 0 8px;
}

/* ── Input / form fields ────────────────────────────────────────────────
 * Default state, hover lift to a brighter line, focused state with an
 * accent glow ring. Smooth transition on every property. */
vaadin-text-field::part(input-field),
vaadin-password-field::part(input-field),
vaadin-email-field::part(input-field),
vaadin-select::part(input-field),
vaadin-combo-box::part(input-field),
vaadin-number-field::part(input-field),
vaadin-big-decimal-field::part(input-field),
vaadin-date-picker::part(input-field),
vaadin-time-picker::part(input-field) {
  background: var(--ba-panel);
  border: 1px solid var(--ba-line);
  transition:
    border-color    var(--ba-dur-med) var(--ba-ease),
    box-shadow      var(--ba-dur-med) var(--ba-ease),
    background      var(--ba-dur-med) var(--ba-ease);
}
vaadin-text-field:hover:not([disabled])::part(input-field),
vaadin-password-field:hover:not([disabled])::part(input-field),
vaadin-email-field:hover:not([disabled])::part(input-field),
vaadin-select:hover:not([disabled])::part(input-field),
vaadin-combo-box:hover:not([disabled])::part(input-field),
vaadin-number-field:hover:not([disabled])::part(input-field),
vaadin-big-decimal-field:hover:not([disabled])::part(input-field),
vaadin-date-picker:hover:not([disabled])::part(input-field),
vaadin-time-picker:hover:not([disabled])::part(input-field) {
  border-color: var(--ba-line-2);
  background:   var(--ba-panel-2);
}
vaadin-text-field[focused]::part(input-field),
vaadin-password-field[focused]::part(input-field),
vaadin-email-field[focused]::part(input-field),
vaadin-select[focused]::part(input-field),
vaadin-combo-box[focused]::part(input-field),
vaadin-number-field[focused]::part(input-field),
vaadin-big-decimal-field[focused]::part(input-field),
vaadin-date-picker[focused]::part(input-field),
vaadin-time-picker[focused]::part(input-field) {
  border-color: var(--ba-accent);
  box-shadow: 0 0 0 3px var(--ba-glow-accent);
}
vaadin-text-field[invalid]::part(input-field),
vaadin-password-field[invalid]::part(input-field),
vaadin-email-field[invalid]::part(input-field),
vaadin-number-field[invalid]::part(input-field),
vaadin-big-decimal-field[invalid]::part(input-field) {
  border-color: var(--ba-accent-2);
  box-shadow: 0 0 0 3px var(--ba-glow-error);
}

/* ── Grid ── */
/* Compact + economic by default. Tighter row, smaller font, less header
 * padding. Applies everywhere — individual grids don't need overrides. */
vaadin-grid {
  background: var(--ba-panel);
  border: 1px solid var(--ba-line);
  border-radius: var(--lumo-border-radius-m);
  font-size: 0.85em;
}

/* Row & cell spacing */
vaadin-grid::part(row) {
  min-height: 28px;
}
vaadin-grid::part(cell) {
  padding: 2px 8px;
}
vaadin-grid::part(header-cell) {
  padding: 4px 8px;
  font-size: 0.78em;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--lumo-secondary-text-color);
}

/* Action buttons inside grid cells: shrink them too. */
vaadin-grid vaadin-button {
  font-size: 0.78em !important;
  height: 24px !important;
  min-height: 24px !important;
  padding: 0 8px !important;
}

/* Mobile: tighten further. */
@media (max-width: 500px) {
  vaadin-grid {
    font-size: 0.78em;
  }
  vaadin-grid::part(row) {
    min-height: 24px;
  }
  vaadin-grid::part(cell) {
    padding: 1px 6px;
  }
}

/* ── Dialog ── */
/* Bulletproof dead-center positioning. Vaadin's overlay host is normally
 * `position: fixed; inset: 0; display: flex; align-items: center;
 * justify-content: center` which centers the part(overlay) child. Some
 * combination of our html/body clamps + tall body content + dev viewport
 * simulation was leaving the dialog rendered in the bottom half of the
 * viewport. The !important rules below force-pin the dialog to viewport
 * center regardless of any Vaadin internal --_vaadin-overlay-align-self
 * variable that bottom-sheet mode might flip on small screens. */
vaadin-dialog-overlay,
vaadin-confirm-dialog-overlay {
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  position: fixed !important;
  inset: 0 !important;
}
vaadin-dialog-overlay::part(overlay),
vaadin-confirm-dialog-overlay::part(overlay) {
  align-self: center !important;
  margin: auto !important;
  background: var(--ba-panel);
  border: 1px solid var(--ba-line);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.55);
}

/* ── Notification / header bar — gold hairline under, plum tint ── */
vaadin-app-layout::part(navbar) {
  background: linear-gradient(180deg, rgba(20, 12, 18, 0.92), rgba(10, 6, 8, 0.85));
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--ba-gold-d);
  box-shadow: 0 1px 0 rgba(212, 168, 87, 0.10), 0 8px 24px rgba(0, 0, 0, 0.40);
}

/* ── Utility classes (mirror mockup) ── */
.ba-panel {
  border: 1px solid var(--ba-line);
  border-radius: 14px;
  background: var(--ba-panel);
  box-shadow: 0 10px 22px rgba(0, 0, 0, 0.35);
  padding: 16px;
}

.ba-panel-2 {
  border: 1px solid var(--ba-line);
  border-radius: 12px;
  background: var(--ba-panel-2);
  padding: 12px;
}

.ba-chip {
  display: inline-block;
  padding: 4px 10px;
  border-radius: 999px;
  border: 1px solid var(--ba-line);
  background: var(--ba-chip);
  font-size: 12px;
  color: var(--ba-ink);
}

.ba-bar {
  background: linear-gradient(90deg, #1d1018, #251720);
  border-bottom: 1px solid var(--ba-line);
  padding: 10px 14px;
  font-size: 13px;
  color: var(--ba-ink);
  display: flex;
  justify-content: space-between;
  align-items: center;
}

/* ── Typography ── */
h2, h3, h4 {
  letter-spacing: -0.01em;
  margin: 0;
  color: var(--ba-ink);
}

/* Shared responsive layout primitives.
 *
 * `.ba-page` is the content view inside MainLayout's contentSlot. It is
 * CONTENT-SIZED — it does NOT stretch to fill the viewport. This was a
 * SYSTEMIC regression user flagged repeatedly: stretching the view via
 * `height:100%; flex:1 1 auto` left a visible empty band below short pages
 * (Dashboard, Profile) because the view's internals stay at the top. Now
 * the view is just as tall as its content; the empty area below blends
 * with the body background (set on contentSlot in MainLayout — see
 * `.ba-content-slot` rule below). */
.ba-page {
  width: 100%;
  max-width: 100%;
  min-width: 0;
  box-sizing: border-box;
}

/* MainLayout's contentSlot. The slot still fills the viewport (so internal
 * scroll lives there for tall pages like SiteAdmin) but is TRANSPARENT
 * so the body's fixed-attachment gradient shows through edge-to-edge.
 * Combined with `body { background-attachment: fixed }` above, this makes
 * the empty area below a short page look like a continuation of the
 * cardroom felt — no visible seam, no hard band, no "page height ends
 * mid-viewport" effect. User: "the page height should finish at the
 * bottom of the last control ... FIX IT BROADLY!" */
.ba-content-slot {
  background: transparent !important;
}

.ba-wrap-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}

.ba-section-card {
  border: 1px solid var(--ba-line);
  border-radius: 14px;
  background: var(--ba-panel);
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.28);
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  /* Clip any descendant that blew its intrinsic width past the card edge.
   * Without this, a long title H2 inside a flex row was pushing the right-
   * edge content (badge / status pill) off-viewport on the dashboard. */
  min-width: 0;
  max-width: 100%;
  overflow: hidden;
  box-sizing: border-box;
  width: 100%;
  min-width: 0;
  max-width: 100%;
  box-sizing: border-box;
  overflow: hidden;
}

.ba-responsive-grid-wrap {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 12px;
  width: 100%;
}

/* Auth pages */
.auth-page {
  /* #244 / SHARED §5.9 — natural flow: card sets the height; no min-height
   * 100% inflating an empty error/short page into a dark band. */
  width: 100%;
  box-sizing: border-box;
}

.auth-card {
  border: 1px solid var(--ba-line);
  border-radius: 14px;
  background: var(--ba-panel);
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.28);
  padding: 16px;
  width: 100%;
  box-sizing: border-box;
  min-width: 0;
  max-width: 460px;
}

/* Login two-column layout — CSS grid lays out the cards so one column
 * collapses cleanly at narrow widths and the page never renders blank
 * because of a flex-basis that exceeds the available track. */
.auth-twocol {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 24px;
  justify-content: center;
  width: 100%;
  max-width: 920px;
  margin: 0 auto;
  align-items: start;
}
.auth-twocol > .auth-card {
  justify-self: center;
  width: 100%;
}
@media (max-width: 760px) {
  .auth-twocol {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Register view: mobile-first, expands to two groups on desktop */
.register-page {
  min-height: 100%;
}

.register-groups-wrap {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 14px;
}

.register-group-card {
  flex: 1 1 500px;
  min-width: 320px;
}

.register-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.register-actions vaadin-button {
  min-height: 44px;
}

.register-contact-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 8px;
}

.register-contact-row > *:first-child {
  flex: 1 1 240px;
  min-width: 220px;
}

/* Grids */
vaadin-grid {
  width: 100%;
}

.ba-game-grid {
  width: 100%;
}

/* ── Top nav layout ── */
.ba-nav {
  width: 100%;
}

.ba-nav-left {
  display: flex;
  align-items: center;
  gap: 2px;
  flex: 1 1 auto;
  min-width: 0;
  flex-wrap: wrap;
}

.ba-nav-links {
  display: flex;
  align-items: center;
  gap: 2px;
  flex-wrap: wrap;
}

.ba-nav-right {
  display: flex;
  align-items: center;
  gap: 4px;
  flex: 1 1 auto;
  justify-content: flex-end;
  flex-wrap: wrap;
  min-width: 0;
  margin-left: auto;
}

/* Tighter buttons on narrow widths */
@media (max-width: 500px) {
  .ba-nav-left vaadin-button,
  .ba-nav-right vaadin-button {
    font-size: 0.78em !important;
    padding: 0 6px !important;
    min-width: 0 !important;
  }

  .ba-nav-logo {
    font-size: 0.9em !important;
    padding: 0 4px !important;
  }
}

/* ── Mobile responsive ── */
@media (max-width: 860px) {
  .ba-wrap-row {
    align-items: stretch;
    gap: 8px;
  }

  .ba-wrap-row vaadin-button {
    width: 100%;
  }

  .ba-section-card {
    padding: 10px;
    gap: 8px;
  }

  .auth-card {
    padding: 14px;
  }

  .register-page {
    gap: 10px !important;
  }

  .register-groups-wrap {
    gap: 10px;
  }

  .register-group-card {
    flex: 1 1 100%;
    min-width: 0;
    padding: 14px !important;
  }

  .register-actions vaadin-button {
    width: 100%;
    flex: 1 1 100% !important;
  }

  .register-contact-row > * {
    flex: 1 1 100%;
    min-width: 0;
  }
}

/* ═════════════════════════════════════════════════════════════════════════
 * PHASE 2 — INTERACTION POLISH
 * Affects every screen at once. Micro-interactions, hover lifts, focus
 * rings, themed notifications. No layout changes — only visual delight.
 * ═════════════════════════════════════════════════════════════════════════ */

/* ── Buttons ──────────────────────────────────────────────────────────── */
/* Smooth transition on every interactive property. Subtle press + hover. */
vaadin-button {
  transition:
    transform   var(--ba-dur-fast) var(--ba-ease),
    box-shadow  var(--ba-dur-med)  var(--ba-ease),
    background  var(--ba-dur-med)  var(--ba-ease),
    border      var(--ba-dur-med)  var(--ba-ease),
    color       var(--ba-dur-med)  var(--ba-ease);
}
vaadin-button:not([disabled]):hover {
  transform: translateY(-1px);
}
vaadin-button:not([disabled]):active {
  transform: translateY(0);
  transition-duration: 60ms;
}

/* Primary button — accent fill with soft glow on hover. */
vaadin-button[theme~="primary"] {
  background: linear-gradient(180deg, var(--ba-accent), var(--ba-accent-d));
  color: var(--lumo-primary-contrast-color);
  border: 1px solid transparent;
  box-shadow: var(--ba-elev-1);
}
vaadin-button[theme~="primary"]:not([disabled]):hover {
  box-shadow: var(--ba-elev-2), 0 0 0 4px var(--ba-glow-accent);
}
vaadin-button[theme~="primary"]:not([disabled]):active {
  filter: brightness(0.94);
}

/* Error / destructive — coral fill with red glow. */
vaadin-button[theme~="error"][theme~="primary"] {
  background: linear-gradient(180deg, var(--ba-accent-2), #d94250);
  color: #fff;
}
vaadin-button[theme~="error"][theme~="primary"]:not([disabled]):hover {
  box-shadow: var(--ba-elev-2), 0 0 0 4px var(--ba-glow-error);
}

/* Tertiary — text-only, gain a faint tinted background on hover. */
vaadin-button[theme~="tertiary"]:not([disabled]):hover {
  background: var(--lumo-contrast-5pct);
}

/* ── Dashboard button variants ────────────────────────────────────────────
 * Mockup [mockups/dash-player.html, dash-game.html] uses three button styles:
 * primary (filled claret — covered by [theme~="primary"] above),
 * outline (transparent + gold-line border + parchment text),
 * danger (transparent + accent-2 border + accent-2 text).
 * Apply via addClassName("ba-btn-outline") / "ba-btn-danger" in views.
 * Stays consistent with mockup parity rule (CLAUDE.md §5). */
vaadin-button.ba-btn-outline {
  background: transparent;
  color: var(--ba-ink);
  border: 1px solid var(--ba-line-2);
  box-shadow: none;
}
vaadin-button.ba-btn-outline:not([disabled]):hover {
  border-color: var(--ba-gold);
  color: var(--ba-gold);
  background: rgba(212, 168, 87, 0.06);
}
vaadin-button.ba-btn-danger {
  background: transparent;
  color: var(--ba-accent-2);
  border: 1px solid var(--ba-accent-2);
  box-shadow: none;
}
vaadin-button.ba-btn-danger:not([disabled]):hover {
  background: rgba(255, 93, 104, 0.10);
  border-color: var(--ba-accent-2);
  color: var(--ba-accent-2);
}

/* Row-entity link pattern — used inside grids where the row represents an
 * editable object (group, game, etc.). The name itself is the link; an
 * adjacent pencil icon column is the explicit edit affordance. Hidden
 * chevrons at the row's right edge are FORBIDDEN — the user has zero
 * chance of finding them. */
.ba-group-link {
  color: var(--ba-gold);
  font-weight: 600;
  cursor: pointer;
  text-decoration: none;
  transition: color var(--ba-dur-fast) var(--ba-ease);
}
.ba-group-link:hover {
  color: #f0c97a;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--ba-gold);
}

/* Disabled state — flatten all the bells and whistles. */
vaadin-button[disabled] {
  opacity: 0.55;
  filter: grayscale(0.3);
  box-shadow: none;
}

/* ── Cards / panels — interactive ones lift on hover ─────────────────── */
.ba-section-card,
.ba-panel,
.auth-card {
  transition:
    transform   var(--ba-dur-med) var(--ba-ease),
    box-shadow  var(--ba-dur-med) var(--ba-ease),
    border      var(--ba-dur-med) var(--ba-ease);
}
/* Cards explicitly tagged interactive (clickable rows / nav cards) lift on hover */
.ba-card-interactive {
  cursor: pointer;
}
.ba-card-interactive:hover {
  transform: translateY(-2px);
  border-color: var(--ba-line-2);
  box-shadow: var(--ba-elev-3);
}

/* ── Grid rows — hover highlight + selected state ────────────────────── */
vaadin-grid::part(row) {
  transition: background var(--ba-dur-fast) var(--ba-ease);
}
vaadin-grid::part(row):hover {
  background: var(--lumo-contrast-5pct);
}
vaadin-grid::part(selected-row) {
  background: rgba(200, 39, 62, 0.10);
}
vaadin-grid::part(selected-row):hover {
  background: rgba(200, 39, 62, 0.18);
}

/* ── Dialogs — entrance animation + backdrop blur ────────────────────── */
@keyframes ba-dialog-in {
  from { opacity: 0; transform: translateY(8px) scale(0.98); }
  to   { opacity: 1; transform: translateY(0)   scale(1);    }
}
@keyframes ba-dialog-out {
  from { opacity: 1; transform: translateY(0)    scale(1);    }
  to   { opacity: 0; transform: translateY(-4px) scale(0.985); }
}
/* #259 — base styles always apply, animation scoped to opening/closing state
 * so it doesn't re-trigger on internal re-renders (root cause of the ESC-
 * dismiss flicker the user reported 2026-05-24). */
vaadin-dialog-overlay::part(overlay) {
  border-radius: var(--lumo-border-radius-l);
  box-shadow: var(--ba-elev-4);
}
vaadin-dialog-overlay[opening]::part(overlay) {
  animation: ba-dialog-in var(--ba-dur-med) var(--ba-ease-back);
}
vaadin-dialog-overlay[closing]::part(overlay) {
  animation: ba-dialog-out var(--ba-dur-fast) var(--ba-ease) forwards;
}
vaadin-dialog-overlay::part(backdrop) {
  background: rgba(7, 9, 13, 0.60);
  backdrop-filter: blur(4px);
}
/* Fade the backdrop in/out in lockstep with the dialog body so the
 * background blur doesn't snap on/off. */
@keyframes ba-backdrop-out {
  from { opacity: 1; } to { opacity: 0; }
}
vaadin-dialog-overlay[closing]::part(backdrop) {
  animation: ba-backdrop-out var(--ba-dur-fast) var(--ba-ease) forwards;
}
vaadin-dialog-overlay::part(header) {
  padding: 14px 18px 8px;
  border-bottom: 1px solid var(--ba-line);
}
vaadin-dialog-overlay::part(content) {
  padding: 14px 18px;
}
vaadin-dialog-overlay::part(footer) {
  padding: 10px 18px 14px;
  border-top: 1px solid var(--ba-line);
  gap: 8px;
}

/* ── Notifications / toasts — themed left stripe + slide-in ──────────── */
@keyframes ba-toast-in {
  from { opacity: 0; transform: translateY(-10px); }
  to   { opacity: 1; transform: translateY(0); }
}
/* Force every notification slot (top/middle/bottom × start/center/end) to
 * appear at the TOP of the viewport. User: "ALL TOASTERS SHOULD ALWAYS BE
 * AT THE TOP!!! ALWAYS!!!" Even if a Notification.show() call passed the
 * wrong Position enum, this anchors them at the top.
 *
 * The container is CSS GRID, not flex. Each slot div is placed via
 * `grid-area: <slot-name>` (e.g. `bottom-end` lands in grid row 3). Earlier
 * attempts using `justify-content: flex-start` + `align-self: flex-start`
 * failed because:
 *   - `justify-content` on a grid sets row alignment when rows don't fill the
 *     container — it doesn't pull row-3-placed items into row 1.
 *   - `align-self: start` only aligns the slot WITHIN its own grid cell, so a
 *     `bottom-end` slot still anchors to the bottom row, just to the top edge
 *     of that bottom row — visually still at the bottom of the viewport.
 * Real fix: rewrite the grid placement on bottom/middle slots so they live in
 * the top row, then pin them with `align-self: start`. Keep flex fallbacks as
 * belt-and-braces in case a Vaadin update flips the container to flex. */
vaadin-notification-container {
  /* Pin the container to viewport top-center. We DO NOT touch its internal
   * display/flex/align rules — Vaadin's own card layout depends on them and
   * forcing `display: flex; align-items: center` on the container collapsed
   * the card to fit-content, producing one-char-per-line text wrapping (user
   * caught this with a screenshot of a column-style "Welcome" toast).
   * Width is `max-content` capped at 92vw so the card sizes to its text
   * naturally, just like Vaadin's default but pinned to top instead of
   * wherever Vaadin's slot-based positioning lands.
   * `transform: translateX(-50%)` + `left: 50%` centers horizontally without
   * stretching the container full-width. */
  position: fixed !important;
  top: 16px !important;
  left: 50% !important;
  transform: translateX(-50%) !important;
  right: auto !important;
  bottom: auto !important;
  width: max-content !important;
  max-width: 92vw !important;
  height: auto !important;
  max-height: 100vh !important;
  z-index: 1000 !important;
  pointer-events: none !important;
}
vaadin-notification-container > [slot] {
  pointer-events: auto !important;
}
/* Every descendant of the toast card must be hit-testable so the BaToasts
 * ✕ close button receives clicks. The container above is pointer-events:
 * none (so non-toast clicks pass through to the page); the slot reverses
 * it, but pointer-events doesn't cascade to grandchildren — repeat the
 * `auto` on the card + its inner button explicitly. User: "Toast still
 * does not close with X!!!!!!!". */
vaadin-notification-card,
vaadin-notification-card * {
  pointer-events: auto;
}
vaadin-notification-card vaadin-button {
  cursor: pointer;
  pointer-events: auto !important;
}
/* #243 — keep toast card AND its inner text within viewport so the ✕ close
 * button never clips. The container's max-width: 92vw caps the OUTER box,
 * but a long single-line subject can let the inner card grow wider than
 * the cap unless we re-cap the card itself + force line-wrap on its text. */
vaadin-notification-card {
  max-width: 92vw !important;
  box-sizing: border-box !important;
  overflow-wrap: anywhere;
  word-break: break-word;
}
vaadin-notification-card [part="content"],
vaadin-notification-card [part="description"] {
  min-width: 0 !important;
  white-space: normal !important;
}

/* ── Date / Time picker overlay — must paint above dialog overlay ──
 * Vaadin's default z-index lets the calendar render UNDER the dialog
 * when invoked from a field inside the dialog. Bump above. */
vaadin-date-picker-overlay,
vaadin-time-picker-overlay,
vaadin-select-overlay,
vaadin-combo-box-overlay {
  z-index: 1100 !important;
}

/* ── Readability — brighten disabled buttons + faded labels ───────────
 * User: "Can hardly read fucken text next to the Mark sent button. Why
 * such a fade text?!?!? ... Just make the fucken text be visible, even
 * when disabled!!!!". Lumo's defaults push disabled buttons to ~opacity
 * 0.4 + faint grey on dark bg = unreadable. Override BOTH the host
 * opacity AND the shadow-DOM label color so disabled text reads clearly. */
vaadin-button[disabled] {
  opacity: 0.95 !important;
  color: var(--lumo-body-text-color) !important;
}
vaadin-button[disabled][theme~="tertiary"],
vaadin-button[disabled][theme~="tertiary-inline"] {
  color: var(--lumo-body-text-color) !important;
}
/* Vaadin renders disabled button text via a shadow-DOM label part. The
 * `::part(label)` override reaches inside the shadow root so dimming
 * the host opacity AND the inner label stay aligned. */
vaadin-button[disabled]::part(label) {
  color: var(--lumo-body-text-color) !important;
  opacity: 1 !important;
}

/* ── Disabled menu items: clearly faded + not-allowed cursor ───────────
 * User: "make disabled menus more contrast to enabled!!! i can hardly
 * see they are disabled. Or color them gray or something." Default Lumo
 * styling on a disabled vaadin-context-menu-item is barely a 5% opacity
 * shift — invisible on the dark BA palette. Pin disabled items to a
 * clearly-faded grey so users can tell at a glance. */
vaadin-menu-bar-overlay vaadin-context-menu-item[disabled],
vaadin-menu-bar-overlay vaadin-context-menu-item[aria-disabled="true"],
vaadin-context-menu-overlay vaadin-context-menu-item[disabled],
vaadin-context-menu-overlay vaadin-context-menu-item[aria-disabled="true"],
vaadin-popover-overlay vaadin-context-menu-item[disabled],
vaadin-popover-overlay vaadin-context-menu-item[aria-disabled="true"] {
  color: rgba(244, 236, 223, 0.32) !important;
  cursor: not-allowed !important;
  font-style: italic;
  pointer-events: none;
}
/* Bump `--lumo-secondary-text-color` upward for legibility on dark bg.
 * Defaults around rgba(.., 0.65) — push to 0.88 so muted helper /
 * "Pending" labels stay readable but still secondary. */
html[theme~="dark"] {
  --lumo-secondary-text-color: rgba(244, 236, 223, 0.88);
  --lumo-disabled-text-color: rgba(244, 236, 223, 0.78);
}
vaadin-notification-card {
  animation: ba-toast-in var(--ba-dur-med) var(--ba-ease-back);
  border-radius: var(--lumo-border-radius-m);
  box-shadow: var(--ba-elev-3);
  border-left: 4px solid var(--ba-accent);
  padding-left: 14px;
  /* Vaadin's slot positioning (e.g. top-end) shrinks the card to ~120px,
   * collapsing the text into a vertical column. Force a sane minimum so
   * the text reads horizontally regardless of which slot the card lands in. */
  min-width: 320px !important;
  width: max-content !important;
}
vaadin-notification-card[theme~="success"] {
  border-left-color: var(--ba-ok);
  background: linear-gradient(180deg, rgba(87,216,108,0.08), var(--ba-panel));
}
vaadin-notification-card[theme~="error"] {
  border-left-color: var(--ba-accent-2);
  background: linear-gradient(180deg, rgba(255,93,104,0.08), var(--ba-panel));
}
vaadin-notification-card[theme~="warning"] {
  border-left-color: var(--ba-warn);
  background: linear-gradient(180deg, rgba(242,184,75,0.08), var(--ba-panel));
}
vaadin-notification-card[theme~="primary"],
vaadin-notification-card:not([theme]) {
  border-left-color: var(--ba-accent);
  background: linear-gradient(180deg, rgba(52,212,161,0.08), var(--ba-panel));
}

/* ── Top nav — active link indicator + smoother hover ────────────────── */
.ba-nav-links vaadin-button,
.ba-nav-right  vaadin-button {
  position: relative;
  border-radius: 8px;
}
.ba-nav-links vaadin-button:not([disabled]):hover {
  background: var(--lumo-contrast-5pct);
  transform: none; /* override the global lift — nav stays grounded */
}
.ba-nav-links vaadin-button[active]::after {
  content: "";
  position: absolute;
  left: 12px;
  right: 12px;
  bottom: 4px;
  height: 2px;
  border-radius: 2px;
  background: var(--ba-accent);
  box-shadow: 0 0 8px var(--ba-glow-accent);
}

/* ── Chips / pills — hover lift on interactive ones ──────────────────── */
.ba-chip {
  transition: background var(--ba-dur-fast) var(--ba-ease),
              border-color var(--ba-dur-fast) var(--ba-ease);
}
.ba-chip:hover {
  background: var(--ba-panel-3);
  border-color: var(--ba-line-2);
}

/* ── Loading skeleton primitive ──────────────────────────────────────── */
@keyframes ba-shimmer {
  from { background-position: -200% 0; }
  to   { background-position:  200% 0; }
}
.ba-skeleton {
  background: linear-gradient(
    90deg,
    var(--ba-panel) 25%,
    var(--ba-panel-2) 50%,
    var(--ba-panel) 75%
  );
  background-size: 200% 100%;
  border-radius: var(--lumo-border-radius-s);
  animation: ba-shimmer 1.4s linear infinite;
  min-height: 18px;
}

/* ── Tabs (vaadin-tabs) — accent underline on active ─────────────────── */
vaadin-tab {
  transition: color var(--ba-dur-med) var(--ba-ease);
}
vaadin-tab:hover {
  color: var(--ba-accent);
}
vaadin-tabs::part(tabs) {
  border-bottom: 1px solid var(--ba-line);
}

vaadin-tabs {
  max-width: 100%;
  overflow-x: auto;
}
vaadin-tabs::-webkit-scrollbar {
  height: 4px;
}

/* ── Number-heavy text gets monospace tabular nums ───────────────────── */
/* Apply via setPartNameGenerator(r -> "ba-tabular-nums") on the column. */
.ba-num,
vaadin-grid::part(ba-tabular-nums),
vaadin-grid-cell-content[path*="amount"],
vaadin-grid-cell-content[path*="balance"],
vaadin-grid-cell-content[path*="total"] {
  font-feature-settings: "tnum" on, "lnum" on;
  font-variant-numeric: tabular-nums;
}

/* ── Scrollbars — themed and slim ────────────────────────────────────── */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--ba-line-2) transparent;
}
*::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}
*::-webkit-scrollbar-thumb {
  background: var(--ba-line-2);
  border-radius: 4px;
}
*::-webkit-scrollbar-thumb:hover {
  background: var(--ba-accent);
}
*::-webkit-scrollbar-track {
  background: transparent;
}

/* ── Headings — clearer hierarchy ────────────────────────────────────── */
h1, h2, h3, h4 {
  font-weight: 600;
  letter-spacing: -0.015em;
  line-height: 1.25;
}
h1 { font-size: 1.6em; }
h2 { font-size: 1.25em; }
h3 { font-size: 1.05em; }

/* ── Poker felt texture overlay — subtle linen weave on body ─────────── */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  opacity: 0.06;
  background-image:
    repeating-linear-gradient(45deg,  rgba(212,168,87,0.30) 0 1px, transparent 1px 4px),
    repeating-linear-gradient(-45deg, rgba(200,39,62,0.20)  0 1px, transparent 1px 4px);
  mix-blend-mode: overlay;
}
body > * { position: relative; z-index: 1; }

/* ── Poker-chip stat tile — for dashboard stat cards ─────────────────── */
.ba-chip-tile {
  position: relative;
  background:
    radial-gradient(circle at 50% 50%, var(--ba-panel-2) 60%, var(--ba-panel) 62%),
    var(--ba-panel);
  border: 2px solid var(--ba-gold);
  border-radius: 14px;
  padding: 14px 16px;
  box-shadow:
    inset 0 0 0 4px var(--ba-bg),
    inset 0 0 0 6px var(--ba-gold-d),
    var(--ba-elev-2);
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.ba-chip-tile::after {
  /* Edge-notches like a real poker chip */
  content: "";
  position: absolute;
  inset: 6px;
  border-radius: 10px;
  background:
    repeating-conic-gradient(
      from 0deg at 50% 50%,
      rgba(212, 168, 87, 0.0) 0deg 12deg,
      rgba(212, 168, 87, 0.18) 12deg 18deg
    );
  mask: radial-gradient(circle, transparent 60%, #000 62%);
  -webkit-mask: radial-gradient(circle, transparent 60%, #000 62%);
  pointer-events: none;
}

/* ── Empty-state hero — replaces an empty grid with something inviting ── */
.ba-empty-hero {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  background:
    radial-gradient(ellipse at top, rgba(212, 168, 87, 0.10), transparent 60%),
    linear-gradient(180deg, var(--ba-panel-2), var(--ba-panel));
  border: 1px dashed var(--ba-line-2);
  border-radius: 14px;
  padding: 22px 24px;
  width: 100%;
  box-sizing: border-box;
  text-align: left;
}
@media (max-width: 500px) {
  .ba-empty-hero {
    padding: 18px;
  }
  .ba-empty-hero vaadin-button[theme~="primary"] {
    width: 100%;
  }
}

/* ── Felt active-game banner — green felt with red velvet rope ──────── */
.ba-felt-banner {
  background:
    radial-gradient(ellipse at top, rgba(58, 165, 90, 0.18), transparent 70%),
    linear-gradient(180deg, #122218, #0d1812);
  border: 2px solid var(--ba-gold);
  border-radius: 14px;
  padding: 22px 26px;
  box-shadow:
    inset 0 0 0 1px rgba(212,168,87,0.25),
    var(--ba-elev-3);
  /* Same clip rule as .ba-section-card — the banner's children include a
   * flex row whose H2 title would otherwise push the right-edge pills
   * past the banner's right edge. */
  min-width: 0;
  max-width: 100%;
  overflow: hidden;
  box-sizing: border-box;
}

/* ═════════════════════════════════════════════════════════════════════════
 * RESPONSIVE — every dialog, notification, view, table sized to device.
 * Breakpoints:
 *   ≤ 500px  → mobile (phone portrait)
 *   501-900  → tablet / phone landscape
 *   ≥ 901    → desktop
 * Page must NEVER scroll — internal scroll only on grids + dialog content.
 * ═════════════════════════════════════════════════════════════════════════ */

/* Dialog overlay — bound to viewport at every breakpoint, content scrolls */
vaadin-dialog-overlay::part(overlay) {
  max-width: min(95vw, 800px);
  max-height: 85vh;
  width: auto;
  box-sizing: border-box;
}
vaadin-dialog-overlay::part(content) {
  overflow-y: auto;
  overscroll-behavior: contain;
  max-height: calc(85vh - 110px);
}
vaadin-confirm-dialog-overlay::part(overlay) {
  max-width: min(94vw, 460px);
}

/* Notifications — never wider than the viewport */
vaadin-notification-card {
  max-width: min(92vw, 560px);
  word-break: break-word;
}
vaadin-notification-container {
  /* On mobile, nudge in from the edge so the card doesn't hug the bezel */
  padding: 8px;
}

/* Grids — internal scroll only; page does NOT scroll */
vaadin-grid {
  min-height: 0;
  overflow: auto;
}

/* Page-level wrappers — safe-area aware, fluid widths */
.ba-page,
.ba-section-card {
  max-width: 100%;
  box-sizing: border-box;
}

/* ── Mobile (≤ 700px) — FULL-WIDTH, CONTENT-SIZED DIALOGS ────────────
 * User mandate 2026-05-15: dialogs must occupy full mobile WIDTH (no
 * tiny floating card lost in the middle of the viewport, no backdrop tap
 * accidentally dismissing input). User mandate 2026-05-17: dialogs must
 * NOT pad empty vertical space — a single-input Buy-in dialog forced to
 * 100vh height with the footer pinned at the bottom is "gigantic" with a
 * huge empty band, which the user (rightly) called out. Reconciled:
 *   - width: 100vw (full bleed horizontally, no rounded corners)
 *   - height: auto (content-sized — short dialogs stay short)
 *   - max-height: 100vh (large dialogs cap at viewport + body scrolls)
 *   - vertical centering — short dialog floats mid-screen, large dialog
 *     pins top.
 * Backdrop stays non-interactive on mobile so a stray tap on it doesn't
 * dismiss while the user means to interact with the dialog. */
@media (max-width: 700px) {
  vaadin-dialog-overlay::part(overlay),
  vaadin-confirm-dialog-overlay::part(overlay) {
    width: 100vw !important;
    max-width: 100vw !important;
    min-width: 100vw !important;
    height: auto !important;
    max-height: 100vh !important;
    min-height: 0 !important;
    border-radius: 0 !important;
    margin: 0 !important;
    box-sizing: border-box !important;
  }
  vaadin-dialog-overlay::part(content),
  vaadin-confirm-dialog-overlay::part(message) {
    /* Header (≈48px) + Footer (≈56px) = 104px reserved chrome. The body
     * grows with content but caps at the remaining viewport and scrolls
     * within those bounds for large dialogs. */
    max-height: calc(100vh - 104px) !important;
    overflow-y: auto !important;
    -webkit-overflow-scrolling: touch;
    padding: 12px 14px;
  }
  vaadin-dialog-overlay::part(header),
  vaadin-dialog-overlay::part(footer) {
    padding: 10px 14px;
  }
  vaadin-dialog-overlay::part(backdrop),
  vaadin-confirm-dialog-overlay::part(backdrop) {
    background: var(--ba-bg) !important;
    pointer-events: none !important;
  }
}

/* ── Mobile (≤ 500px) — page chrome ───────────────────────────────────── */
@media (max-width: 500px) {
  vaadin-notification-card {
    max-width: 96vw;
    font-size: 0.92em;
  }
  /* Page padding on root */
  .ba-page {
    padding: 8px !important;
  }
  /* Section cards: tighter */
  .ba-section-card,
  .ba-felt-banner,
  .auth-card {
    padding: 12px !important;
    border-radius: 10px;
  }
  /* Felt banner CTA at full width on mobile */
  .ba-felt-banner vaadin-button[theme~="primary"] {
    width: 100%;
  }
  /* Stat tiles fit two-up on phone, not one */
  .ba-chip-tile {
    padding: 10px 12px;
  }
  /* Headings shrink on phone */
  h1 { font-size: 1.35em; }
  h2 { font-size: 1.10em; }
  h3 { font-size: 0.95em; }
  /* Top nav: compact even more */
  .ba-nav-logo {
    height: 36px !important;
  }
}

/* ── Tablet / phone landscape (501–900px) ─────────────────────────────── */
@media (min-width: 501px) and (max-width: 900px) {
  vaadin-dialog-overlay::part(overlay) {
    max-width: min(80vw, 640px);
  }
  .ba-page {
    padding: 12px !important;
  }
  .ba-section-card,
  .ba-felt-banner {
    padding: 16px !important;
  }
}

/* ── Desktop (≥ 901px) ────────────────────────────────────────────────── */
@media (min-width: 901px) {
  vaadin-dialog-overlay::part(overlay) {
    max-width: min(70vw, 720px);
  }
}

/* Touch target sizing — every interactive element ≥ 36px on phone */
@media (max-width: 500px) {
  vaadin-button:not([theme~="tertiary"]):not([theme~="small"]) {
    min-height: 40px;
  }
  vaadin-text-field input,
  vaadin-password-field input,
  vaadin-email-field input,
  vaadin-number-field input,
  vaadin-big-decimal-field input,
  vaadin-select::part(input-field) {
    min-height: 40px;
    font-size: 16px; /* 16px prevents iOS zoom-on-focus */
  }
}

/* #295 (2026-05-27): deprecated `ba-grid-wide-only` / `ba-grid-mobile-only`
 * column-hide pattern REMOVED. CSS `display:none` on cell-content elements
 * leaves Vaadin's column allocator reserving the column width, producing
 * header↔cell misalignment on mobile. Per new SHARED §5.7 the long-term
 * answer is cards-on-mobile / tables-only-on-desktop (#290 refactor); in
 * the interim, all columns render on every viewport — mobile may horizontal-
 * scroll on dense grids, but the columns are at least aligned. */

/* #290 (2026-05-27) partial — enable smooth horizontal scrolling on mobile
 * grids until the full cards-on-mobile refactor lands. Touch-momentum-
 * scrolling keeps mobile usable when a 4-5 column grid exceeds the 390px
 * viewport width. */
@media (max-width: 700px) {
  vaadin-grid {
    overflow-x: auto !important;
    -webkit-overflow-scrolling: touch;
  }
}

/* #290 (2026-05-27) opt-in cards-on-mobile pattern per SHARED §5.7. Apply
 * `card-on-mobile` attribute to any vaadin-grid via
 * grid.getElement().setAttribute("card-on-mobile", true) and on viewports
 * ≤700px the grid rows render as stacked cards instead of a table row.
 * Header row stays hidden on mobile (each cell carries its own label via
 * the column's header text being placed inline as ::before pseudo-content
 * — caller must use setHeader(String) for this to populate). Desktop
 * unchanged. */
@media (max-width: 700px) {
  vaadin-grid[card-on-mobile]::part(header-cell) {
    display: none !important;
  }
  vaadin-grid[card-on-mobile]::part(row) {
    display: flex !important;
    flex-direction: column !important;
    align-items: stretch !important;
    background: var(--ba-panel);
    border: 1px solid var(--ba-line);
    border-radius: 10px;
    margin: 6px 0 !important;
    padding: 4px 8px !important;
  }
  vaadin-grid[card-on-mobile]::part(cell) {
    border: 0 !important;
    text-align: left !important;
    width: 100% !important;
    min-height: 28px !important;
    padding: 2px 0 !important;
  }
}

/* ── Profile menu bar in top nav — looks like a tertiary button ───────── */
.ba-nav-profile {
  --lumo-button-size: 32px;
  font-size: 0.85em;
  white-space: nowrap;
  max-width: 180px;
  overflow: hidden;
}
.ba-nav-profile vaadin-menu-bar-button {
  font-size: 0.85em;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
@media (max-width: 500px) {
  .ba-nav-profile vaadin-menu-bar-button {
    font-size: 0.78em;
    padding: 0 6px;
  }
}

/* ── Dev-mode controls inline in top nav — small contrast pills ───────── */
.ba-dev-control {
  font-size: 0.74em !important;
  opacity: 0.75;
  border: 1px dashed var(--lumo-contrast-30pct) !important;
  border-radius: 6px !important;
  white-space: nowrap !important;
  transition: opacity .15s var(--ba-ease);
}
.ba-dev-control:hover { opacity: 1; }
@media (max-width: 500px) {
  /* On phone, shrink padding so they don't push profile off the bar. */
  .ba-dev-control {
    padding: 0 6px !important;
    font-size: 0.7em !important;
  }
}

/* ── #36 MOBILE-DROPDOWN-OUTSIDE-BOUNDS — clamp overlays into viewport ──
 * On mobile Vaadin's auto-positioning for ComboBox / Select / context-menu
 * overlays can land far below the trigger (off-screen). User reported every
 * dropdown felt "did not open" on phone — actually opened way down the page.
 * Clamp max-height + force the overlay container to fit-content with a
 * sensible bottom-margin floor; the host's positioning will then never push
 * the visible content past viewport bottom. */
@media (max-width: 700px) {
  /* User mandate 2026-05-15: dropdowns must stay ANCHORED to the field that
   * opens them (not float to screen center) AND scroll freely no matter
   * how long the list is. Especially relevant for the player-picker
   * MultiSelectComboBoxes (game + group invite flows can list 50+ users).
   *
   * Cap the overlay at the visible viewport, scroll its inner content. The
   * vaadin-combo-box-overlay-content `vaadin-combo-box-scroller` handles
   * virtualized scrolling for the user list — we just need to ensure the
   * outer overlay doesn't clamp to a height less than its content. */
  vaadin-combo-box-overlay::part(overlay),
  vaadin-multi-select-combo-box-overlay::part(overlay),
  vaadin-select-overlay::part(overlay),
  vaadin-context-menu-overlay::part(overlay),
  vaadin-menu-bar-overlay::part(overlay),
  vaadin-popover-overlay::part(overlay) {
    max-height: min(70vh, calc(100vh - 80px)) !important;
    max-width: calc(100vw - 16px) !important;
  }
  /* #294 (narrowed 2026-05-27 after createGame spec regression — the
   * earlier full-override pushed select-items outside Playwright's viewport
   * coords). Keep the size constraints from the block above; let Vaadin's
   * own anchored positioning handle WHERE the overlay lands. The earlier
   * complaint (bottom-of-page disconnection) was the bottom-sheet mode
   * firing for triggers near the page top — Vaadin's anchored mode (the
   * default when the trigger is in view) handles that case correctly. */
  vaadin-combo-box-overlay::part(content),
  vaadin-multi-select-combo-box-overlay::part(content),
  vaadin-select-overlay::part(content) {
    max-height: inherit !important;
    overflow-y: auto !important;
    -webkit-overflow-scrolling: touch;
  }
  /* The actual scrollable list inside the combo-box overlay. Vaadin's
   * virtualizer needs this element to be the scroll container — pin it. */
  vaadin-combo-box-overlay vaadin-combo-box-scroller,
  vaadin-multi-select-combo-box-overlay vaadin-combo-box-scroller {
    max-height: inherit !important;
    overflow-y: auto !important;
    -webkit-overflow-scrolling: touch;
  }
  /* DELIBERATELY NO date-picker-overlay / time-picker-overlay rules below
   * 700px. Vaadin has its own mobile-fullscreen calendar layout for these,
   * and my earlier overrides on `::part(content)` + `vaadin-date-picker-
   * overlay-content` + `align-items: flex-start; justify-content: center`
   * broke the virtualized month scroll AND captured pointer events even
   * when the overlay was closed — locking the whole UI when the user
   * tapped the field. Reverted 2026-05-15 20:50. Trust Vaadin's defaults. */
}

/* z-index already pinned to 1100 in the earlier "Date / Time picker overlay"
 * block at line ~928. DO NOT add pointer-events overrides on the host
 * `vaadin-date-picker-overlay` element — Vaadin keeps the host in the DOM
 * when the overlay is closed, and forcing pointer-events:auto on the host
 * makes the (visually-empty) overlay capture clicks across the whole page,
 * locking the UI. Symptom: clicking the DatePicker input "locks the whole
 * UI". Diagnosed 2026-05-15 20:50. Reverted. Trust Vaadin's internal
 * pointer-events handling on the overlay parts. */

/* ── Reduced motion — respect the user's OS pref ─────────────────────── */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration:   0.001ms !important;
    transition-duration:  0.001ms !important;
    animation-iteration-count: 1 !important;
  }
}

/* ── DashPlayerView / DashGameView responsive stat grid ──────────────────
 * Mobile: single column (mockup parity at 390x844).
 * Tablet (>=700px): 2 columns.
 * Desktop (>=1000px): 3 columns.
 * Used by the felt hero in DashPlayerView + pool-totals in DashGameView.
 * Inline `@media` in a style="" attribute is rejected by Vaadin's CSS
 * parser, so the responsive wrap MUST live here as a class. */
.ba-dash-stats {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
}

/* Dash nav: title block flexes to fill, tabs sit at the right. On narrow
 * widths the nav wrap is enabled inline; below 500px we shrink the pills
 * so two of them fit comfortably alongside the title. Without this, the
 * 17px/800/uppercase pills push the right edge past viewport and the page
 * inherits the horizontal scrollbar — exactly the bug the user flagged
 * 2026-05-15. */
.ba-dash-nav { min-width: 0; }
.ba-dash-nav > * { min-width: 0; }
@media (max-width: 500px) {
  .ba-dash-nav vaadin-horizontal-layout {
    margin-left: auto;
  }
}
@media (max-width: 420px) {
  /* Span-based pills emitted by tab() — selectors target the inline
   * `font-size: 17px` so we need attribute-style overrides. */
  .ba-dash-nav span[style*="border-radius: 999px"] {
    font-size: 13px !important;
    padding: 7px 12px !important;
    letter-spacing: 0.04em !important;
  }
}

/* Global horizontal-overflow guard for every dashboard page. The page
 * wrapper already sets max-width:1080px + width:100%, but inner grids
 * with min-content children can blow past the viewport. `overflow-x:
 * hidden` clips the runaway and the body stops needing a horizontal
 * scrollbar. Vertical scroll is unaffected. */
.ba-page,
.ba-page > * {
  max-width: 100%;
  box-sizing: border-box;
}
.ba-page {
  overflow-x: hidden;
}
@media (min-width: 700px) {
  .ba-dash-stats {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (min-width: 1000px) {
  .ba-dash-stats {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}
