/* ==========================================================================
   /assets/css/ma_shared.css
   MatchAid — Shared Styles (GoDaddy)

   SECTIONS
   ─────────────────────────────────────────────────────────────────────────
    1.  Design Tokens (:root)
    2.  Base / Reset
    3.  App Shell Layout
    4.  Chrome — Header
    5.  Chrome — Footer Shell & Status Line
    6.  Chrome — Bottom Nav (Desktop Icon Bar)
    7.  Chrome — Footer Action Bar (Save / Cancel)
    8.  Chrome — Mobile Nav Hub (Navigate Button + Tray)
    9.  Multi-Panel Layout
   10.  Overlay Family (Drawer + Modal)
   11.  Actions Menu (deprecated shell + active maModal variant)
   12.  Cards
   13.  Pills & Chips
   14.  Buttons
   15.  Form Fields
   16.  Date Badge & Calendar
   17.  List Rows
   18.  Admin Picker
   19.  Misc (Empty State, Tab Panels)
   20.  Source Module Shared Vocabulary
   22.  MA.ui — Busy / Confirm Footer / Modal Notice / Toast
   ========================================================================== */


/* ==========================================================================
   1. DESIGN TOKENS
   ========================================================================== */
:root {

  /* --- Typography --- */
  --fontFamilyBase: "Montserrat", Arial, sans-serif;
  --inputTextSize: 16px;
  --labelTextSize: 15px;

  /* --- Brand colors --- */
  --brandPrimary: #07432A;
  --brandSecondary: #3F7652;
  --brandTertiary: #073B4C;       /* Event-context navy — card/panel/chrome headers */
  --brandTertiaryText: #ffffff;   /* White text on navy — same as brandSecondaryText */
  --brandQuaternary: #262339;     /* Player-context burgundy — chosen at 19.5deg hue,*/
  --brandQuaternaryText: #ffffff;
  
  --brandColor3: #0066CC;
  --brandAccent: #0b5fff; /* 24a0ed or #0b5fff or 0066CC */
  --brandPrimaryText: #ffffff;
  --brandPrimaryTextMuted: rgba(255,255,255,.78);
  --brandSecondaryText: #ffffff;
  --danger: #c62828;
  --warn: #f6d365;
  --success: #0aa45c;

  /* --- Portal color layers (L0 chrome / L1 panel hdr / L2 outer card+modal /
     L3 inner card) — Games portal is the default ramp. Each level is a
     derived white-mix of the portal's own base color, not a hand-picked
     value, so levels can never collide or go undefined. See
     .is-event-context below for the Events-portal override of the same
     four tokens. Percentages are tunable; 75/35/15 is the current pick. */
  --layer0-bg: var(--brandPrimary);
  --layer1-bg: color-mix(in srgb, var(--brandPrimary) 75%, white);
  --layer2-bg: color-mix(in srgb, var(--brandPrimary) 35%, white);
  --layer3-bg: color-mix(in srgb, var(--brandPrimary) 15%, white);
  --layer0-text: var(--brandPrimaryText);
  --layer1-text: var(--brandPrimaryText);
  --layer2-text: var(--ink);
  --layer3-text: var(--ink);

  /* --- Surfaces --- */
  --brandPrimaryBg: rgba(7,67,42,.08);
  --brandSecondaryBg: #ffffff;
  --surfaceApp: #f7f7f7;
  --surfaceChrome: #ffffff;

  /* Common ink/surface aliases (so components don't hardcode colors) */
  --bg: var(--surfaceChrome);
  --surface: var(--surfaceChrome);
  --ink: #111111;
  --mutedText: #3a3a3a;
  --border: var(--borderSubtle);

  /* --- Borders & shadows --- */
  --borderSubtle: rgba(0,0,0,.12);
  --shadowSubtle: 0 1px 0 rgba(0,0,0,.06);

  /* --- Spacing --- */
  --spaceSm: 6px;
  --spaceMd: 10px;

  /* --- Interaction --- */
  --pressedBg: rgba(0,0,0,.06);

  /* --- Radii --- */
  --controlRadius: 14px;
  --radiusMd: 10px;
  --radiusSq: 6px;
  --radiusLg: 12px;

  /* --- Controls --- */
  --controlBorder: var(--borderSubtle);

  /* --- Chrome Header --- */
  --chromePad: 10px;
  --chromeGap: 10px;
  --chromeHdrBg: #18422F;
  --chromeHdrBtnBg: #FFFFFF;
  --chromeHdrBtnText: var(--brandPrimary);
  --chromeHdrBtnBorder: rgba(0,0,0,.22);
  --chromeBg: var(--surfaceChrome);
  --chromeBorder: var(--borderSubtle);
  --chromeShadow: var(--shadowSubtle);
  --chromeTitleText: #FFFFFF;
  --chromeSubtitleText: rgba(255,255,255,.82);
  --chromeTitleSize: 18px;
  --chromeSubtitleSize: 12px;
  --modalTitleSize: 16px;
  --modalSubTitleSize: 12px;
  --chromeBtnFontSize: 18px;

  /* --- Chrome Status Line --- */
  --chromeStatusHeight: 24px;
  --chromeStatusPadY: 2px;
  --chromeStatusFontSize: 13px;
  --statusInfoBg: #ffffff;
  --statusInfoText: #1f2a37;
  --statusSuccessBg: var(--success);
  --statusSuccessText: #ffffff;
  --statusWarnBg: var(--warn);
  --statusWarnText: #111111;
  --statusDangerBg: var(--danger);
  --statusDangerText: #ffffff;

  /* --- Bottom Nav (icon bar) --- */
  /* Desktop icon nav bar (.maNavBtn family) */
  --navBarHeight: 66px;
  --navBarBg: #ffffff;
  --navBarText: #4b5563;
  --navBarTextSelected: var(--ink);
  --navBarFontSize: 15px;
  --navBarIconBox: 34px;
  --navBarIconSize: 24px;

  /* Mobile hub tray rows (.maHubRow family) */
  --hubRowBg: #f5f5f0;
  --hubRowText: var(--ink);
  --hubRowSelectedBg: color-mix(in srgb, var(--brandPrimary) 14%, white);
  --hubRowRootBg: var(--brandPrimary);
  --hubRowRootText: var(--brandPrimaryText);
  --hubRowFontSize: 20px;
  --hubRowIconSize: 18px;
  --hubRowIndent: 20px;
  --hubHeaderBg: var(--brandAccent);   /* one-off blue — matches the Navigate button that opens this tray */
  --hubHeaderText: var(--brandPrimaryText);

  /* --- Buttons --- */
  --btnHeight: 34px;
  --btnPadX: 12px;
  --btnRadius: var(--controlRadius);
  --btnBorder: var(--controlBorder);
  --btnFontSize: var(--fieldValueSize);
  --btnFontWeight: 800;
  --btnBg: var(--bg);
  --btnText: var(--ink);
  --btnPrimaryBg: var(--bg);
  --btnPrimaryText: var(--ink);
  --btnPrimaryBorder: var(--btnBorder);
  --btnSecondaryBg: var(--brandColor3);
  --btnSecondaryText: var(--brandPrimaryText);
  --btnSecondaryBorder: color-mix(in srgb, var(--brandSecondary) 70%, black);
  --btnLinkText: var(--brandAccent);
  --btnHoverBg: rgba(0,0,0,.04);
  --btnPressedBg: var(--pressedBg);

  /* --- Footer action bar (Save / Cancel) --- */
  --btnCancelBg: #e5e7eb;
  --btnCancelText: var(--ink);
  --btnCancelBorder: rgba(0, 0, 0, .18);
  --btnSaveBg: var(--brandAccent);
  --btnSaveText: #ffffff;
  --btnSaveBorder: color-mix(in srgb, var(--brandAccent) 70%, black);
  --ftrActionsPad: 10px;
  --ftrActionsGap: 10px;
  --ftrActionsBtnH: 44px;
  --ftrActionsBtnW: 200px;

  /* --- Pills / Chips --- */
  --pillRadius: 12px;
  --pillPadX: 10px;
  --pillPadY: 6px;
  --pillBg: rgba(0,0,0,.06);
  --pillText: var(--ink);
  --pillLabelText: var(--mutedText);
  --pillLabelSize: 10px;
  --pillValueSize: 12px;
  --pillValueWeight: 900;
  --pillMinHeight: 34px;
  --pillTitleSize: 11px;

  /* Choice chips */
  --choiceChipRadius: 12px;
  --choiceChipBorder: var(--controlBorder);
  --choiceChipBg: var(--surface);
  --choiceChipText: var(--ink);
  --choiceChipSelectedBg: var(--segmentSelectedBg);
  --choiceChipSelectedText: var(--segmentSelectedText);
  --choiceChipSelectedBorder: color-mix(in srgb, var(--segmentSelectedBg) 55%, black);

  /* Segmented controls */
  --chipHeight: 34px;
  --chipLabelSize: 12px;
  --chipLabelWeight: 800;
  --segmentSelectedBg: #C9B99A; /* #F1D7B7; */
  --segmentSelectedText: var(--ink);
  --segRadius: var(--controlRadius);
  --segBorder: var(--controlBorder);
  --segBg: var(--surface);
  --segBtnHeight: var(--chipHeight);
  --segBtnFontSize: 13px;
  --segBtnWeight: 800;
  --segBtnText: var(--mutedText);
  --segActiveBg: var(--segmentSelectedBg);
  --segActiveText: var(--segmentSelectedText);

  /* --- Overlays & Modals --- */
  --overlayBg: rgba(0,0,0,.35);
  --overlayZ: 99990;
  --overlayBgDim: var(--overlayBg);
  --overlayBlur: 2px;
  --modalSurface: var(--surfaceChrome);
  --modalMaxW: 720px;        /* wide is the rule; .maModal--compact keeps 520px */
  --modalMaxH: 96dvh;
  --modalViewportGap: 16px;
  --modalRadius: 18px;
  --modalShadow: 0 14px 34px rgba(0,0,0,.18);
  --modalHeaderBg: var(--layer1-bg);
  --modalHeaderText: var(--layer1-text);
  --drawerRadius: var(--controlRadius);
  --drawerMaxW: 720px;
  --drawerTopRadius: 18px;
  --drawerMaxH: var(--modalMaxH);

  /* --- Panels --- */
  --panelGap: 8px;
  --panelPad: 8px;
  --panelBg: var(--bg);
  --panelBorder: var(--border);
  --panelRadius: 14px;
  --panelShadow: 0 1px 0 rgba(0,0,0,.02);
  --panelHdrBg: var(--panelBg);
  --panelHdrText: var(--ink);
  --panelHdrBorder: var(--panelBorder);
  --panelControlsBg: color-mix(in srgb, var(--panelBg) 96%, black);
  --panelControlsBorder: var(--panelBorder);
  --panelFtrBg: var(--panelBg);
  --panelFtrBorder: var(--panelBorder);

  /* --- Cards --- */
  --cardBg: var(--panelBg);
  --cardBorder: var(--panelBorder);
  --cardRadius: var(--panelRadius);
  --cardShadow: var(--panelShadow);
  --cardsGap: 6px;
  --cardPad: 8px;
  --cardHdrPadY: 8px;
  --cardHdrPadX: 10px;
  --cardHdrBg: var(--cardBg);
  --cardHdrText: var(--ink);
  --cardHdrBorder: var(--cardBorder);
  --cardTitleSize: 13px;
  --cardActionSize: 34px;
  --cardActionRadius: 10px;
  --cardActionBg: transparent;
  --cardActionHoverBg: rgba(0,0,0,.04);
  --cardActionPressedBg: var(--pressedBg);
  --cardActionText: var(--btnLinkText);
  --cardActionGap: 6px;

  /* --- Page control area --- */
  --ControlAreaBg: color-mix(in srgb, var(--panelBg) 88%, black);
  --ControlAreaBorder: rgba(0,0,0,0.18);

  /* --- Misc typography tokens --- */
  --fieldValueSize: 13px;
  --fieldValueSublineSize: 12px;

  /* --- Date badge --- */
  --datebadgeTopBg: #E6D39A;
  --datebadgeTopText: #111111;

  /* --- List Row States --- */
  --rowBgDefault:        #ffffff;
  --rowBgSelected:       rgba(7,67,42,.16);
  --rowBgEnrolled:       #ebebeb;
  --rowPinnedDivider:    rgba(0,0,0,.12);

  /* --- Avatar Colors --- */
  --avatarMaleBg:        #BDD7EE;
  --avatarFemaleBg:      #F4C6D0;
  --avatarUnknownBg:     #E0E0E0;
  --avatarText:          #111111;
  --avatarBorder:        #ffffff;
}


/* ==========================================================================
   2. BASE / RESET
   ========================================================================== */

html, body {
  font-family: var(--fontFamilyBase);
  height: 100%;
  margin: 0;
}

body {
  display: flex;
  flex-direction: column;
  background: var(--surfaceApp);
  overflow-x: hidden;
}

/* Fix for iOS zoom on focus — inputs must be at least 16px */
input,
select,
textarea {
  font-size: var(--inputTextSize, 16px) !important;
}


/* ==========================================================================
   3. APP SHELL LAYOUT
   ========================================================================== */

.maPage {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: var(--spaceMd);
  display: block;
  flex-direction: column;
  min-height: 0;
  -webkit-overflow-scrolling: touch;
}

.maPage--multi {
  padding: var(--spaceMd);
}

.maControlArea {
  flex: 0 0 auto;
  padding: var(--spaceMd);
  margin: 0 var(--spaceMd) var(--spaceMd) var(--spaceMd);
  background: var(--ControlAreaBg);
  border: 1px solid var(--ControlAreaBorder);
  border-radius: var(--radiusLg);
}

/* Bare modifier — same flex/positioning role as .maControlArea (pinned
   above .maPage) without the bordered "panel" look, for pages like
   score_gis where every pixel of vertical space matters and a single
   hole-nav row doesn't need its own boxed chrome the way score_entry's
   busier control area (with its Scores/Side Games tabs) does. */
.maControlArea--bare {
  padding: 6px 0 0 0;
  margin: 0 var(--spaceMd) 6px var(--spaceMd);
  background: transparent;
  border: none;
}

/* Hole nav (pinned in .maControlArea) — shared by score_entry and score_gis. */
.scoreHoleNavInner{
  width: 100%;
  max-width: 360px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(72px, 1fr) minmax(72px, 96px) minmax(72px, 1fr);
  justify-content: center;
  gap: 8px;
  align-items: center;
  min-width: 0;
  box-sizing: border-box;
}

.scoreHoleNavInner > .btn{
  width: 100%;
  min-width: 0;
  min-height: 46px;
  height: 46px;
  padding-left: 8px;
  padding-right: 8px;
  box-sizing: border-box;
}

.scoreHoleSelect{
  width: 100%;
  min-width: 0;
  max-width: 96px;
  min-height: 46px;
  height: 46px;
  padding-left: 8px;
  padding-right: 24px;
  text-align: center;
  text-align-last: center;
  justify-self: center;
  font-size: clamp(22px, 7vw, 32px) !important;
  font-weight: 900;
  box-sizing: border-box;
}

@media (max-width: 768px){
  .scoreHoleNavInner{
    max-width: 100%;
    grid-template-columns: minmax(58px, 1fr) minmax(64px, 106px) minmax(58px, 1fr);
    gap: 8px;
  }

  .scoreHoleSelect{
    max-width: 106px;
    min-height: 48px;
    height: 48px;
    padding-left: 8px;
    padding-right: 22px;
    font-size: clamp(22px, 7vw, 32px) !important;
  }

  .scoreHoleNavInner > .btn{
    min-height: 48px;
    height: 48px;
  }
}

/* Prevent underlying page scroll when an overlay is open */
.maOverlayOpen .maPage {
  overflow: hidden;
}

.maOverlayOpen body {
  width: 100vw;
  overflow-x: hidden;
  position: relative;
}


/* ==========================================================================
   4. CHROME — HEADER
   ========================================================================== */

.maChrome__hdr {
  background: var(--chromeHdrBg);
  border-bottom: 1px solid var(--chromeBorder);
  box-shadow: var(--chromeShadow);
  padding: var(--chromePad);
}

/* ── Event context — navy chrome + panel/card headers ────────────────────
   Applied on <html> (document.documentElement) by chromeHeader.php's
   inline script — a real DOM ancestor of everything, including modals
   appended straight to <body> — not just on <header>, so CSS variable
   inheritance actually reaches every descendant. (The class also still
   gets stamped on <header> itself below, for its own direct styling.)
   Cascades to any element referencing the --layerN-* tokens: panels,
   cards, and modals alike, with no per-page CSS needed. Same white-mix
   formula as the Games default ramp, just anchored to brandTertiary. */
.is-event-context {
  --layer0-bg: var(--brandTertiary);
  --layer1-bg: color-mix(in srgb, var(--brandTertiary) 75%, white);
  --layer2-bg: color-mix(in srgb, var(--brandTertiary) 35%, white);
  --layer3-bg: color-mix(in srgb, var(--brandTertiary) 15%, white);
  --layer0-text: var(--brandTertiaryText);
  --layer1-text: var(--brandTertiaryText);
  --layer2-text: var(--ink);
  --layer3-text: var(--ink);
}

.maChrome__hdr.is-event-context {
  background: var(--brandTertiary);
}

/* Player context — burgundy chrome + panel/card headers. Applied on
   <html> by chromeHeader.php, driven by $_SESSION['SessionPortal'] ===
   'PLAYER PORTAL' (set unconditionally by playerhome.php), mirroring the
   is-event-context mechanism above exactly.

   Uses html.is-player-context / header.maChrome__hdr.is-player-context
   (element + class, not just class) rather than matching is-event-context's
   bare-class specificity — deliberately, so Player always wins if a page
   ever carries both classes at once (a player viewing a game that belongs
   to an event). This mirrors the priority already established in
   game_players.js / game_summary.js's setBottomNav logic, where isPlayer
   is checked before isEvent. Determinism here doesn't depend on which
   block happens to be declared later in this file. */
html.is-player-context {
  --layer0-bg: var(--brandQuaternary);
  --layer1-bg: color-mix(in srgb, var(--brandQuaternary) 75%, white);
  --layer2-bg: color-mix(in srgb, var(--brandQuaternary) 35%, white);
  --layer3-bg: color-mix(in srgb, var(--brandQuaternary) 15%, white);
  --layer0-text: var(--brandQuaternaryText);
  --layer1-text: var(--brandQuaternaryText);
  --layer2-text: var(--ink);
  --layer3-text: var(--ink);
}

header.maChrome__hdr.is-player-context {
  background: var(--brandQuaternary);
}

/* NOTE: the old ".is-event-context ~ main .maPanel__hdr, .maCard__hdr"
   sibling-combinator rule that lived here has been removed. It predated
   the base .maPanel__hdr / .maCard__hdr rules becoming token-aware
   (they now reference --layer1-bg / --layer2-bg directly and inherit
   correctly from either .is-event-context or .is-player-context on
   <html> with no extra rule needed) — and it had crept out of sync with
   that fix: at (0,2,1) specificity it was beating the base .maCard__hdr
   rule's (0,1,0) and forcing card headers to the L1 value even where L2
   was correct, on any real event-context page. Found and removed while
   adding Player context, not something the Player work itself caused. */

.maChrome__hdrRow {
  display: flex;
  align-items: center;
  gap: var(--chromeGap);
}

.maChrome__hdrLeft,
.maChrome__hdrRight {
  display: flex;
  align-items: center;
  justify-content: center;
}

.maChrome__hdrBtn {
  height: 34px;
  min-width: 72px;
  padding: 0 10px;
  border-radius: var(--radiusMd);
  background: var(--chromeHdrBtnBg);
  color: var(--chromeHdrBtnText);
  border: 1px solid var(--chromeHdrBtnBorder);
  font-family: var(--fontFamilyBase);
  font-weight: 700;
  font-size: var(--btnFontSize);
  cursor: pointer;
  user-select: none;
}

.maChrome__hdrBtn:active {
  transform: scale(.98);
}

.maChrome__brand {
  width: 48px;
  height: 48px;
  border-radius: var(--radiusMd);
  background: var(--brandPrimaryBg);
  display: none;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  flex: 0 0 auto;
}

.maChrome__brand img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.maChrome__titles {
  flex: 1 1 auto;
  min-width: 0;
  text-align: center;
}

.maChrome__title {
  font-family: var(--fontFamilyBase);
  font-weight: 700;
  color: var(--chromeTitleText);
  font-size: var(--chromeTitleSize);
  line-height: 1.2;
}

.maChrome__subtitle {
  font-family: var(--fontFamilyBase);
  color: var(--chromeSubtitleText);
  font-size: var(--chromeSubtitleSize);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* 3rd header line (matches subtitle feel) */
.maChrome__subtitle2 {
  font-family: var(--fontFamilyBase);
  color: var(--chromeSubtitleText);
  font-size: var(--chromeSubtitleSize);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  opacity: .9;
}


/* ==========================================================================
   5. CHROME — FOOTER SHELL & STATUS LINE
   ========================================================================== */

.maChrome__ftr {
  background: var(--chromeBg);
  border-top: 1px solid var(--chromeBorder);
  padding-bottom: 8px;
}

.maChrome__status {
  font-family: var(--fontFamilyBase);
  min-height: var(--chromeStatusHeight, 24px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--chromeStatusPadY, 2px) var(--spaceMd);
  font-size: var(--chromeStatusFontSize);
  line-height: 1.15;
  text-align: center;
  border-bottom: 1px solid var(--chromeBorder);
  user-select: none;
}

/* Status variants (driven by MA.setStatus → status-* classes) */
.maChrome__status.status-info {
  background: var(--statusInfoBg, #e9eef5);
  color: var(--statusInfoText, #1f2a37);
}

.maChrome__status.status-success {
  background: var(--statusSuccessBg, #e7f7ee);
  color: var(--statusSuccessText, #0f5132);
}

.maChrome__status.status-warn {
  background: var(--statusWarnBg, #fff7db);
  color: var(--statusWarnText, #664d03);
}

.maChrome__status.status-danger {
  background: var(--statusDangerBg, #fde7ea);
  color: var(--statusDangerText, #842029);
}


/* ==========================================================================
   6. CHROME — BOTTOM NAV (DESKTOP ICON BAR)
   ========================================================================== */

.maChrome__bottomNav {
  height: var(--navBarHeight);
  display: flex;
  align-items: stretch;
  justify-content: space-between;
  padding-bottom: env(safe-area-inset-bottom, 0px);
  background: var(--navBarBg);
}

/* Each nav button: icon stacked over label.
   Normal/Selected both carry a 1px border so neither state shifts the
   button's box size relative to the other — see .is-selected below,
   which uses outline (not border) for the same reason. */
.maNavBtn {
  position: relative;
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  padding: 6px 4px;
  margin: 0;
  border: 1px solid #c4c4c0;
  background: #f0f0ee;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  color: var(--navBarText);
}

.maNavIcon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--navBarIconBox);
  height: var(--navBarIconBox);
  font-size: var(--navBarIconSize);
  line-height: 1;
}

/* img/svg icons hardcode their own width/height attributes in markup —
   this overrides them so every icon type obeys one token regardless of
   how it's marked up. */
.maNavIcon img,
.maNavIcon svg {
  width: var(--navBarIconSize);
  height: var(--navBarIconSize);
}

.maNavLabel {
  font-size: var(--navBarFontSize);
  line-height: 1.1;
  letter-spacing: .2px;
  white-space: nowrap;
}

.maNavBtn:active {
  transform: scale(.98);
  background: rgba(0,0,0,.06);
}

.maNavBtn:disabled {
  transform: none;
  cursor: default;
}

/* The current page's button is always disabled too (you can't navigate to
   where you already are), but it must NOT dim like a genuinely-unavailable
   button — that would wash out the is-selected tint/outline meant to make
   it stand out. Opacity only applies to disabled buttons that aren't also
   the selected one. */
.maNavBtn:disabled:not(.is-selected) {
  opacity: .55;
}

/* Selected: current page. Outline (not border) so the box size never
   changes between Normal and Selected. Text/icon stay ink, not green —
   green is reserved for the outline + chevron accent, keeping text at
   full contrast for daylight readability (matches the mobile treatment). */
.maNavBtn.is-selected {
  background: color-mix(in srgb, var(--brandPrimary) 12%, white);
  color: var(--navBarTextSelected);
  border-color: transparent;
  outline: 1.5px solid var(--brandPrimary);
  outline-offset: -1.5px;
}

/* Inset chevron — a second, shape-based "you are here" signal alongside
   the tint/outline, sitting just inside the outline rather than breaking
   through it (buttons sit edge-to-edge with no gap, so a chevron poking
   past the edge would land on the neighboring button). */
.maNavBtn.is-selected::before {
  content: "";
  position: absolute;
  left: 8px;
  top: 10px;
  bottom: 10px;
  width: 11px;
  background: var(--brandPrimary);
  clip-path: polygon(0 0, 45% 0, 100% 50%, 45% 100%, 0 100%);
}

/* Root: this button exits the current object/page entirely (set per-page
   via MA.chrome.setBottomNav({ root: [...] }) — see ma_shared.js).
   Solid fill is the strongest step in the same brandPrimary ramp Selected
   uses, so Normal -> Selected -> Root reads as one continuous signal.
   Light border (not brandPrimary) so adjacent roots — e.g. Player Home +
   Score Home — show a seam instead of merging into one dark block. */
.maNavBtn--root {
  background: var(--brandPrimary);
  border-color: rgba(255,255,255,.5);
  color: var(--brandPrimaryText);
}

.maNavBtn--root .maNavLabel {
  color: var(--brandPrimaryText);
}

/* Root + Selected (rare — e.g. standing on the page a root button points
   to). Restates fill/border because .maNavBtn.is-selected out-specifies
   .maNavBtn--root. The light border already sits on the edge, so the
   outline is inset further to read as a distinct ring, and the chevron
   flips to white so it shows against the dark fill. */
.maNavBtn--root.is-selected {
  background: var(--brandPrimary);
  border-color: rgba(255,255,255,.5);
  outline: 1.5px solid rgba(255,255,255,.85);
  outline-offset: -4px;
}

.maNavBtn--root.is-selected::before {
  background: var(--brandPrimaryText);
}

/* Divider marking a scope change among the currently-visible buttons —
   toggled in JS based on the page-supplied root set, not a fixed markup
   attribute (root is page-relative, see ma_shared.js setBottomNav). */
.maNavBtn--scope-start {
  border-left: 2px solid var(--borderSubtle);
  margin-left: 4px;
}

/* Compact mode: 1–2 visible items centered */
.maChrome__bottomNav.is-compact {
  justify-content: center;
  gap: 18px;
}

.maChrome__bottomNav.is-compact .maNavBtn {
  flex: 0 0 auto;
  min-width: 140px;
}


/* ==========================================================================
   7. CHROME — FOOTER ACTION BAR (SAVE / CANCEL)
   ========================================================================== */

/* Optional page action slot — hidden by default, shown by MA.chrome.setActions */
.maChrome__pageAction {
  padding: 8px 10px;
  border-bottom: 1px solid var(--chromeBorder);
  display: flex;
  justify-content: center;
  background: var(--chromeBg);
}

.maChrome__pageActionBtn {
  width: 100%;
  padding: 11px 14px;
  background: transparent;
  border: 1.5px dashed var(--brandPrimary);
  border-radius: var(--controlRadius);
  color: var(--mutedText);
  font-family: var(--fontFamilyBase);
  font-size: 13px;
  font-weight: 800;
  cursor: pointer;
  text-align: center;
  letter-spacing: .2px;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
}

.maChrome__pageActionBtn:active {
  background: var(--pressedBg);
  transform: scale(.99);
}

@media (min-width: 600px) {
  .maChrome__pageActionBtn {
    width: 280px;
  }
}

/* Footer action bar shell */
.maChrome__ftrActions {
  display: none;              /* hidden until footer--actions mode active */
  align-items: center;
  padding: var(--ftrActionsPad, 10px);
  gap: var(--ftrActionsGap, 10px);
  background: var(--chromeBg);
  flex-direction: row;
  justify-content: stretch;
}

/* Footer in actions mode: show bar, hide nav */
.maChrome__ftr--actions .maChrome__ftrActions {
  display: flex;
}

.maChrome__ftr--actions .maChrome__bottomNav {
  display: none;
}

/* Shared footer button base */
.maFtrBtn {
  flex: 1 1 0;
  min-height: var(--ftrActionsBtnH, 44px);
  border-radius: var(--controlRadius);
  font-family: var(--fontFamilyBase);
  font-size: 15px;
  font-weight: 800;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid transparent;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  transition: filter .15s ease, transform .1s ease;
  white-space: nowrap;
}

.maFtrBtn:active {
  transform: scale(.98);
  filter: brightness(.96);
}

.maFtrBtn:disabled,
.maFtrBtn.is-disabled {
  opacity: .50;
  cursor: default;
  transform: none;
  filter: none;
}

.maFtrBtn--save {
  background: var(--btnSaveBg, var(--brandAccent));
  color: var(--btnSaveText, #ffffff);
  border-color: var(--btnSaveBorder, color-mix(in srgb, var(--brandAccent) 70%, black));
}

.maFtrBtn--cancel {
  background: var(--btnCancelBg, #e5e7eb);
  color: var(--btnCancelText, var(--ink));
  border-color: var(--btnCancelBorder, rgba(0, 0, 0, .18));
}

/* Tablet + desktop (≥600px): right-justified, fixed width */
@media (min-width: 600px) {
  .maChrome__ftrActions {
    justify-content: flex-end;
  }

  .maFtrBtn {
    flex: 0 0 var(--ftrActionsBtnW, 200px);
  }
}


/* ==========================================================================
   8. CHROME — MOBILE NAV HUB (NAVIGATE BUTTON + TRAY)
   Controls:
     - Navigate button  (.maChrome__navHub)
     - Hub tray overlay (.maChrome__hubTray)
   On mobile (≤600px) the icon bar is hidden and the Navigate button takes
   its place in the footer. Tapping it slides up the hub tray, which is
   populated by MA.chrome.setBottomNav() at page boot.
   The Save/Cancel overlay hides both the icon bar and Navigate button via
   the existing .maChrome__ftr--actions class toggle.
   ========================================================================== */

/* Navigate button container — hidden by default (desktop).
   Sits inside .maChrome__bottomNav as a flex child, so it stretches
   to fill the full nav width and height on mobile. */
.maChrome__navHub {
  display: none;
  align-items: center;
  justify-content: center;
  flex: 1 1 auto;      /* fill the nav's full width */
  align-self: stretch; /* fill the nav's full height */
}

.maChrome__navHubBtn {
  display: flex;
  align-items: center;
  width: 75%;
  justify-content: center;
  gap: 8px;
  background: var(--brandAccent);
  color: #fff;
  border: none;
  border-radius: 10px;
  font-size: 16px;
  min-height: 44px;
  padding: 0 28px;
  font-weight: 500;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: opacity 0.15s;
}

.maChrome__navHubBtn:active {
  opacity: 0.85;
}

.maChrome__navHubIcon {
  font-size: 16px;
  line-height: 1;
}

.maChrome__navHubLabel {
  font-size: 16px;
  line-height: 1;
}

/* Hub tray overlay — always in DOM, toggled via [hidden] + .is-open */
.maChrome__hubTray {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  pointer-events: none;
}

/* [hidden] keeps it out of the accessibility tree.
   JS removes [hidden] before animating open so transitions fire. */
.maChrome__hubTray[hidden] {
  display: none;
}

.maChrome__hubTray.is-open {
  pointer-events: all;
}

/* Backdrop */
.maChrome__hubBackdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0);
  transition: background 0.25s ease;
  cursor: pointer;
}

.maChrome__hubTray.is-open .maChrome__hubBackdrop {
  background: rgba(0, 0, 0, 0.50);
}

/* Sheet */
.maChrome__hubSheet {
  position: relative;
  background: #fff;
  border-radius: 16px 16px 0 0;
  display: flex;
  flex-direction: column;
  max-height: 88vh;
  transform: translateY(100%);
  transition: transform 0.28s cubic-bezier(0.32, 0.72, 0, 1);
}

.maChrome__hubTray.is-open .maChrome__hubSheet {
  transform: translateY(0);
}

/* Drag handle */
.maChrome__hubHandle {
  width: 36px;
  height: 4px;
  background: #ddd;
  border-radius: 2px;
  margin: 10px auto 6px;
  flex-shrink: 0;
}

/* Header row */
.maChrome__hubHeader {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 14px;
  background: var(--hubHeaderBg);
  border-radius: 16px 16px 0 0;
  flex-shrink: 0;
}

.maChrome__hubTitle {
  font-size: 15px;
  font-weight: 500;
  color: var(--hubHeaderText);
}

.maChrome__hubClose {
  background: rgba(255,255,255,.2);
  border: none;
  border-radius: 50%;
  width: 26px;
  height: 26px;
  font-size: 13px;
  color: var(--hubHeaderText);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.maChrome__hubClose:active {
  opacity: 0.7;
}

/* Scrollable row area */
.maChrome__hubScroll {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 6px 10px 16px;
  flex: 1;
}

.maChrome__hubScroll::after {
  content: "";
  display: block;
  height: 8px;
}

/* Hub tray nav rows (injected by setBottomNav / _buildHubRows).
   Text and icon color stay black/high-contrast in every state — this app
   is used outdoors in daylight, so state is communicated through
   background tint, a left accent bar, and indentation, never through
   muted or light-colored text. */
.maHubRow {
  box-sizing: border-box;
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  background: var(--hubRowBg);
  border: none;
  border-left: 3px solid transparent;
  border-radius: 8px;
  padding: 10px 12px;
  margin-bottom: 6px;
  cursor: pointer;
  text-align: left;
  -webkit-tap-highlight-color: transparent;
  transition: background 0.12s;
}

.maHubRow:active {
  background: #e8e8e0;
}

/* Indented child rows — only applied when this tray actually has a root
   row (guarded in JS so pages without a `root:` config render flush-left
   exactly as before, with no stray margin). */
.maHubRow--indented {
  width: calc(100% - var(--hubRowIndent));
  margin-left: var(--hubRowIndent);
}

.maHubRow__icon {
  font-size: var(--hubRowIconSize);
  width: 22px;
  text-align: center;
  flex-shrink: 0;
  color: var(--hubRowText);
}

.maHubRow__label {
  font-size: var(--hubRowFontSize);
  font-weight: 500;
  color: var(--hubRowText);
  flex: 1;
}

.maHubRow__arrow {
  font-size: var(--hubRowIconSize);
  color: var(--hubRowText);
  flex-shrink: 0;
}

/* Selected: current page. Background tint + left accent bar carry the
   signal, since text/icon color can't (daylight constraint above). */
.maHubRow.is-selected {
  background: var(--hubRowSelectedBg);
  border-left-color: var(--brandPrimary);
}

/* Root: this row exits the current object entirely (page-supplied via
   root:, same as desktop — see ma_shared.js). Full-contrast white on a
   solid fill, so the daylight constraint doesn't require any change here. */
.maHubRow--root {
  background: var(--hubRowRootBg);
  border-left-color: transparent;
}

.maHubRow--root .maHubRow__icon,
.maHubRow--root .maHubRow__label,
.maHubRow--root .maHubRow__arrow {
  color: var(--hubRowRootText);
}

/* Root + Selected (rare) — light outline distinguishes it from plain
   Root, since a dark accent bar would vanish against the dark fill. */
.maHubRow--root.is-selected {
  outline: 1px solid rgba(255,255,255,.6);
  outline-offset: -1px;
}

/* Section divider between root and object-scoped rows */
.maHubDivider {
  border: none;
  border-top: 0.5px solid #eee;
  margin: 4px 0;
}

/* --- Media queries: visibility swap --- */

/* Mobile (≤600px): hide icon nav buttons, show Navigate button.
   The nav element itself stays as display:flex — only its icon button
   children are hidden. The navHub div fills the remaining space. */
@media (max-width: 600px) {
  .maChrome__bottomNav .maNavBtn {
    display: none !important;
  }

  .maChrome__navHub {
    display: flex;
  }
}

/* Desktop (≥601px): hide Navigate button; belt-and-suspenders hide tray */
@media (min-width: 601px) {
  .maChrome__navHub {
    display: none;
  }

  .maChrome__hubTray {
    display: none !important;
  }
}

/* Save/Cancel overlay hides the entire nav (including Navigate button
   inside it) via the rule in section 7 above. No extra rule needed here. */

/* Landscape-short phones ("peek" mode) -------------------------------------
   A landscape phone is WIDE but SHORT, so the width-only breakpoints above
   don't catch it — e.g. an iPhone in landscape comfortably exceeds 600px/
   820px width while still being only ~380-430px tall, so it falls into the
   "desktop" bucket above: full icon row instead of the compact Navigate
   button, and the hub tray force-hidden by that same desktop rule.

   Landscape on a phone is treated as a brief "peek" at content, not a place
   to take action — so this also hides the chrome header outright (including
   any page action buttons sitting in chromeBtnLeft/chromeBtnRight), on the
   theory that a user who wants to act just rotates back to portrait, where
   both the header and the normal nav re-appear automatically (pure media
   query, no JS/class involved, so it's reactive to live rotation).

   Unconditional and app-wide — no per-page opt-in/opt-out. If a page ever
   needs an exception (e.g. it can't afford to lose a header action while
   rotated), that's a deliberate follow-up, not a default to design around
   now. Placed after the width-based rules above so it wins the cascade
   whenever it matches, regardless of actual width. */
@media (orientation: landscape) and (max-height: 500px) {
  .maChrome__hdr {
    display: none;
  }

  .maChrome__bottomNav .maNavBtn {
    display: none !important;
  }

  .maChrome__navHub {
    display: flex !important;
  }

  /* Restates the hub tray's own two rules (base flex / [hidden]->none) so
     it works normally again here, overriding the desktop rule's blanket
     "display:none !important" above rather than forcing it always-open. */
  .maChrome__hubTray {
    display: flex !important;
  }

  .maChrome__hubTray[hidden] {
    display: none !important;
  }
}


/* ==========================================================================
   9. MULTI-PANEL LAYOUT
   
   CONTRACT: .maPanel__body is the ONLY scrollable region, at every
   breakpoint. hdr/controls/ftr are fixed. Every panel's scrollable
   content MUST be wrapped in .maPanel__body — do not apply overflow
   directly to .maPanel or any custom panel variant.

   Expected markup:
     <main class="maPage maPage--multi">
       <div class="maPanels maPanels--2"> (or --3 / --4)
         <section class="maPanel maPanel--primary">...</section>
         <section class="maPanel maPanel--secondary">...</section>
       </div>
     </main>
   ========================================================================== */

.maPanels {
  height: 100%;
  min-height: 0;
  display: grid;
  gap: var(--panelGap);
  grid-template-columns: 1fr; /* mobile default — stacked */
}

@media (min-width: 900px) {
  .maPanels--2 { grid-template-columns: 1fr 1fr; }
  .maPanels--3 { grid-template-columns: 1fr 1fr 1fr; }
  .maPanels--4 { grid-template-columns: 1fr 1fr 1fr 1fr; }
}

/* Panel shell */
.maPanel {
  display: flex;
  flex-direction: column;
  min-height: 0;
  background: var(--panelBg);
  border: 1px solid var(--panelBorder);
  border-radius: var(--panelRadius);
  box-shadow: var(--panelShadow);
  overflow: hidden;
}

/* Panel regions */
.maPanel__hdr {
  flex: 0 0 auto;
  background: var(--layer1-bg);
  color: var(--layer1-text);
  padding: var(--panelPad);
  border-bottom: 1px solid var(--panelHdrBorder);
}

.maPanel__controls {
  flex: 0 0 auto;
  background: var(--panelControlsBg);
  padding: 6px 8px; /*it was var(--panelPad); */
  border-bottom: 1px solid var(--panelControlsBorder);
}

.maPanel__controls .maFieldRow {
  margin-top: 4px;
  gap: 6px;
}

.maPanel__body {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  padding: var(--panelPad);
  overscroll-behavior: contain;
}

.maPanel__ftr {
  flex: 0 0 auto;
  background: var(--panelFtrBg);
  padding: var(--panelPad);
  border-top: 1px solid var(--panelFtrBorder);
}

/* ---------- Tray / canvas mobile swap ------------------------------------
   Consolidates a pattern that existed as four independent, near-identical
   copies (game_players.css, event_roster.css, game_pairings.css,
   game_slotting.css) before this. Below 900px, .maPanels--2 has already
   collapsed to one column (see .maPanels above) — this decides which of
   the two panels occupies it. .maPanel--secondary (the tray: unassigned
   players, add-player sources, etc.) starts hidden; .maPanel--primary
   (the canvas) is the default view.

   Not an overlay — no backdrop, no fixed positioning, no animation. Plain
   display swap. This is a deliberately different mechanism from
   .maChrome__hubTray (the mobile nav drawer, below) despite the shared
   "tray" name — that one slides up over a backdrop; this one just swaps
   which panel is visible in place. Don't conflate the two.

   .is-tray-open is a plain descendant selector with no required ancestor
   — it can be toggled on the page wrapper (as game_players/event_roster
   do), a tab wrapper (as game_pairings/game_slotting do, for independent
   per-tab tray state), or a modal (.maModal--panels), unmodified.

   Expected trigger markup:
     Inside .maPanel--primary's own .maPanel__ftr:
       <button class="maTrayOpenBtn" type="button">+ Add Players</button>
     Inside .maPanel--secondary's own .maPanel__hdr:
       <button class="maTrayCloseBtn iconBtn btnSecondary" type="button"
               aria-label="Close">×</button>
   JS toggles .is-tray-open on the shared ancestor; nothing else required.
   ------------------------------------------------------------------------- */
@media (max-width: 900px) {
  .maPanels--2 .maPanel--secondary {
    display: none;
  }

  .is-tray-open .maPanels--2 .maPanel--secondary {
    display: flex;
    flex-direction: column;
  }

  .is-tray-open .maPanels--2 .maPanel--primary {
    display: none;
  }

  /* Controls belong to the canvas, not the tray — hide the modal-level
     controls strip (e.g. cascade mode toggle, Auto-Pair) while the tray
     is showing instead of the canvas. Retained on desktop regardless of
     .is-tray-open, since panels never swap there. */
  .is-tray-open .maModal__controls {
    display: none;
  }
}

.maTrayOpenBtn {
  display: none !important;
  width: 100%;
  min-height: var(--btnHeight);
  align-items: center;
  justify-content: center;
  border: 1px dashed var(--brandPrimary);
  border-radius: var(--radiusMd);
  background: transparent;
  color: var(--brandPrimary);
  font-family: var(--fontFamilyBase);
  font-size: 14px;
  font-weight: 900;
  cursor: pointer;
}

.maTrayOpenBtn:active {
  transform: translateY(1px);
}

.maTrayCloseBtn {
  display: none !important;
}

@media (max-width: 900px) {
  .maTrayOpenBtn {
    display: inline-flex !important;
  }

  .maTrayCloseBtn {
    display: flex !important;
  }
}


/* ==========================================================================
   10. OVERLAY FAMILY — DRAWER + MODAL
   ========================================================================== */

/* ---------- Drawer (secondary panel on mobile) --------------------------- */
/*
   Expected markup:
     <div class="maDrawerOverlay is-open">
       <section class="maDrawer">
         <header class="maPanel__hdr">...</header>
         <div class="maPanel__controls">...</div>  (optional)
         <div class="maPanel__body">...</div>
         <footer class="maPanel__ftr">...</footer>
       </section>
     </div>
*/
.maDrawerOverlay {
  position: fixed;
  inset: 0;
  display: none;
  align-items: flex-end;
  justify-content: center;
  padding: 10px;
  background: var(--overlayBgDim);
  z-index: var(--overlayZ);
  backdrop-filter: blur(var(--overlayBlur));
}

.maDrawerOverlay.is-open { display: flex; }

.maDrawer {
  width: min(var(--drawerMaxW), 100%);
  max-height: var(--drawerMaxH);
  background: var(--panelBg);
  border: 1px solid var(--panelBorder);
  border-radius: var(--drawerTopRadius) var(--drawerTopRadius) 0 0;
  box-shadow: var(--modalShadow);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

/* ---------- Modal (capture / edit / filters / settings) ------------------ */
/*
   Expected markup:
     <div class="maModalOverlay is-open">
       <section class="maModal" role="dialog" aria-modal="true">
         <header class="maModal__hdr">...</header>
         <div class="maModal__controls">...</div>  (optional)
         <div class="maModal__body">...</div>
         <footer class="maModal__ftr">...</footer>
       </section>
     </div>
*/
.maModalOverlay {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100svh;
  overflow: hidden;
  overscroll-behavior: none;
  display: none;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;  /* NEW */
  padding:
    calc(20px + env(safe-area-inset-top))
    8px
    calc(20px + env(safe-area-inset-bottom))
    8px;
  background: var(--overlayBgDim);
  z-index: var(--overlayZ);
  backdrop-filter: blur(var(--overlayBlur));
  touch-action: none;
}

.maModalOverlay.is-open { display: flex; }

.maModal {
  width: 100%;
  max-width: min(var(--modalMaxW), calc(100vw - 16px));  /* NEW */
  max-height: 88vh; /* legacy fallback */
  max-height: min(var(--modalMaxH), calc(100dvh - (var(--modalViewportGap) + env(safe-area-inset-top) + env(safe-area-inset-bottom))));
  background: var(--modalSurface);
  border: 1px solid var(--border);
  border-radius: var(--modalRadius);
  box-shadow: var(--modalShadow);
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
  padding: 0;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}

.maModal__hdr {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 14px;
  background: var(--modalHeaderBg);
  color: var(--modalHeaderText);
  border-bottom: 1px solid rgba(255,255,255,.18);
}

.maModal__controls {
  flex: 0 0 auto;
  padding: 12px 14px;
  background: var(--panelControlsBg);
  border-bottom: 1px solid var(--panelControlsBorder);
  overflow: hidden;
}

.maModal__body {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  padding: 14px;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}

.maModal__body--flush {
  padding: 0;
}

.maModal__ftr {
  flex: 0 0 auto;
  display: flex;
  justify-content: space-between;
  gap: 10px;
  padding: 12px 14px;
  border-top: 1px solid var(--border);
  background: color-mix(in srgb, var(--bg) 96%, black);
}

.maModal__ftrActions {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
  align-items: center;
  width: 100%;
}

.maModal__title {
  font-size: var(--modalTitleSize);
  font-weight: 900;
  letter-spacing: .2px;
}

.maModal__subtitle {
  margin-top: 2px;
  font-size: var(--modalSubTitleSize);
  color: rgba(255,255,255,.92);
  line-height: 1.1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---------- Modal variant: hosts a .maPanels tray/canvas layout ---------
   Opt-in modifiers for a modal whose body is a two-panel tray/canvas
   layout (see section 9) rather than ordinary form fields.

   .maModal--panels  — the panels need a real, definite height to fill
     (not just the default max-height cap) so .maPanel__body's own
     overflow:auto has something concrete to scroll within. Same
     viewport-safe expression the existing max-height rule already uses.

   .maModal__body--panels — strips the default 14px body padding (the
     panels supply their own internal spacing) and locks outer scroll —
     only .maPanel__body should scroll, never this wrapper. Mirrors the
     "lock outer, scroll inner" rule every standalone tray/canvas page
     already applies to its own <main class="maPage--X">.
   ------------------------------------------------------------------------- */
.maModal--panels {
  height: min(var(--modalMaxH), calc(100dvh - (var(--modalViewportGap) + env(safe-area-inset-top) + env(safe-area-inset-bottom))));
}

/* Compact popups — short messages, menus and one- or two-field forms
   (confirm, busy, Actions / row-tap menus, the Game and Event Settings
   menus, Select Tee, the contact editor). Everything else uses the wide
   --modalMaxW above. Phones are unaffected either way (100vw - 16px wins). */
.maModal--compact,
.maModal--busy {
  --modalMaxW: 520px;
}

/* Fixed height — for tabbed popups, so switching tabs doesn't resize the
   window (e.g. the messaging Contacts picker). Fills the available height on
   a phone, capped at 680px on larger screens; the body scrolls. */
.maModal--fixedHeight {
  height: min(680px, calc(100dvh - (var(--modalViewportGap) + env(safe-area-inset-top) + env(safe-area-inset-bottom))));
}

.maModal__body--panels {
  padding: 0;
  overflow: hidden;
}

/* Mobile overrides for modal fields */
@media (max-width: 600px) {
  .maModal {
    max-width: 100%;
    box-sizing: border-box;
  }

  .maModal .maField {
    flex: 1 1 auto;
  }

  .maModal .maFieldRow {
    flex-direction: column;
  }
}


/* ==========================================================================
   11. ACTIONS MENU
   ========================================================================== */

/* ---------- DEPRECATED: actionMenuOverlay -------------------------------- */
/* DO NOT USE — use maModalOverlay + maModal instead.
   Kept for any legacy pages not yet migrated. */

.actionMenuOverlay {
  position: fixed;
  inset: 0;
  background: var(--overlayBg);
  display: none;
  z-index: 99999;
  backdrop-filter: blur(2px);
  touch-action: none;
  align-items: center;
  justify-content: center;
  padding: 18px;
}

.actionMenuOverlay.open { display: flex; }

.actionMenu {
  position: relative;
  min-width: 260px;
  width: min(360px, 100%);
  max-width: 360px;
  background: var(--modalSurface);
  border: 1px solid var(--controlBorder);
  border-radius: var(--drawerRadius);
  overflow: hidden;
  box-shadow: 0 14px 34px rgba(0,0,0,.18);
  padding: 0;
}

.actionMenu_header {
  position: sticky;
  top: 0;
  background: var(--modalHeaderBg);
  color: var(--modalHeaderText);
  padding: 12px 14px;
  z-index: 2;
}

.actionMenu_headerRow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.actionMenu_title {
  font-weight: 900;
  font-size: var(--chromeTitleSize);
  line-height: 1.15;
}

.actionMenu_subtitle {
  margin-top: 2px;
  font-weight: 800;
  font-size: var(--chromeSubtitleSize);
  opacity: .9;
}

.actionMenu_closeBtn {
  border: 0;
  background: rgba(255,255,255,.20);
  color: var(--bg);
  border-radius: var(--radiusLg);
  width: 30px;
  height: 28px;
  font-size: var(--btnFontSize);
  line-height: 1;
  font-weight: 900;
  cursor: pointer;
}

.actionMenu_closeBtn:hover {
  background: rgba(255,255,255,.28);
}

.actionMenu_item {
  width: 100%;
  border: 0;
  border-radius: 0;
  margin: 0;
  padding: 14px 16px;
  background: transparent;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 10px;
  font-weight: 900;
  font-size: var(--fieldValueSize);
  color: var(--ink);
  cursor: pointer;
  user-select: none;
  border-bottom: 1px solid rgba(0,0,0,.10);
}

.actionMenu_item:hover { background: var(--pressedBg); }

.actionMenu_item.disabled {
  opacity: .50;
  cursor: default;
  color: var(--mutedText);
}

.actionMenu_item.danger { color: var(--danger); }

.actionMenu_divider {
  height: 8px;
  background: #f0f0f0;
  margin: 0;
}

@media (max-width: 520px) {
  .actionMenu {
    width: 100%;
    max-width: none;
  }
}

/* ---------- Active: maModal variant of actions menu --------------------- */

.maModal .actionMenu_subtitle {
  margin: 0 0 8px 0;
  font-weight: 800;
  font-size: var(--chromeSubtitleSize);
  color: var(--mutedText);
}

.maModal .actionMenu_item {
  width: 100%;
  border: 0;
  border-radius: 0;
  margin: 0;
  padding: 14px 16px;
  background: transparent;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 10px;
  font-weight: 900;
  font-size: var(--fieldValueSize);
  color: var(--ink);
  cursor: pointer;
  user-select: none;
  border-bottom: 1px solid rgba(0,0,0,.10);
}

.maModal .actionMenu_item:hover { background: var(--pressedBg); }

.maModal .actionMenu_item.disabled {
  opacity: .50;
  cursor: default;
  color: var(--mutedText);
}

.maModal .actionMenu_item.danger { color: var(--danger); }

.actionMenu_item.indent,
.maModal .actionMenu_item.indent {
  padding-left: 28px;
}

.maModal .actionMenu_divider {
  height: 8px;
  background: #f0f0f0;
  margin: 0;
}

/* Category break — section header with tinted background */
.actionMenu_category {
  background: var(--brandPrimaryBg);
  border-top: 1px solid var(--borderSubtle);
  border-bottom: 1px solid var(--borderSubtle);
  padding: 8px 16px 5px;
  font-weight: 900;
  font-size: var(--fieldValueSize);
  color: var(--ink);
  pointer-events: none;
  user-select: none;
}

.actionMenu_categoryDesc {
  background: var(--brandPrimaryBg);
  border-bottom: 1px solid var(--borderSubtle);
  padding: 0 16px 7px;
  font-weight: 800;
  font-size: var(--fieldValueSize);
  color: var(--ink);
  pointer-events: none;
  user-select: none;
}

.maModal .actionMenu_category {
  background: var(--brandPrimaryBg);
  border-top: 1px solid var(--borderSubtle);
  border-bottom: 1px solid var(--borderSubtle);
  padding: 8px 16px 5px;
  font-weight: 900;
  font-size: var(--fieldValueSize);
  color: var(--ink);
  pointer-events: none;
  user-select: none;
}

.maModal .actionMenu_categoryDesc {
  background: var(--brandPrimaryBg);
  border-bottom: 1px solid var(--borderSubtle);
  padding: 0 16px 7px;
  font-weight: 800;
  font-size: var(--fieldValueSize);
  color: var(--ink);
  pointer-events: none;
  user-select: none;
}


/* ==========================================================================
   12. CARDS
   Use for repeatable surfaces inside a page/panel.
   Regions: .maCard__hdr (optional), .maCard__body (required)
   ========================================================================== */

.maCards {
  display: flex;
  flex-direction: column;
  gap: var(--cardsGap);
  min-width: 0;
}

.maCards--scroll {
  overflow: visible;
  max-height: none;
}

.maCard {
  background: var(--cardBg);
  border: 1px solid var(--cardBorder);
  border-radius: var(--cardRadius);
  box-shadow: var(--cardShadow);
  overflow: hidden;
  min-width: 0;
}

/* Header: left title, right actions (0–3) */
.maCard__hdr {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: var(--cardHdrPadY) var(--cardHdrPadX);
  background: var(--layer2-bg);
  color: var(--layer2-text);
  border-bottom: 1px solid var(--cardHdrBorder);
}

/* Alternate card header tier — L1 instead of the default L2. For one-off
   cases where a card needs panel-level visual weight rather than content-
   card weight (first use: Admin Home's Games/Events list cards; expected
   for Player and Score portal list cards too). Apply this class directly
   on .maCard__hdr in the module that builds the markup — don't reach for
   it via page-CSS overrides targeting another file's output, which is
   what caused the original inconsistency this class replaces. */
.maCard__hdr--l1 {
  background: var(--layer1-bg);
  color: var(--layer1-text);
}
.maCard__hdr--l1 .maCard__title {
  color: var(--layer1-text);
}

/* Lighter card header tier — L3 (dark text on a pale tint), the same shade
   Pairings' group cards use. Chosen where a header must stay readable in
   direct sunlight (Score Entry's Side Bets player cards). Written as a
   compound selector so it also wins on pages that restyle plain
   .maCard__hdr (score_entry.css does), without needing !important. */
.maCard__hdr.maCard__hdr--l3 {
  background: var(--layer3-bg);
  color: var(--layer3-text);
}
.maCard__hdr--l3 .maCard__title {
  color: var(--layer3-text);
}

.maCard__title {
  min-width: 0;
  flex: 1 1 auto;
  font-family: var(--fontFamilyBase);
  font-size: var(--cardTitleSize);
  font-weight: 800;
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.maCard__actions {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--cardActionGap);
}

.maCard__actionBtn {
  width: var(--cardActionSize);
  height: var(--cardActionSize);
  border-radius: var(--cardActionRadius);
  border: 0;
  background: var(--cardActionBg);
  color: var(--cardActionText);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}

.maCard__actionBtn:active {
  background: var(--cardActionPressedBg);
  transform: scale(.98);
}

.maCard__actionBtn:disabled {
  opacity: .55;
  cursor: default;
  transform: none;
}

/* ---------- Card header — mobile-stacked variant -------------------------
   Opt-in modifier: add alongside .maCard__hdr (e.g.
   class="maCard__hdr maCard__hdr--wrap") to stack the title above the
   actions slot on narrow viewports, instead of the default single-row
   layout. Deliberately NOT a change to .maCard__hdr itself — that class is
   shared by cards elsewhere (e.g. module_runAutoPair.js's compact pairing
   preview cards, score_home.js's scoring cards) that are single-row by
   design and shouldn't restack. Breakpoint matches the 820px mobile
   threshold already used in game_summary.css / game_scorecards.css.

   Markup pattern:
     <header class="maCard__hdr maCard__hdr--wrap">
       <div class="maCard__title">...</div>
       <div class="maCard__actions">
         <span class="maHintText">...</span>
       </div>
     </header>
   ------------------------------------------------------------------------- */
@media (max-width: 820px) {
  .maCard__hdr--wrap {
    flex-direction: column;
    align-items: flex-start;
  }

  .maCard__hdr--wrap .maCard__title {
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
  }

  .maCard__hdr--wrap .maCard__actions {
    width: 100%;
    justify-content: flex-start;
  }
}

.maCard__body {
  padding: var(--cardPad);
  min-width: 0;
}

/* ---------- Collapsible modifier — a .maCard that can expand/collapse.
   First real consumer: Scorecard group cards. Also independently built
   once before as .gpGroupCard (game_pairings.css, page-scoped) — same
   structure, same mechanism, different prefix. This is the canonical
   version both should eventually share; no new class family, only
   modifiers on the classes that already exist.

   Markup: two .maCard__hdr siblings (one --expanded, one --collapsed),
   toggled by .is-collapsed on the card itself. Title sits as a direct
   flex child of .maCard__hdr alongside its buttons — .maCard__hdr is
   already display:flex + justify-content:space-between, and
   .maCard__title already has flex:1 1 auto, so the title naturally
   fills the middle and pushes a trailing button to the far right with
   no extra wrapper needed. */

.maCard--collapsible.is-collapsed .maCard__hdr--expanded,
.maCard--collapsible.is-collapsed .maCard__body {
  display: none;
}

.maCard--collapsible:not(.is-collapsed) .maCard__hdr--collapsed {
  display: none;
}

/* Stable header color, expanded or collapsed alike — decided
   explicitly, not swapped on toggle. Scoped to the modifier, not the
   base .maCard__hdr, so it never affects any other card in the app. */
.maCard--collapsible .maCard__hdr {
  background: color-mix(in srgb, var(--brandColor3) 6%, white);
}

/* Opt-in L3 tier for collapsible cards — the rule above otherwise beats
   .maCard__hdr--l3 (same specificity, declared later). Pale portal tint,
   same as Pairings' group cards, and follows event/player context via the
   layer tokens. First use: Admin Reporting game cards. Consumers without
   the modifier (scorecards, side bets) keep the tint above. */
.maCard--collapsible .maCard__hdr.maCard__hdr--l3 {
  background: var(--layer3-bg);
  color: var(--layer3-text);
}


/* ==========================================================================
   13. PILLS & CHIPS
   ========================================================================== */

/* ---------- Pills (informational) --------------------------------------- */
.maPills {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  min-width: 0;
}

.maPill {
  background: var(--pillBg);
  color: var(--pillText);
  border-radius: var(--pillRadius);
  padding: var(--pillPadY) var(--pillPadX);
  font-size: var(--pillValueSize);
  font-weight: 800;
  line-height: 1.1;
  white-space: nowrap;
  flex: 0 0 auto;
  min-height: var(--pillMinHeight);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

/* 2-line label/value pill */
.maPillKV {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-height: var(--pillMinHeight);
}

.maPillLabel {
  font-size: var(--pillLabelSize);
  font-weight: 800;
  color: var(--pillLabelText);
  line-height: 1;
}

.maPillValue {
  font-size: var(--pillValueSize);
  font-weight: var(--pillValueWeight);
  line-height: 1.1;
  color: var(--pillText);
}

/* Status variants */
.maPill--success {
  color: var(--success);
  background: color-mix(in srgb, var(--success) 14%, var(--cardBg));
  border: 1px solid color-mix(in srgb, var(--success) 35%, var(--border));
}

.maPill--warn  { color: var(--warn); }
.maPill--danger { color: var(--danger); }

/* ---------- Choice chips (enum selection / toggle) ---------------------- */
.maChoiceChips {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  min-width: 0;
}

.maChoiceChip {
  border: 1px solid var(--choiceChipBorder);
  background: var(--choiceChipBg);
  color: var(--choiceChipText);
  border-radius: var(--choiceChipRadius);
  padding: 8px 12px;
  font-family: var(--fontFamilyBase); /* buttons don't inherit font — without this chips fall back to the browser default */
  font-weight: 800;
  font-size: var(--pillTitleSize);
  line-height: 1;
  cursor: pointer;
  user-select: none;
}

.maChoiceChip.is-selected {
  background: var(--choiceChipSelectedBg);
  color: var(--choiceChipSelectedText);
  border-color: var(--choiceChipSelectedBorder);
}

/* Second selected state — brandSecondary green instead of the default tan.
   For cases where a choice chip sits near another tan-selected control
   (e.g. Define Flights' by-player/by-flight view toggle) and the shared
   tan would make two unrelated "selected" meanings look identical. */
.maChoiceChip.is-selected-accent {
  background: var(--brandSecondary);
  color: var(--brandSecondaryText);
  border-color: color-mix(in srgb, var(--brandSecondary) 70%, black);
}

/* Define Flights — flight name row: input, remove button, player count all
   sit on one line on desktop; wraps to its own line on mobile only, using
   the app's existing 600px breakpoint (see .maFtrBtn above). */
.dfFlightRow {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: nowrap;
}

.dfFlightRow .dfFlightCount {
  white-space: nowrap;
}

@media (max-width: 600px) {
  .dfFlightRow {
    flex-wrap: wrap;
  }
}

/* Generic config-row layout — swatch/input + trailing count, one line on
   desktop, wraps on mobile only (same 600px breakpoint as .dfFlightRow
   above). Used by Manage Teams' team-name rows. */
.maConfigRow {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: nowrap;
}

@media (max-width: 600px) {
  .maConfigRow {
    flex-wrap: wrap;
  }
}

/* Hide-on-mobile wrapper for action-button rows on pages that rely solely
   on the chrome-header Actions button for mobile access (no in-canvas
   replacement trigger needed — e.g. Game Players). Deliberately no base
   styling here, so it can't clobber whatever the page's own CSS already
   sets on desktop; only takes effect at the 600px breakpoint. Compound
   selector keeps specificity high enough to win over an equal-specificity
   page-level rule regardless of stylesheet load order. */
@media (max-width: 600px) {
  .maDesktopActions,
  .gpCanvasControls__right.maDesktopActions {
    display: none;
  }
}

.maChoiceChip.is-disabled {
  opacity: .55;
  cursor: default;
}

/* Touch-size chip — THE canonical large selectable row (Auto-Pair Pairing
   Strategy, Score Entry side bets). Full-width, 44px+ for one-handed use
   outdoors. Same colours as a normal chip: tan when .is-selected, white
   otherwise. The 2px --ink unselected border is deliberate — contrast in
   bright sunlight — don't soften it. Selection shows three ways: filled
   dot, tan background, selected border. The dot is drawn by ::before, so
   every consumer renders it identically and it's never its own tap
   target — the whole row is the button. Sits inside .maChoiceChips (a
   wrapping flex row); flex-basis 100% makes each chip its own line.

   Semantics are the consumer's job, since the look is the same either way:
   single-select → role="radio" + aria-checked inside role="radiogroup";
   multi-select  → aria-pressed.

   Markup:
     <button class="maChoiceChip maChoiceChip--touch is-selected" type="button">
       <span class="maChoiceChip__label">Sandy</span>
       <span class="maChoiceChip__detail">Held by Bishop</span>   (optional)
     </button> */
.maChoiceChip--touch {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: 10px;
  row-gap: 2px;
  align-items: center;
  flex: 1 1 100%;
  min-width: 0;
  min-height: 44px;
  padding: 8px 12px;
  font-size: var(--labelTextSize);
  line-height: 1.2;
  text-align: left;
  border-width: 2px;
  border-color: var(--ink);
}

.maChoiceChip--touch::before {
  content: "";
  grid-column: 1;
  grid-row: 1;
  width: 18px;
  height: 18px;
  box-sizing: border-box;
  border: 2px solid currentColor;
  border-radius: 50%;
}

.maChoiceChip--touch.is-selected::before {
  background: currentColor;
}

.maChoiceChip__label {
  grid-column: 2;
  grid-row: 1;
  min-width: 0;
  overflow-wrap: anywhere;
}

.maChoiceChip__detail {
  grid-column: 2;
  grid-row: 2;
  min-width: 0;
  font-size: var(--fieldValueSublineSize);
  font-weight: 600;
  color: var(--mutedText);
  line-height: 1.3;
  overflow-wrap: anywhere;
}

/* ---------- Segmented control (single-select tab switching) ------------- */
.maSeg {
  display: flex;
  width: 100%;
  border: 1px solid var(--segBorder);
  border-radius: var(--segRadius);
  overflow: hidden;
  background: var(--segBg);
}

.maSegBtn {
  flex: 1;
  min-height: var(--segBtnHeight);
  border: 0;
  border-right: 1px solid var(--segBorder);
  background: transparent;
  font-size: var(--segBtnFontSize);
  font-weight: var(--segBtnWeight);
  cursor: pointer;
  color: var(--segBtnText);
  padding: var(--spaceSm) calc(var(--spaceMd) + 2px);
  user-select: none;
}

.maSegBtn:last-child { border-right: 0; }

.maSegBtn.is-active {
  background: var(--segActiveBg);
  color: var(--segActiveText);
}

/* Blue selected state — for segmented yes/no decisions where the default
   tan is-active reads as too neutral, e.g. Define Flights' "Apply to all
   rounds?" toggle. Same brandColor3 already used for filled action buttons
   elsewhere (Manage Teams, Refresh Handicaps, Multi-Add). */
.maSegBtn.is-active-accent {
  background: var(--brandColor3);
  color: var(--brandPrimaryText);
}

.maSegBtn:disabled {
  opacity: .55;
  cursor: default;
}

/* ---------- Toggle (on/off switch) --------------------------------------
   A compact Yes/No switch that sits beside its label — distinct from .maSeg,
   which is a full-width view swap. Same border/radius/color tokens as .maSeg
   so it reads as part of the same family.

   Markup:
     <div class="maToggleRow">
       <span class="maListRow__col">Activate</span>
       <div class="maToggle" role="group" aria-label="...">
         <button type="button" class="maToggle__btn is-active" aria-pressed="true">Yes</button>
         <button type="button" class="maToggle__btn" aria-pressed="false">No</button>
       </div>
     </div>
     <div class="maHintText">What the current selection means.</div>
   ------------------------------------------------------------------------- */
.maToggleRow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.maToggle {
  display: flex;
  flex: 0 0 auto;
  border: 1px solid var(--segBorder);
  border-radius: var(--segRadius);
  overflow: hidden;
  background: var(--segBg);
}

.maToggle__btn {
  min-height: var(--segBtnHeight);
  border: 0;
  border-right: 1px solid var(--segBorder);
  background: transparent;
  font-size: var(--segBtnFontSize);
  font-weight: var(--segBtnWeight);
  cursor: pointer;
  color: var(--segBtnText);
  padding: var(--spaceSm) calc(var(--spaceMd) + 2px);
  user-select: none;
}

.maToggle__btn:last-child { border-right: 0; }

.maToggle__btn.is-active {
  background: var(--brandColor3);
  color: var(--brandPrimaryText);
}

.maToggle__btn:disabled {
  opacity: .55;
  cursor: default;
}


/* ==========================================================================
   14. BUTTONS
   ========================================================================== */

/* Base button */
.btn {
  border: 1px solid var(--btnBorder);
  background: var(--btnBg);
  color: var(--btnText);
  border-radius: var(--btnRadius);
  min-height: var(--btnHeight);
  padding: 0 var(--btnPadX);
  font-family: var(--fontFamilyBase);
  font-size: var(--btnFontSize);
  font-weight: var(--btnFontWeight);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  white-space: nowrap;
  user-select: none;
}

.btn:active {
  background: var(--btnPressedBg);
  transform: scale(.98);
}

.btn:disabled,
.btn.disabled {
  opacity: .55;
  cursor: default;
  transform: none;
}

/* Primary = default (ink on light surface, semantic marker) */
.btnPrimary {
  background: var(--btnPrimaryBg);
  color: var(--btnPrimaryText);
  border-color: var(--btnPrimaryBorder);
}

/* Secondary = filled brand button (white on brandSecondary) */
.btnSecondary {
  background: var(--btnSecondaryBg);
  color: var(--btnSecondaryText);
  border-color: var(--btnSecondaryBorder);
}

.btnSecondary:active { filter: brightness(.96); }

/* Link button = text-only action */
.btnLink,
.btn.btnLink {
  border: 0;
  background: transparent;
  padding: 0;
  min-height: 0;
  height: auto;
  min-width: 0;
  justify-content: flex-start;
  color: var(--btnLinkText);
  font-weight: var(--btnFontWeight);
}

.btnLink:hover,
.btn.btnLink:hover {
  text-decoration: underline;
}

/* Square icon button (calendar, etc.) */
.iconBtn {
  width: var(--btnHeight);
  height: var(--btnHeight);
  flex: 0 0 var(--btnHeight);
  padding: 0;
  border-radius: var(--radiusSq);
  border: 1px solid var(--btnBorder);
  background: var(--btnBg);
  color: var(--btnText);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  user-select: none;
}

.iconBtn:active {
  background: var(--btnPressedBg);
  transform: scale(.98);
}

/* Indicator usage — non-interactive, fully visible when disabled */
.iconBtn:disabled {
  opacity: 1;
  cursor: default;
  pointer-events: none;
}

/* Close button (used in modals) */
.closeBtn {
  border: 1px solid var(--btnBorder);
  background: var(--btnBg);
  color: var(--btnText);
  border-radius: var(--radiusMd);
  padding: 7px 10px;
  cursor: pointer;
  font-weight: 700;
  font-family: var(--fontFamilyBase);
}

/* Pill button (rounded action chip) */
.pillBtn {
  border: 1px solid var(--btnBorder);
  background: var(--btnBg);
  border-radius: 999px;
  padding: 8px 12px;
  font-weight: 700;
  cursor: pointer;
  font-family: var(--fontFamilyBase);
  font-size: var(--btnFontSize);
  display: inline-flex;
  gap: 8px;
  align-items: center;
  user-select: none;
}

.pillBtn:active {
  background: var(--btnPressedBg);
  transform: scale(.98);
}


/* ==========================================================================
   15. FORM FIELDS
   ========================================================================== */

.maFieldRow {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 12px;
}

.maField {
  flex: 1 1 240px;
  min-width: 0;
}

.maLabel {
  display: block;
  margin: 0 0 6px 2px;
  font-size: var(--labelTextSize);
  font-weight: 900;
  color: var(--mutedText);
}

.maLabelLg {
  display: block;
  margin: 0 0 6px 2px;
  font-size: 18px;
  font-weight: 900;
  color: var(--ink);
  line-height: 1.1;
}

.maValueLg {
  display: block;
  font-size: 20px;
  font-weight: 950;
  color: var(--ink);
  line-height: 1;
}

.maInputWrap {
  display: flex;
  gap: 8px;
  align-items: center;
  min-width: 0;
}

/* Input wrap with inner action button (chevron, clear, search icon, etc.)
   Usage: add .maInputWrap--inner to the wrap div, place .maInputInnerBtn
   as the last child after .maTextInput.                                   */
.maInputWrap--inner {
  position: relative;
}

.maInputWrap--inner .maTextInput {
  padding-right: 40px;
}

.maInputInnerBtn {
  position: absolute;
  right: 8px;
  top: 50%;
  transform: translateY(-50%);
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  -webkit-tap-highlight-color: transparent;
}

.maInputInnerBtn:active {
  opacity: 0.7;
  transform: translateY(-50%) scale(.93);
}

/* Clear variant — unicode × rendered as text */
.maInputInnerBtn--clear {
  font-size: 18px;
  font-weight: 700;
  color: var(--textMuted);
  line-height: 1;
}

.maTextInput {
  width: 100%;
  min-height: var(--btnHeight);
  padding: 0 12px;
  border-radius: var(--controlRadius);
  border: 1px solid var(--controlBorder);
  background: #fff;
  color: var(--ink);
  font-family: var(--fontFamilyBase);
  font-size: var(--inputTextSize);
  font-weight: 800;
  outline: none;
  min-width: 0;
  box-sizing: border-box;
}

.maTextInput:focus {
  border-color: var(--brandSecondary);
  box-shadow: 0 0 0 3px rgba(0,0,0,.06);
}

/* Regular weight for a .maTextInput that holds prose rather than a value
   (e.g. the message composer's Subject). */
.maTextInput--regular {
  font-weight: 400;
}

/* Multi-line text box — same look as .maTextInput, with room for lines
   (vertical padding, a taller start, drag to resize). Pages may set their
   own height (e.g. game_import.css). */
.maTextArea {
  display: block;
  width: 100%;
  min-height: 120px;
  padding: 10px 12px;
  border-radius: var(--controlRadius);
  border: 1px solid var(--controlBorder);
  background: #fff;
  color: var(--ink);
  font-family: var(--fontFamilyBase);
  font-size: var(--inputTextSize);
  font-weight: 800;
  line-height: 1.4;
  outline: none;
  resize: vertical;
  box-sizing: border-box;
}

.maTextArea:focus {
  border-color: var(--brandSecondary);
  box-shadow: 0 0 0 3px rgba(0,0,0,.06);
}

.maHelpText {
  font-size: 11px;
  font-weight: 600;
  color: var(--mutedText);
  line-height: 1.4;
  margin-top: 4px;
}


/* ==========================================================================
   16. DATE BADGE & CALENDAR
   ========================================================================== */

.maDateBadge {
  width: 62px;
  flex: 0 0 auto;
  border: 1px solid var(--borderSubtle);
  border-radius: var(--radiusLg);
  overflow: hidden;
  background: var(--cardBg);
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: center;
  padding: 0;
  line-height: 1;
}

.maDateBadge__top {
  background: var(--datebadgeTopBg);
  color: var(--datebadgeTopText);
  font-size: 12px;
  font-weight: 900;
  letter-spacing: .3px;
  text-align: center;
  padding: 6px 0 5px;
}

.maDateBadge__mid {
  color: var(--ink);
  font-size: 22px;
  font-weight: 950;
  text-align: center;
  padding: 8px 0 2px;
}

.maDateBadge__bot {
  color: rgba(17,17,17,.72);
  font-size: 12px;
  font-weight: 900;
  text-align: center;
  padding: 0 0 8px;
}

/* Calendar */
.maCalWrap {
  display: none; /* opened by JS via .open */
  margin-top: 12px;
  border: 1px solid var(--borderSubtle);
  border-radius: var(--radiusLg);
  overflow: hidden;
  background: #fff;
}

.maCalWrap.open { display: block; }

.maCalHeader {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px;
  background: var(--panelHdrBg);
  color: var(--panelHdrText);
  border-bottom: 1px solid var(--borderSubtle);
}

.maCalHint {
  font-size: 12px;
  font-weight: 900;
  opacity: .95;
}

.maCalLeft {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.maCalMonthLabel {
  font-size: 14px;
  font-weight: 900;
  letter-spacing: .2px;
  padding: 0 6px;
}

.maCalNavBtn { min-width: 40px; }

.maCalMiniBtn { padding: 0 10px; }

.maCalRight { display: none; } /* legacy pills kept in DOM */

.maCalDow {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 6px;
  padding: 10px 10px 0 10px;
  color: var(--mutedText);
  font-weight: 900;
  font-size: 11px;
}

.maCalGrid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 6px;
  padding: 10px;
}

.maCalDay {
  min-height: 36px;
  border-radius: 10px;
  border: 1px solid var(--borderSubtle);
  background: var(--cardBg);
  color: var(--ink);
  font-weight: 900;
  cursor: pointer;
}

.maCalDay:hover { background: var(--pressedBg); }
.maCalDay.muted { opacity: .45; }
.maCalDay.today { border-color: var(--brandSecondary); }

.maCalDay.selected {
  background: var(--brandSecondary);
  border-color: var(--brandSecondary);
  color: #fff;
}

.maCalDay.inRange {
  background: rgba(48, 110, 230, .10);
  border-color: rgba(48, 110, 230, .10);
}

.maCalDay.from,
.maCalDay.to {
  background: var(--brandSecondary);
  border-color: var(--brandSecondary);
  color: #fff;
}


/* ==========================================================================
   17. LIST ROWS
   Lightweight rows for search/recent lists (course picker, etc.)
   ========================================================================== */

.maListRows {
  display: flex;
  flex-direction: column;
  gap: 0;
  min-width: 0;
}

.maListRow {
  display: flex;
  gap: 10px;
  align-items: center;
  padding: 10px 10px;
  background: #fff;
  border-bottom: 1px solid var(--borderSubtle);
  cursor: pointer;
  user-select: none;
}

.maListRow:hover  { background: rgba(0,0,0,.02); }
.maListRow:active { background: rgba(0,0,0,.04); }
.maListRow--static {
  cursor: default;
  pointer-events: none;
}

.maListRow__col {
  min-width: 0;
  font-size: 13px;
  font-weight: 900;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.maListRow__col--muted {
  font-size: 13px;
  font-weight: 800;
  color: var(--mutedText);
}

.maListRow__col--right { text-align: right; }
.maListRow__col--rightJust {
  flex: 1;
  text-align: right;
  font-weight: 900;
  color: var(--ink);
}

.maListRow.is-selected {
  border-color: #7ea489;
  background: #f5faf6;
  box-shadow: 0 0 0 1px rgba(126,164,137,.45) inset;
}

.maListRow .maPill {
  min-height: 22px;
  padding: 0 10px;
  font-size: 12px;
  font-weight: 700;
}

/* Group divider label — section sub-heading within a scrollable list.
   Use to separate named buckets of rows (e.g. team groups on the roster,
   flight groups in pairings, status groups in any list view).

   Base style (no modifier): neutral tint, darkened ink for legibility in
   daylight. Pair with a --color modifier to add a team/status swatch dot.

   Usage:
     <div class="maListRow__group">All Players</div>
     <div class="maListRow__group maListRow__group--red">Team A</div>
     <div class="maListRow__group maListRow__group--blue">Team B</div>
     <div class="maListRow__group maListRow__group--none">No Team</div>

   Pages currently using this pattern:
     - game_players.js  → roster team groups (sort by team)
*/
.maListRow__group {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  /* Use --ink rather than --mutedText: the light brandPrimaryBg background
     makes #3a3a3a hard to read in bright daylight; --ink (#111) gives
     sufficient contrast at this small font size. */
  color: var(--ink);
  padding: 7px 12px 3px;
  background: var(--brandPrimaryBg);
  border-top: 0.5px solid var(--borderSubtle);
  border-bottom: 0.5px solid var(--borderSubtle);
  user-select: none;
}

/* Color-dot swatch — indicates team or category identity.
   Dot is suppressed on the base class (no modifier).
   Parallels .maSwatch but auto-inserted via ::before so no extra markup
   is needed. */
.maListRow__group--red::before,
.maListRow__group--blue::before,
.maListRow__group--none::before {
  content: "";
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}

.maListRow__group--red::before  { background: var(--danger); }
.maListRow__group--blue::before { background: var(--brandColor3); }
.maListRow__group--none::before { background: var(--mutedText); opacity: .45; }

/* Collapsible group divider — the whole divider toggles its rows; a compact
   +/- button (.iconBtn.iconBtn--sm.btnSecondary) sits where the swatch dot
   would be. Promoted from game_pairings.js's inline-styled tray group
   header (renderTrayGroupHeader). First use: Admin Reporting status groups.

   Usage:
     <div class="maListRow__group maListRow__group--collapsible" data-...>
       <button class="iconBtn iconBtn--sm btnSecondary" type="button">…14px svg…</button>
       <span>Unregistered (12)</span>
     </div>
*/
.maListRow__group--collapsible {
  cursor: pointer;
  padding-top: 5px;
  padding-bottom: 5px;
}

/* Avatar circle — circular initials badge used as left slot in a list row */
.maListRow__avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 800;
  flex-shrink: 0;
  background: rgba(0,0,0,.07);
  color: var(--mutedText);
}



/* Label slot — fixed left column in a list row, the same setup as
   .maListRow__avatar but sized for a short label or a small button, so the
   values on stacked rows line up (e.g. the message composer's To / From /
   Subject lines, Outlook-style). Pair with .maListRow__value. */
.maListRow__label {
  flex: 0 0 72px;
  font-weight: 700;
  color: var(--mutedText);
}

/* Value slot — the rest of the row after a .maListRow__label, in regular
   weight (unlike .maListRow__col, which is for names). */
.maListRow__value {
  flex: 1 1 auto;
  min-width: 0;
  font-weight: 400;
}

/* --- Row state modifier classes (must follow base .maListRow rule) --- */

/* Selected row — multi-add active selection */
.maListRow--selected {
  background: var(--rowBgSelected);
}

/* Enrolled / inactive row — player already in game */
.maListRow--enrolled {
  background: var(--rowBgEnrolled);
  cursor: default;
  pointer-events: none;
}

/* Pinned row — always-first identity row (e.g. "You") */
.maListRow--pinned {
  border-bottom: 2px solid var(--rowPinnedDivider) !important;
}

/* Gender-coded avatar color modifiers (must follow base .maListRow__avatar rule) */
.maListRow__avatar--m { background: var(--avatarMaleBg); color: var(--avatarText); }
.maListRow__avatar--f { background: var(--avatarFemaleBg); color: var(--avatarText); }
.maListRow__avatar--u { background: var(--avatarUnknownBg); color: var(--avatarText); }

/* Avatar border — applied via modifier so it only affects gender-coded avatars */
.maListRow__avatar--m,
.maListRow__avatar--f,
.maListRow__avatar--u {
  border: 2px solid var(--avatarBorder);
}

/* Standard muted subline */
.maListRow__subline {
  font-size: 11px;
  font-weight: 700;
  color: var(--mutedText);
  margin-top: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Wrapping helper/hint text — explains what a control's current selection
   means (e.g. Define Flights' apply-to-all-rounds hint). Unlike
   .maListRow__subline this wraps instead of truncating, since it's a full
   sentence, not a label. */
.maHintText {
  font-size: 11px;
  font-weight: 600;
  color: var(--mutedText);
  line-height: 1.4;
  margin-top: 6px;
}

/* Larger variant — for hints that stand alone as the primary guidance in
   a controls band (e.g. "Use the Actions Menu to print"), rather than a
   secondary annotation sitting next to a control. Same weight/color/
   line-height as the base, just sized up. */
.maHintText--lg {
  font-size: 15px;
}

/* Right-aligned variant, margin reset — for hint text sitting as a
   horizontal flex sibling (e.g. a card header's right-side note next to
   the title) rather than stacked below something, where the base
   margin-top would be wrong. First use: Hole Champions' card-header note. */
.maHintText--right {
  text-align: right;
  margin-top: 0;
}

/* Empty/missing data subline — italic hint */
.maListRow__subline--empty {
  font-size: 11px;
  font-weight: 600;
  color: var(--mutedText);
  font-style: italic;
  margin-top: 2px;
}

/* Indented past a swatch — used under team name inputs in MA.manageTeams
   to align the player-count label past the 10px swatch + 8px gap = 18px.
   Replaces gpSub--indented. */
.maListRow__subline--indented {
  padding-left: 18px;
}

/* Pinned identity label — "You" pill */
.maListRow__pinnedLabel {
  display: inline-block;
  font-size: 10px;
  font-weight: 700;
  padding: 1px 7px;
  border-radius: 99px;
  background: var(--brandSecondary);
  color: var(--brandSecondaryText);
  line-height: 1.6;
  margin-left: 6px;
  vertical-align: middle;
}

/* ==========================================================================
   SHARED CHECKBOX — .maCheckbox / .maCheckbox.is-checked
   Reusable row-level checkbox using brand tokens.
   Used by: Buddy Groups modal, game pairings, admin picker, and any future
   multi-select list. Replaces page-local variants (gpRowCheck, gmTagCheck,
   maAdminRow__check).

   Markup pattern:
     <div class="maCheckbox"></div>                  — unchecked
     <div class="maCheckbox is-checked"></div>       — checked
   The checkmark is rendered via ::after pseudo-element (no inner text needed).
   ========================================================================== */

.maCheckbox {
  width: 20px;
  height: 20px;
  border-radius: var(--radiusSq);
  border: 1px solid var(--borderSubtle);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  background: var(--bg);
  box-sizing: border-box;
  transition: background 0.1s, border-color 0.1s;
}

.maCheckbox.is-checked {
  background: var(--brandSecondary);
  border-color: var(--brandSecondary);
}

.maCheckbox.is-checked::after {
  content: '';
  width: 10px;
  height: 6px;
  border-left: 2px solid #ffffff;
  border-bottom: 2px solid #ffffff;
  transform: rotate(-45deg) translateY(-1px);
  display: block;
}

/* ---------- .maCheckbox--accent — blue variant ---------------------------
   Same component, --brandAccent instead of the default brandSecondary
   green — matches the blue already used for selection state everywhere
   else it appears (.gpRowCheck.is-selected, .gpMasterCheck.has-selection
   in game_pairings.css; .maListRow.is-selected here). Not --brandColor3
   ("button blue" / .btnSecondary) — that's a different semantic role.
   Additive modifier, same convention as .btn--confirm / .btn--danger
   (section 21e). The base .maCheckbox.is-checked default is untouched
   for existing consumers (Buddy Groups modal, game pairings, admin
   picker).
   ------------------------------------------------------------------------- */
.maCheckbox--accent.is-checked {
  background: var(--brandAccent);
  border-color: var(--brandAccent);
}


/* ==========================================================================
   18. ADMIN PICKER
   ========================================================================== */

.maAdminPick__top { margin-top: 12px; }

.maAdminPick {
  margin-top: 10px;
  border: 1px solid var(--borderSubtle);
  border-radius: var(--radiusLg);
  overflow: hidden;
  background: #fff;
}

.maAdminPick__hdr {
  display: grid;
  grid-template-columns: 44px 1fr 44px;
  gap: 8px;
  align-items: center;
  padding: 10px;
  background: var(--panelHdrBg);
  color: var(--panelHdrText);
  border-bottom: 1px solid var(--borderSubtle);
}

.maAdminPick__hdrName {
  font-weight: 900;
  letter-spacing: .2px;
}

.maAdminPick__rows {
  max-height: 360px;
  overflow: auto;
}

.maAdminRow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--borderSubtle);
  cursor: pointer;
  user-select: none;
}

.maAdminRow:hover { background: var(--pressedBg); }

.maAdminRow__left {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}

.maAdminRow__check {
  width: 22px;
  height: 22px;
  border-radius: 7px;
  border: 1px solid var(--borderSubtle);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  font-weight: 900;
  color: var(--mutedText);
  flex: 0 0 auto;
}

.maAdminRow__check.on {
  background: var(--brandSecondary);
  border-color: var(--brandSecondary);
  color: #fff;
}

.maAdminRow__name {
  font-weight: 900;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.maAdminRow__right {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
}


/* ==========================================================================
   19. MISC — EMPTY STATE, TAB PANELS, GAME CARD OVERRIDES
   ========================================================================== */

.maEmptyState {
  margin: 10px 0;
  padding: 16px 14px;
  text-align: center;
  color: var(--mutedText);
  font-weight: 800;
  border: 1px dashed var(--borderSubtle);
  border-radius: var(--radiusLg);
  background: var(--cardBg);
}

.maTabPanel { display: none; }
.maTabPanel.is-active { display: block; }

/* Hide game card manage button on mobile */
@media (max-width: 600px) {
  .maGameCard__manageBtn {
    display: none !important;
  }
}

/* ==========================================================================
   20. PAGE HELP — Modal + Header Button
   ========================================================================== */
 
/* --- Help button in chrome header --- */
.maHelpBtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: none;
  background: transparent;
  padding: 0;
  cursor: pointer;
  flex-shrink: 0;
  -webkit-tap-highlight-color: transparent;
}
 
.maHelpBtn:active {
  transform: scale(.93);
}
 
.maHelpBtn img {
  width: 26px;
  height: 26px;
  display: block;
  border-radius: 50%;
}
 
/* Hidden on mobile — help is a desktop affordance */
@media (max-width: 600px) {
  .maHelpBtn {
    display: none;
  }
}
 
/* Ensure right slot has correct gap and alignment when help button is present */
/* Gap tripled (30px) to give breathing room between ? and Actions button */
.maChrome__hdrRight {
  gap: calc(var(--chromeGap) * 3);
  justify-content: flex-end;
}
 
/* --- Help modal sizing --- */
.maHelpModal {
  max-width: 620px;
  width: min(620px, calc(100vw - 32px));
}
 
/* --- Help modal body layout --- */
.maHelpBody {
  display: flex;
  flex-direction: column;
}
 
/* --- Individual help section --- */
.maHelpSection {
  display: grid;
  grid-template-columns: 44px 1fr;
  gap: var(--spaceMd);
  padding: var(--spaceMd) 0;
  border-top: 1px solid var(--borderSubtle);
}
 
.maHelpSection:first-child {
  border-top: 0;
  padding-top: 0;
}
 
/* --- Icon circle --- */
.maHelpIcon {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--brandPrimary) 10%, transparent);
  color: var(--brandPrimary);
  flex-shrink: 0;
}
 
/* --- Section text --- */
.maHelpSection__content {
  display: flex;
  flex-direction: column;
  gap: var(--spaceSm);
}
 
.maHelpSection__title {
  margin: 0;
  font-size: var(--labelTextSize);
  font-weight: 900;
  color: var(--brandPrimary);
}
 
.maHelpSection__body {
  margin: 0;
  font-size: var(--fieldValueSize);
  color: var(--ink);
  line-height: 1.45;
}
 
.maHelpList {
  margin: 0;
  padding-left: 1.1rem;
  color: var(--ink);
  font-size: var(--fieldValueSize);
}
 
.maHelpList li {
  margin-bottom: var(--spaceSm);
  line-height: 1.4;
}
 
.maHelpList li:last-child {
  margin-bottom: 0;
}
 
.maHelpSubList {
  margin: var(--spaceSm) 0 0 0;
  padding-left: 1rem;
  list-style-type: circle;
  color: var(--mutedText);
  font-size: var(--fieldValueSize);
  display: flex;
  flex-direction: column;
  gap: 2px;
}
 
.maHelpSubList li {
  line-height: 1.35;
}
 
/* --- Tab panels — hidden by default, shown when is-active --- */
.maHelpTabPanel {
  display: none;
}
 
.maHelpTabPanel.is-active {
  display: block;
}
 
/* --- Segmented control inside help modal controls area --- */
.maHelpSeg {
  width: 100%;
}
 
/* --- Mobile adjustments (modal still usable if somehow reached) --- */
@media (max-width: 640px) {
  .maHelpModal {
    width: calc(100vw - 20px);
  }
 
  .maHelpSection {
    grid-template-columns: 36px 1fr;
  }
 
  .maHelpIcon {
    width: 34px;
    height: 34px;
  }
}

/* ==========================================================================
   ADDITIONS TO ma_shared.css
   Add .maSwatch to Section 1 (Design Tokens / utility classes).
   Add .maTeamBadge to Section 13 (Pills & Chips), after .maChoiceChip block.
   ========================================================================== */


/* ---------- Section 1 addition — after the :root block -------------------
   .maSwatch — generic color dot used beside labelled inputs.
   Color modifier classes follow the same --red / --blue pattern as other
   semantic utilities in the system.
   ------------------------------------------------------------------------- */

.maSwatch {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}

.maSwatch--red  { background: var(--danger); }
.maSwatch--blue { background: var(--brandColor3); }


/* ---------- Section 13 addition — after .maChoiceChip block --------------
   .maTeamBadge — interactive team assignment button.
   Visually similar to maPill but is a <button>, not a display element.
   Used in the Manage Teams module roster to assign players to T1 / T2.
   ------------------------------------------------------------------------- */

.maTeamBadge {
  font-size: 11px;
  font-weight: 800;
  padding: 3px 9px;
  border-radius: var(--pillRadius);
  border: 1px solid;
  cursor: pointer;
  white-space: nowrap;
  font-family: var(--fontFamilyBase);
  line-height: 1.4;
  background: transparent;
}

.maTeamBadge:active {
  transform: scale(.96);
}

.maTeamBadge:disabled {
  opacity: .55;
  cursor: default;
  transform: none;
}

/* Color variants — inactive (outline) state */
.maTeamBadge--red {
  color: var(--danger);
  border-color: color-mix(in srgb, var(--danger) 35%, transparent);
  background: color-mix(in srgb, var(--danger) 6%, white);
}

.maTeamBadge--blue {
  color: var(--brandColor3);
  border-color: color-mix(in srgb, var(--brandColor3) 35%, transparent);
  background: color-mix(in srgb, var(--brandColor3) 6%, white);
}

.maTeamBadge--none {
  color: var(--mutedText);
  border-color: var(--borderSubtle);
  background: transparent;
}

/* Active (filled) state — player is assigned to this team */
.maTeamBadge--red.is-active {
  background: var(--danger);
  color: #ffffff;
  border-color: color-mix(in srgb, var(--danger) 80%, black);
}

.maTeamBadge--blue.is-active {
  background: var(--brandColor3);
  color: #ffffff;
  border-color: color-mix(in srgb, var(--brandColor3) 80%, black);
}

.maTeamBadge--none.is-active {
  background: var(--mutedText);
  color: #ffffff;
  border-color: var(--mutedText);
}


/* ==========================================================================
   21. SOURCE MODULE SHARED VOCABULARY
   Phase 1 — CSS Foundation
   Promoted from game_players.css gp* classes.
   All source modules (MA.ghinSearch, MA.favoritesSource, MA.nonRatedSource,
   MA.eventRosterSource) and their host pages (game_players, event_roster)
   reference only these shared names — no gp* class names.

   Sub-sections:
     21a. List row layout variants
     21b. Icon button variants (enrollment indicators)
     21c. Clearable input wrapper
     21d. Multi-add toggle strip
     21e. Button modifier variants
     21f. Inline status / feedback band
     21g. Utility
   ========================================================================== */


/* ---------- 21a. List row layout variants --------------------------------
   These extend .maListRow with a grid-template-columns override that
   matches the column structure each source module renders.
   Always applied alongside the base .maListRow class.
   ------------------------------------------------------------------------- */

/* 4-col grid: name │ HI │ gender │ indicator
   Used by MA.ghinSearch (panel + modal) and MA.eventRosterSource rows
   that show GHIN-sourced players. */
.maListRow--player {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 56px 46px 34px;
  align-items: center;
  column-gap: var(--spaceSm);
  padding: 8px var(--spaceMd);
}

/* 3-col grid: avatar │ name+subline │ indicator
   Used by MA.favoritesSource in single-add mode. */
.maListRow--favorites {
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr) 34px;
  align-items: center;
  column-gap: var(--spaceSm);
  padding: 8px var(--spaceMd);
}

/* 4-col grid: checkbox │ avatar │ name+subline │ indicator
   Used by MA.favoritesSource in multi-add mode. */
.maListRow--favoritesMulti {
  display: grid;
  grid-template-columns: 34px 34px minmax(0, 1fr) 34px;
  align-items: center;
  column-gap: var(--spaceSm);
  padding: 8px var(--spaceMd);
}

/* 4-col grid: checkbox │ name+subline │ badge group │ indicator
   Used by MA.eventRosterSource in multi-add mode. Mirrors
   .maListRow--favoritesMulti's checkbox column, but replaces the
   fixed-width avatar slot with an auto-sized team/pairing badge group,
   since event-roster rows have no avatar. */
.maListRow--playerMulti {
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr) auto 34px;
  align-items: center;
  column-gap: var(--spaceSm);
  padding: 8px var(--spaceMd);
}

/* 3-col grid: avatar │ name+subline │ badge group
   Used by MA.manageTeams roster rows. Replaces gpRow--teams. */
.maListRow--teams {
  display: grid;
  grid-template-columns: 30px minmax(0, 1fr) auto;
  align-items: center;
  column-gap: 8px;
  padding: 8px;
}

/* Green tint — marks the row currently loaded into the Non-Rated edit form.
   Replaces gpNrRow--selected. */
.maListRow--active {
  background: color-mix(in srgb, var(--brandPrimary) 6%, white);
}


/* ---------- 21b. Icon button variants — enrollment indicators ------------
   Applied to .iconBtn elements that serve as enroll / already-enrolled
   indicators in source module rows. .iconBtn:disabled { opacity: 1 } in
   Section 14 ensures these remain fully visible when non-interactive.
   ------------------------------------------------------------------------- */

/* Blue + — player not yet enrolled; tapping initiates enrollment */
.iconBtn--add {
  border-color: var(--brandAccent);
  color: var(--brandAccent);
}

/* Green checkmark — player already enrolled; non-interactive */
.iconBtn--check {
  border-color: var(--brandPrimary);
  color: var(--brandPrimary);
}

/* Compact 20px size — for toggles inside small dividers (see
   .maListRow__group--collapsible). Pair with a 14px icon. */
.iconBtn--sm {
  width: 20px;
  height: 20px;
  flex: 0 0 20px;
}


/* ---------- 21c. Clearable input wrapper ---------------------------------
   Wraps a .maTextInput with an absolutely-positioned × clear button.
   Replaces gpInputClearWrap / clearBtn.

   Markup pattern:
     <div class="maInputWrap--clearable">
       <input class="maTextInput" …>
       <button class="maClearBtn isHidden" type="button">×</button>
     </div>
   ------------------------------------------------------------------------- */

.maInputWrap--clearable {
  position: relative;
}

/* Push right padding so text doesn't slide under the × button */
.maInputWrap--clearable .maTextInput {
  padding-right: 30px;
}

/* Position the × button inside the right edge of the input */
.maInputWrap--clearable .maClearBtn {
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
}

/* The × button itself */
.maClearBtn {
  border: 0;
  background: transparent;
  color: var(--mutedText);
  width: 24px;
  height: 24px;
  border-radius: 12px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  line-height: 1;
  padding: 0;
}

.maClearBtn:hover {
  background: rgba(0, 0, 0, .06);
}


/* ---------- 21d. Multi-add toggle strip ----------------------------------
   Thin band above the list body showing "Select All / Clear All" actions.
   Replaces gpMultiSelectToggle / gpMultiSelectToggle__text.

   Markup pattern:
     <div class="maMultiToggle">
       <span class="maMultiToggle__action" data-act="select-all">Select All</span>
       &nbsp;·&nbsp;
       <span class="maMultiToggle__action" data-act="clear-all">Clear All</span>
     </div>
   ------------------------------------------------------------------------- */

.maMultiToggle {
  padding: 5px 12px;
  border-bottom: 0.5px solid var(--borderSubtle);
  background: var(--rowBgDefault);
}

.maMultiToggle__action {
  font-size: 11px;
  font-weight: 500;
  color: var(--brandAccent);
  cursor: pointer;
  user-select: none;
}

.maMultiToggle__action:hover {
  text-decoration: underline;
}


/* ---------- 21e. Button modifier variants --------------------------------
   Applied alongside the base .btn class.
   Replaces inline styles previously used for Update Player / Cancel buttons.
   ------------------------------------------------------------------------- */

/* Green confirm — primary action (Update Player, Confirm) */
.btn--confirm {
  background: var(--brandPrimary);
  color: #fff;
  border-color: var(--brandPrimary);
}

.btn--confirm:active {
  filter: brightness(.93);
}

/* Red danger — destructive / cancel action */
.btn--danger {
  color: var(--danger);
  border-color: rgba(198, 40, 40, .3);
}

.btn--danger:active {
  background: color-mix(in srgb, var(--danger) 8%, white);
}


/* ---------- 21f. Inline status / feedback band ---------------------------
   Narrow tinted band rendered below the controls area inside a source
   module to show result counts, truncation warnings, or search hints.
   Replaces gpInlineStatus / maInlineAlert--warn.
   ------------------------------------------------------------------------- */

.maInlineStatus {
  padding: var(--spaceMd) 8px;
  font-size: 12px;
  font-weight: 600;
  color: var(--mutedText);
  border-bottom: 1px solid var(--borderSubtle);
}


/* ---------- 21g. Utility ------------------------------------------------- */

/* Global display:none — replaces the scoped .clearBtn.isHidden pattern.
   Applied by JS on any element that should be hidden without layout impact.
   The !important mirrors the intent of the original scoped rule and prevents
   specificity fights with layout classes. */
.isHidden {
  display: none !important;
}


/* ---------- 21h. Canvas controls row — sort strip + action group ---------
   Generic "controls row, space-between, right-aligned action cluster"
   layout. Used above the main roster/canvas list on both Game Players
   and Event Roster (sort buttons left, Manage Teams / other actions
   right). Promoted from page-scoped gpCanvasControls — purely
   structural, no page-specific values, so it belongs here rather than
   duplicated per page.
   ------------------------------------------------------------------------- */

.maCanvasControls {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  flex-wrap: wrap;
}

.maCanvasControls__right {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
}

/* ---------- 21i. .maTable — frozen-header/column table mechanics --------
   Generic, reusable table shell for any dense data grid needing a sticky
   header row and/or sticky first column — no scorecard/golf vocabulary in
   any of these names on purpose. First consumer is the scorecard module's
   two tables (see Section 23), but promoted here rather than kept
   module-local since a frozen-header/column data table is exactly the
   kind of thing other pages are likely to want eventually (standings,
   pairings grids, etc.) — same "shared vocabulary" reasoning as every
   other rule in this section.

   Expected markup:
     <table class="maTable">
       <thead><tr>
         <th class="maTable__frozenCorner">...</th>   (optional — only if
                                                         the header row ALSO
                                                         has a frozen first
                                                         column)
         <th>...</th>   (sticky-top applies to every header cell automatically)
         ...
       </tr></thead>
       <tbody>
         <tr>
           <td class="maTable__frozenCol">...</td>     (optional — only if
                                                         this table has a
                                                         frozen first column)
           <td>...</td>
         </tr>
         <tr class="maTable__subtotalRow">...</tr>
         <tr class="maTable__totalRow">...</tr>
       </tbody>
     </table>

   NOTE: the scorecard module (Section 23) doesn't use the
   .maTable__frozenCol / .maTable__frozenCorner classes directly — it folds
   the identical sticky mechanics into its own .scTHoleCol class instead,
   since that's the only column it's ever applied to. Both approaches
   produce the same result; a future consumer with no scorecard-specific
   column of its own would reach for these classes directly.
   ------------------------------------------------------------------------- */

.maTable {
  border-collapse: collapse;
  width: 100%;
  font-size: var(--maTableFontSize, 12px);
}

/* Size modifier, independent of any structural modifier (e.g.
   .maTable--transposed) — composes with it if a table ever needs both.
   First use: Hole Champions, which needs larger text than the default
   scorecard grid without affecting that grid's own font-size at all. */
.maTable--fontLg {
  --maTableFontSize: 15px;
}

.maTable td,
.maTable th {
  padding: 4px 6px;
  text-align: center;
  border-right: 0.5px solid var(--borderSubtle);
  border-bottom: 0.5px solid var(--borderSubtle);
  vertical-align: middle;
}

/* Every header cell is sticky-top by default — no modifier class needed
   for the common case of "just freeze the header row." */
.maTable thead th {
  position: sticky;
  top: 0;
  z-index: 3;
  background: var(--panelControlsBg);
  border-bottom: 1.5px solid var(--borderSubtle);
  font-weight: 800;
}

.maTable__frozenCol {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--panelControlsBg);
  border-right: 1.5px solid var(--borderSubtle);
}

.maTable__frozenCorner {
  position: sticky;
  top: 0;
  left: 0;
  z-index: 4;
  background: var(--panelControlsBg);
  border-right: 1.5px solid var(--borderSubtle);
  border-bottom: 1.5px solid var(--borderSubtle);
}

/* Subtotal / total row tiers — both resolved from tokens already defined
   in Section 1, not new colors. */
.maTable__subtotalRow td,
.maTable__subtotalRow th {
  background: var(--borderSubtle);
  font-weight: 800;
  border-top: 1px solid var(--borderSubtle);
  border-bottom: 1px solid var(--borderSubtle);
  color: var(--ink);
}

.maTable__totalRow td,
.maTable__totalRow th,
td.maTable__totalRow,
th.maTable__totalRow {
  background: var(--ControlAreaBorder);
  font-weight: 800;
  border-top: 1px solid var(--ControlAreaBorder);
  border-bottom: 1px solid var(--ControlAreaBorder);
  color: var(--ink);
}

/* Sticky frozen-column cell inside a subtotal/total row reads one shade
   darker than its own row so it stays legible while the table scrolls
   horizontally underneath it — same color-mix-off-an-existing-token
   trick this file already uses for --ControlAreaBg. */
.maTable__subtotalRow td.maTable__frozenCol {
  background: color-mix(in srgb, var(--borderSubtle) 85%, black);
}

.maTable__totalRow td.maTable__frozenCol {
  background: color-mix(in srgb, var(--ControlAreaBorder) 85%, black);
}

/* ---------- 21j. Label/value column pair — the scorecard grid's shape
   (one left-aligned label column, several centered value columns) —
   confirmed unique to this table, no other table in the app has this
   shape, so it lives here as its own real component rather than a
   one-off page class. ------------------------------------------------- */

.maTable td.maTable__labelCol,
.maTable th.maTable__labelCol {
  text-align: left;
  white-space: normal;
  cursor: pointer;
}

.maTable td.maTable__labelCol:hover,
.maTable th.maTable__labelCol:hover {
  background: var(--pressedBg);
}

.maTable__valueCol {
  text-align: center;
  cursor: pointer;
}

.maTable__valueCol:hover {
  background: var(--pressedBg);
}

.maTable__valueCol--minor {
  font-size: 11px;
  color: var(--ink);
}

/* ---------- 21k. Detail row — a secondary row nested under a primary
   row, toggled via the existing .isHidden utility (no new toggle
   mechanism needed). First use: stroke-marks row under each player. --- */

.maTable__detailRow td {
  background: var(--surfaceApp);
  font-size: 10px;
  color: var(--mutedText);
}

/* ---------- 21l. Frozen hole-label column — narrow-column specifics
   layered on top of the generic .maTable__frozenCol sticky mechanic
   (21i). Applied together: class="maTable__frozenCol maTable__holeCol". */

.maTable__holeCol {
  min-width: 68px;
  width: 68px;
}

/* ---------- 21m. Total column header tint — a header COLUMN
   identification tint (marking "this column is a pairing total"),
   distinct in purpose from .maTable__totalRow (which tints a DATA row).
   Not the same value as __totalRow on purpose — different concept. ---- */

.maTable__totalColHeader {
  background: color-mix(in srgb, var(--panelControlsBg) 91%, black);
  white-space: normal;
  min-width: 44px;
}

/* ---------- 21n. Transposed-table cell sizing — the pivoted/drawer
   view uses larger score cells than the main scorecard grid. Scoped to
   this modifier rather than bare .maCell, since both tables share
   .maTable as a base and need different cell sizes. --------------------- */

.maTable--transposed .maCell {
  min-width: 24px;
  min-height: 24px;
}

.maTable--transposed .maCell--birdie .maCellVal,
.maTable--transposed .maCell--eagle .maCellVal,
.maTable--transposed .maCell--bogey .maCellVal,
.maTable--transposed .maCell--bogeyplus .maCellVal {
  min-width: 20px;
  height: 20px;
}

/* ---------- 21o. Score cell + shape indicators — an individual
   scorecard cell carrying a status/shape indicator (birdie/eagle/bogey).
   Confirmed genuinely novel — nothing else in the app needs "circle/box
   around a number to indicate performance relative to par." Shape
   borders stay hardcoded #000 on purpose — universal scorecard
   convention, shouldn't move with brand color. ------------------------- */

.maCell {
  position: relative;
  min-height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.maCellVal {
  font-weight: 800;
}

.maCell--declared {
  background: var(--rowBgSelected);
}

.maCell--birdie .maCellVal {
  border-radius: 999px;
  border: 1.8px solid #000;
  display: inline-flex;
  min-width: 16px;
  height: 16px;
  align-items: center;
  justify-content: center;
  padding: 0 5px;
}

.maCell--eagle .maCellVal {
  border-radius: 999px;
  border: 1.8px double #000;
  display: inline-flex;
  min-width: 16px;
  height: 16px;
  align-items: center;
  justify-content: center;
  padding: 0 5px;
}

.maCell--bogey .maCellVal {
  border: 1.8px solid #000;
  display: inline-flex;
  min-width: 16px;
  height: 16px;
  align-items: center;
  justify-content: center;
  padding: 0 5px;
}

.maCell--bogeyplus .maCellVal {
  border: 2px solid #000;
  display: inline-flex;
  min-width: 16px;
  height: 16px;
  align-items: center;
  justify-content: center;
  padding: 0 5px;
  box-shadow: inset 0 0 0 1px #000;
}

.maCellSuperscripts {
  position: absolute;
  top: 2px;
  right: 2px;
  font-size: 7px;
  font-weight: 700;
  color: var(--mutedText);
}

/* ==========================================================================
   22. MA.ui — BUSY / CONFIRM FOOTER / MODAL NOTICE / TOAST
   Additive support for MA.ui.* (ma_shared.js). Reuses existing tokens only —
   no new colors introduced.
   ========================================================================== */

/* ---------- Busy overlay body (MA.ui.showBusy) --------------------------- */
.maModal--busy .maModal__body,
.maModalBusy__body {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 28px 20px;
  text-align: center;
}

.maModalBusy__spinner {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 3px solid var(--borderSubtle);
  border-top-color: var(--brandAccent);
  animation: maSpin 0.8s linear infinite;
}

.maModalBusy__title {
  font-family: var(--fontFamilyBase);
  font-size: var(--modalTitleSize);
  font-weight: 900;
  color: var(--ink);
}

.maModalBusy__message {
  font-family: var(--fontFamilyBase);
  font-size: var(--fieldValueSize);
  color: var(--mutedText);
  line-height: 1.5;
}

@keyframes maSpin {
  to { transform: rotate(360deg); }
}

/* ---------- Confirm/info footer buttons (MA.ui.confirm) ------------------ */
.maModalFtr--right {
  justify-content: flex-end;
}

.maModalFtr__btn {
  height: 38px;
  padding: 0 var(--btnPadX);
  border-radius: var(--controlRadius);
  border: 1px solid transparent;
  font-family: var(--fontFamilyBase);
  font-size: 13px;
  font-weight: 800;
  cursor: pointer;
}

.maModalFtr__btn:active {
  transform: scale(.98);
}

.maModalFtr__btn--cancel {
  background: var(--btnCancelBg);
  color: var(--btnCancelText);
  border-color: var(--btnCancelBorder);
}

.maModalFtr__btn--confirm {
  background: var(--btnSaveBg);
  color: #ffffff;
}

.maModalFtr__btn--danger {
  background: var(--danger);
  color: #ffffff;
}

/* ---------- Modal notice band tone (MA.ui.showModalNotice) --------------- */
/* .maInlineStatus already exists (Sec 21f) for neutral bands; these add tone. */
.maInlineStatus.status-info    { background: var(--statusInfoBg);    color: var(--statusInfoText); }
.maInlineStatus.status-success { background: var(--statusSuccessBg); color: var(--statusSuccessText); }
.maInlineStatus.status-warn    { background: var(--statusWarnBg);    color: var(--statusWarnText); }
.maInlineStatus.status-danger  { background: var(--statusDangerBg);  color: var(--statusDangerText); }

/* ---------- Toast (MA.ui.notify, shown only while a modal is open) ------- */
:root {
  --toastZ: 100000; /* above --overlayZ (99990) so it's never hidden behind a modal */
}

.maToast {
  position: fixed;
  left: 50%;
  bottom: calc(16px + env(safe-area-inset-bottom));
  transform: translateX(-50%) translateY(8px);
  z-index: var(--toastZ);
  max-width: min(360px, calc(100vw - 32px));
  padding: 10px 16px;
  border-radius: var(--radiusMd);
  box-shadow: var(--modalShadow);
  font-family: var(--fontFamilyBase);
  font-size: 13px;
  font-weight: 700;
  text-align: center;
  cursor: pointer;
  opacity: 0;
  visibility: hidden;
  transition: opacity .15s ease, transform .15s ease, visibility .15s;
}

.maToast.is-open {
  opacity: 1;
  visibility: visible;
  transform: translateX(-50%) translateY(0);
}

.maToast.status-info    { background: var(--statusInfoBg);    color: var(--statusInfoText); }
.maToast.status-success { background: var(--statusSuccessBg); color: var(--statusSuccessText); }
.maToast.status-warn    { background: var(--statusWarnBg);    color: var(--statusWarnText); }
.maToast.status-danger  { background: var(--statusDangerBg);  color: var(--statusDangerText); }

@media (max-width: 600px) {
  .maToast {
    left: 12px;
    right: 12px;
    bottom: calc(12px + env(safe-area-inset-bottom));
    max-width: none;
    transform: translateY(8px);
  }

  .maToast.is-open {
    transform: translateY(0);
  }
}

/* Event-context modal header — explicit escape hatch for modules that
   self-determine portal from fetched data rather than ambient page
   state (e.g. module_menuGameSettings.js keys off a specific game's own
   dbGames_EID). In the common case this is now redundant with plain
   .maModal__hdr inheriting --layer1-bg from an ancestor .is-event-context,
   but it stays correct for the case where a module's own data disagrees
   with the page's ambient context. Derives from the same layer1 formula
   rather than hardcoding brandTertiary a second time. Modals sit at L1,
   not L2 — a full-focus overlay reads closer to a panel header in
   visual weight than a content card. */
.maModal__hdr.is-event-context {
  background: color-mix(in srgb, var(--brandTertiary) 75%, white);
  color: #ffffff;
}


/* ==========================================================================
   Rich text editor (Quill 2, assets/vendor/quill/) — .maRichText wraps the
   editor element so Quill's toolbar (inserted as a sibling) and its
   container both pick up app tokens. Used by the message composer
   (assets/modules/composeEmail.js). quill.snow.css supplies the rest.
   ========================================================================== */
.maRichText .ql-toolbar.ql-snow,
.maRichText .ql-container.ql-snow {
  border-color: var(--borderSubtle);
  background: var(--bg);
}
.maRichText .ql-toolbar.ql-snow {
  border-radius: var(--controlRadius) var(--controlRadius) 0 0;
}
.maRichText .ql-container.ql-snow {
  border-radius: 0 0 var(--controlRadius) var(--controlRadius);
  font-family: var(--fontFamilyBase);
  font-size: var(--fieldValueSize);
}
.maRichText .ql-editor {
  min-height: 160px;
  max-height: 40vh;
  overflow-y: auto;
  color: var(--ink);
}
.maRichText .ql-editor.ql-blank::before {
  color: var(--mutedText);
  font-style: normal;
}
