:root {
    --bg-primary: #0a0e1a;
    --bg-secondary: #131829;
    --bg-card: #1e2440;
    --bg-hover: #252d4a;
    --accent: #e8611a;
    --accent-light: #f97316;
    --green: #22c55e;
    --red: #ef4444;
    --text-primary: #e2e8f0;
    --text-secondary: #94a3b8;
    --text-muted: #475569;
    --border: #2d3561;
    --gold: #f59e0b;
    --silver: #94a3b8;
    --bronze: #cd7f32;
    /* Surface aliases used by the schedule modals. */
    --surface: #1e2440;
    --surface2: #252d4a;
    --text: #e2e8f0;
    --blue: #2563eb;
    --nav-active: #e8611a;  /* selected left-menu entry: the brand orange (--accent) */
}

* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

body {
    background-color: var(--bg-primary);
    color: var(--text-primary);
    font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
    font-size: 14px;
    line-height: 1.5;
}

/* Thin scrollbars in the dark theme. scrollbar-width is not inherited (hence
   the universal selector); scrollbar-color is. More specific rules (e.g.
   scrollbar-width:none on mobile bars) still win. ::-webkit-scrollbar is for
   Safari and older Chrome. */
* {
    scrollbar-width: thin;
}

html {
    scrollbar-color: #3b4680 transparent;
}

::-webkit-scrollbar {
    width: 8px;
    height: 8px;
}

::-webkit-scrollbar-track {
    background: transparent;
}

::-webkit-scrollbar-thumb {
    background: #3b4680;
    border-radius: 8px;
    border: 2px solid transparent;
    background-clip: padding-box;
}

::-webkit-scrollbar-thumb:hover {
    background: #5563a8;
    background-clip: padding-box;
}

::-webkit-scrollbar-corner {
    background: transparent;
}

/* Pull-to-refresh indicator (home screen mode, _initPullToRefresh in static/js/app/boot.js).
   Follows the finger, shows ↓ then ↻ past the threshold, spins while reloading. */
#ptr-indicator {
    position: fixed;
    top: calc(env(safe-area-inset-top, 0px) + 6px);
    left: 50%;
    transform: translate(-50%, -60px);
    opacity: 0;
    z-index: 10000;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--bg-card);
    border: 1px solid var(--border);
    box-shadow: 0 4px 14px rgba(0, 0, 0, .4);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--text-primary);
    font-size: 18px;
    pointer-events: none;
}

#ptr-indicator .ptr-icon {
    display: inline-block;
}

#ptr-indicator.ptr-ready .ptr-icon {
    color: var(--accent);
}

#ptr-indicator.ptr-loading .ptr-icon {
    animation: ptr-spin .8s linear infinite;
    color: var(--accent);
}

@keyframes ptr-spin {
    to {
        transform: rotate(360deg);
    }
}

/* ── Auth pages (sign-in, forgot password…) ──
   App-like: the page itself never scrolls (html is overflow:hidden). The body
   is fixed to the screen and scrolls only when its content really overflows
   (e.g. sign-up on a small phone), without bounce. The card is centred with
   margin:auto, not align-items:center, which would cut off tall content. */
html:has(body.auth-page) {
    height: 100%;
    overflow: hidden;
    overscroll-behavior: none;
}

body.auth-page {
    position: fixed;
    inset: 0;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: none;
    -webkit-overflow-scrolling: touch;
    display: flex;
    flex-direction: column;
    align-items: center;
    /* Not justify-content:center: content taller than the screen would lose its top, out of reach. */
    justify-content: flex-start;
    padding: calc(env(safe-area-inset-top, 0px) + 16px) env(safe-area-inset-right, 0px)
        calc(env(safe-area-inset-bottom, 0px) + 16px) env(safe-area-inset-left, 0px);
    touch-action: manipulation;
}

body.auth-page .auth-card {
    width: min(400px, calc(100% - 40px));
    margin: auto;
    flex-shrink: 0;
}

.auth-logo-img {
    display: block;
    width: 132px;
    height: auto;
    margin: 0 auto;
}

/* iOS zooms on any field whose text is under 16px. */
body.auth-page .auth-input {
    font-size: 16px;
}

/* Initial loading indicator for a view other than Home (see templates/index.html,
   #leagues_pan, initial_view). Replaced by the view content as soon as it arrives. */
.view-loading {
    display: flex;
    justify-content: center;
    padding: 60px 0;
}

.view-loading-spinner {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    border: 3px solid var(--border);
    border-top-color: var(--accent);
    animation: ptr-spin .8s linear infinite;
}

/* "Add to home screen" banner (static/js/install-banner.js). */
.install-banner {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 14px;
    margin-bottom: 18px;
    background: var(--bg-card);
    border: 1px solid var(--accent);
    border-radius: 12px;
}

.install-banner-icon {
    width: 44px;
    height: 44px;
    border-radius: 10px;
    flex-shrink: 0;
}

.install-banner-text {
    flex: 1;
    min-width: 0;
    font-size: 13px;
    line-height: 1.45;
    color: var(--text-secondary);
}

.install-banner-title {
    font-weight: 700;
    color: var(--text-primary);
    margin-bottom: 2px;
}

.install-banner-share {
    vertical-align: -3px;
    color: var(--accent-light);
}

.install-banner-btn {
    margin-top: 6px;
    padding: 6px 14px;
    font-size: 13px;
}

/* Push notifications offer on Home (static/js/app/push.js: _maybeShowPushBanner), same frame as the
   install banner. */
.push-banner-icon {
    width: 44px;
    height: 44px;
    border-radius: 10px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--accent-light);
    background: rgba(232, 97, 26, .12);
}
.push-banner-actions { display: flex; gap: 8px; flex-wrap: wrap; }

.install-banner-close {
    align-self: flex-start;
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 16px;
    cursor: pointer;
    padding: 2px 4px;
}

/* ── Header ─────────────────────────────────── */
/* App header pinned at the top on every screen, desktop and mobile, so it stays while
   any section scrolls. position:fixed, not sticky: the iOS bounce at the end of the page
   moves sticky elements off screen. The content is offset by --app-top (header + any
   admin/preview banner, static/js/app/layout.js: _syncHeaderHeightVar). z-index 150 is
   above the content and below the drawers (199/200) and modals. See docs/styles.md#mobile-header. */
#header {
    background: linear-gradient(135deg, #0d1225 0%, #1a2550 60%, #0d1225 100%);
    border-bottom: 2px solid var(--accent);
    /* iPhone home-screen mode (translucent status bar): keeps the header below the clock. 0 elsewhere. */
    padding-top: env(safe-area-inset-top, 0px);
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 150;
}

body {
    padding-top: var(--app-top, 68px);
}

/* "Admin mode" and preview banners: fixed below the header. */
#admin-mode-banner,
#view-as-banner {
    position: fixed !important;
    top: var(--header-h, 0px) !important;
    left: 0;
    right: 0;
    z-index: 140 !important;
}

/* Auto-scroll to an element: not hidden under the header. */
html {
    scroll-padding-top: calc(var(--app-top, 68px) + 8px);
}

.header-inner {
    display: flex;
    align-items: center;
    padding: 10px 24px;
    gap: 14px;
}

.header-logo {
    font-size: 44px;
    line-height: 1;
    display: inline-flex;
    align-items: center;
}

/* Cropped logo (img/logo-bz-crop.png, transparent margins removed), so it
   shows at the same visible size without empty space. */
.header-logo img {
    height: 56px;
    width: auto;
    border-radius: 8px;
    display: block;
}

.header-title {
    color: #fff;
    font-size: 34px;
    font-weight: 700;
    letter-spacing: -0.3px;
}

/* Text logo "BadZone": "Bad" in the base colour, "Zone" in the orange accent.
   Rajdhani (loaded from Google Fonts in the <head> of each template that uses it)
   sets it apart from the app's Segoe UI/system-ui text. */
.badzone-wordmark {
    font-family: 'Rajdhani', 'Segoe UI', system-ui, -apple-system, sans-serif;
    font-weight: 700;
}

.badzone-wordmark-accent {
    color: var(--accent-light);
}

/* Short line + dot under the wordmark. Only where the logo stands alone (sign-in page), not in the compact app header. */
.badzone-wordmark-accent-line {
    display: block;
    margin: 6px auto 0;
}

.header-subtitle {
    color: var(--text-muted);
    font-size: 11px;
    margin-top: 2px;
}

/* ── App layout ─────────────────────────────── */
.app-layout {
    display: flex;
    /* Viewport minus the REAL header height (--app-top, kept up to date by
       _syncHeaderHeightVar). A hard-coded 68px (the header is ~92px) made
       near-empty pages like Help & support scroll for no reason. */
    min-height: calc(100vh - var(--app-top, 68px));
}

/* ── Sidebar ────────────────────────────────── */
.sidebar {
    width: 230px;
    flex-shrink: 0;
    background: #182240;
    border-right: 1px solid var(--border);
    padding: 16px 0;
    display: flex;
    flex-direction: column;
    position: sticky;
    top: var(--app-top, 68px);
    align-self: flex-start;
    height: calc(100vh - var(--app-top, 68px));
    overflow-y: auto;
}

.sidebar-resize-handle {
    width: 5px;
    flex-shrink: 0;
    cursor: col-resize;
    position: sticky;
    top: var(--app-top, 68px);
    align-self: flex-start;
    /* Same height as the sidebar, using the real header height (--app-top). */
    height: calc(100vh - var(--app-top, 68px));
    background: transparent;
    transition: background 0.12s;
}

.sidebar-resize-handle:hover,
.sidebar-resize-handle.dragging {
    background: var(--accent);
}

.sidebar-section {
    color: var(--text-muted);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 1.5px;
    text-transform: uppercase;
    padding: 6px 18px 10px;
}

/* A nav tab whose per-league module is not in the plan: greyed/disabled, but still clickable so a
   tap explains why (navigation.js: lockModule / _moduleGuard). */
.nav-locked {
    opacity: .4;
    filter: grayscale(1);
}
.nav-locked:hover {
    background: transparent !important;
}

.league-item {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 13px 16px;
    margin: 2px 10px;
    border-radius: 8px;
    cursor: pointer;
    color: var(--text-secondary);
    font-weight: 500;
    font-size: 15px;
    transition: background 0.12s, color 0.12s;
}

.league-item .svg-icon {
    width: 19px;
    height: 19px;
}

.league-item:hover {
    background: var(--bg-card);
    color: var(--text-primary);
}

.league-item.active {
    background: var(--nav-active);
    color: #fff;
    font-weight: 700;
}

.league-icon {
    font-size: 17px;
}

.svg-icon {
    display: inline-block;
    vertical-align: -2px;
}

.sidebar-footer {
    margin-top: auto;
    padding-top: 10px;
    border-top: 1px solid var(--border);
    /* Always visible (My account… Sign out), even when the menu scrolls internally.
       Other entries pass under it, so the background matches the menu. */
    position: sticky;
    bottom: -16px;
    padding-bottom: 16px;
    background: #182240;
}

.sidebar-logout {
    text-decoration: none;
    color: #f87171;
}

.sidebar-logout:hover {
    background: rgba(248, 113, 113, 0.1);
    color: #f87171;
    border-left-color: #f87171;
}

/* Account menu in the header (avatar + dropdown): My account, Info, Help & support,
   sign-out. The one place for them on desktop as on mobile; the left menu no longer
   repeats them, except sign-out, kept at its bottom. */
#header-account-btn {
    display: flex;
}

.sidebar-profile,
.sidebar-footer #nav-account,
.sidebar-footer #nav-info,
.sidebar-footer #nav-help,
.sidebar-footer #nav-tour {
    display: none !important;
}

/* Administration: in the header account menu on desktop; the left menu copy stays in the
   page (panels mark it active) but hidden. On mobile it is the Admin drawer instead. */
.sidebar-admin,
#nav-tab-config,
#nav-tab-notes {
    display: none !important;
}

/* Collapsible menu sections (Administration, Outils): the header is a button with a chevron and,
   while folded, the sum of its entries' badges (navigation.js: _toggleMenuGroup). */
.header-menu-toggle {
    display: flex;
    align-items: center;
    gap: 6px;
    width: 100%;
    background: none;
    border: none;
    border-bottom: 1px solid var(--border);
    text-align: left;
    font-family: inherit;
    cursor: pointer;
    transition: color 0.12s ease, background 0.12s ease;
}
.header-menu-toggle:hover { color: var(--text-secondary); background: var(--bg-secondary); }
.header-menu-chevron { transition: transform 0.15s ease; flex: none; }
.header-menu-toggle[aria-expanded="true"] .header-menu-chevron { transform: rotate(90deg); }
.header-menu-group-badge { margin-left: auto; }
.header-menu-group[hidden] { display: none; }
.header-menu-section.header-menu-toggle { padding: 11px 16px; }

.header-menu-section {
    padding: 10px 16px 4px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.7px;
    text-transform: uppercase;
    color: var(--text-muted);
    border-bottom: 1px solid var(--border);
}


/* Account menu entries (header): My account, Info, Help & support. */
.header-menu-item {
    display: block;
    width: 100%;
    text-align: left;
    padding: 11px 16px;
    font-size: 13px;
    color: var(--text-primary);
    background: none;
    border: none;
    border-bottom: 1px solid var(--border);
    cursor: pointer;
    font-family: inherit;
    transition: background .12s;
}

/* Mobile-only entries of the account menu (Access, Attendance): on desktop they are in the left menu. */
#header-user-menu .header-menu-mobile-only {
    display: none;
}

/* Pending join requests, on the account button (the badge also sits on "Accès" inside). */
#header-account-btn {
    position: relative;
}

.header-manage-badge {
    position: absolute;
    top: 0;
    right: 0;
    margin: 0;
}
/* Pending player-link claims: top-left (over the avatar), away from the manager badge (top-right). */
.header-claims-badge {
    position: absolute;
    top: -3px;
    left: -3px;
    margin: 0;
}

.header-menu-item:hover {
    background: var(--bg-secondary);
}

.home-managed-tag {
    display: inline-block;
    margin-left: 8px;
    padding: 2px 8px;
    border: 1px solid var(--border);
    border-radius: 999px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .4px;
    vertical-align: 3px;
    color: var(--text-secondary);
}

a.header-menu-item {
    box-sizing: border-box;
    text-decoration: none;
}

.header-menu-item .svg-icon {
    vertical-align: -2px;
    margin-right: 6px;
}

.header-user-avatar {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
}

.header-user-icon {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

.account-avatar-lg {
    width: 72px;
    height: 72px;
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
}

.account-avatar-placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    font-size: 30px;
}

/* Profile picture cropper (static/js/app/account.js: _showAvatarCropper). */
.avatar-crop-overlay {
    position: fixed;
    inset: 0;
    z-index: 10000;
    background: rgba(0, 0, 0, .75);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
}

.avatar-crop-box {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 16px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    max-width: 100%;
}

.avatar-crop-title {
    font-weight: 700;
    color: var(--text-primary);
}

.avatar-crop-stage {
    position: relative;
    overflow: hidden;
    touch-action: none;
    cursor: grab;
    background: #000;
    border-radius: 8px;
    -webkit-user-select: none;
    user-select: none;
}

.avatar-crop-img {
    position: absolute;
    top: 0;
    left: 0;
    max-width: none;
    transform-origin: 0 0;
    pointer-events: none;
}

/* Avatar circle; the area outside it is darkened. */
.avatar-crop-ring {
    position: absolute;
    inset: 0;
    border-radius: 50%;
    box-shadow: 0 0 0 999px rgba(0, 0, 0, .55);
    border: 2px solid rgba(255, 255, 255, .85);
    pointer-events: none;
    z-index: 1;
}

.avatar-crop-hint {
    font-size: 12px;
    color: var(--text-secondary);
    text-align: center;
    max-width: 300px;
}

.avatar-crop-zoom {
    width: 100%;
    max-width: 300px;
}

.avatar-crop-actions {
    display: flex;
    gap: 10px;
    justify-content: flex-end;
    width: 100%;
}

/* ── User profile (top of the sidebar) ──────────────── */
.sidebar-profile {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0 10px 16px;
    padding: 8px;
    border-radius: 10px;
    cursor: pointer;
    transition: background 0.12s;
}

.sidebar-profile:hover {
    background: var(--bg-card);
}

.sidebar-profile-name {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ── League switcher (dropdown) ──────────────── */
.league-switcher {
    margin: 0 10px 14px;
}

.league-switcher-btn {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--bg-card);
    color: var(--text-primary);
    font-weight: 700;
    font-size: 14px;
    cursor: pointer;
    transition: border-color 0.12s;
}

.league-switcher-btn:hover {
    border-color: var(--accent);
}

.league-switcher.open .league-switcher-btn {
    border-color: var(--accent);
}

.league-switcher-label {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.league-switcher-chevron {
    flex-shrink: 0;
    font-size: 11px;
    color: var(--text-muted);
    transition: transform 0.15s;
}

.league-switcher.open .league-switcher-chevron {
    transform: rotate(180deg);
}

.league-switcher-panel {
    margin-top: 6px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--bg-card);
    overflow: hidden;
}

.league-switcher-panel .league-item {
    padding: 10px 14px 10px 10px;
    margin: 0;
    border-radius: 0;
}

/* Dropdown: the check mark (.league-switcher-check) already shows the selected
   league, so a plain tint is enough here, not the solid pill of the sidebar nav items. */
.league-switcher-panel .league-item:hover,
.league-switcher-panel .league-item.active {
    background: var(--bg-hover);
    color: var(--text-primary);
    font-weight: 500;
}

/* League marked "In preparation" (api/leagues.py: league_prep_set). */
.league-prep-tag {
    flex: 0 0 auto;
    font-size: 12px;
}

.league-switcher-check {
    display: inline-block;
    width: 14px;
    flex-shrink: 0;
    color: var(--accent-light);
    font-weight: 700;
    visibility: hidden;
}

.league-switcher-panel .league-item.active .league-switcher-check {
    visibility: visible;
}

.league-switcher-add {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 14px;
    cursor: pointer;
    color: var(--accent-light);
    font-weight: 600;
    font-size: 13px;
    border-top: 1px solid var(--border);
    transition: background 0.12s;
}

.league-switcher-add:hover {
    background: rgba(232, 97, 26, 0.1);
}

/* ── Main content ───────────────────────────── */
.main-content {
    flex: 1;
    /* --mc-pad-y mirrors the top padding below, reused by #league-bar's negative margin so the bar
       rests flush at the top (no travel before it pins). */
    --mc-pad-y: 22px;
    padding: var(--mc-pad-y) 24px;
    /* visible, not auto/clip: the body is the scroll container (app-layout is min-height, header
       fixed), so main-content never scrolls on its own. It must NOT be a scroll container, or the
       sticky #league-bar would pin relative to it instead of the viewport — Safari iOS treats clip as
       a scroll container (Chrome does not), which double-offset the bar. visible is a scroll container
       on no engine. min-width:0 lets wide tables (which carry their own overflow-x) shrink. */
    overflow: visible;
    min-width: 0;
}

.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 300px;
    gap: 12px;
    color: var(--text-muted);
}

.empty-icon {
    font-size: 44px;
    opacity: 0.35;
}

.empty-text {
    font-size: 14px;
}

/* ── League header ──────────────────────────── */
.league-header {
    margin-bottom: 16px;
}

.league-name {
    font-size: 19px;
    font-weight: 700;
    color: var(--text-primary);
}

/* League picker at the top of the league pages; the side-menu switcher and the mobile
   "League" button are gone (the picker is the one place to change league). */
#league-switcher,
#mob-btn-league {
    display: none !important;
}

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

/* #league-bar prefix: higher specificity than .modal-input (same classes on the select), so the
   bigger league-name font actually applies instead of .modal-input's 14px. */
#league-bar .league-header-select {
    width: auto;
    max-width: 300px;
    font-size: 19px;
    font-weight: 700;
    padding: 6px 10px;
}

.league-info-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 6px;
    border: none;
    border-radius: 8px;
    background: none;
    color: var(--text-secondary);
    cursor: pointer;
    transition: background-color 120ms ease, color 120ms ease;
}

.league-info-btn:hover {
    background: var(--bg-hover);
    color: var(--text-primary);
}

/* Global league bar (index.html: #league-bar): the single league selector, above the content,
   shown in every league context. The <select> reuses .league-header-select above. */
#league-bar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    min-width: 0;
    /* Sticky below the fixed header (same anchor as the side menu: top:var(--app-top)), so the league
       selector stays reachable while scrolling. The negative top margin cancels .main-content's top
       padding so the bar RESTS exactly at its sticky position — it does not travel before pinning.
       Opaque background covers the content beneath it. */
    position: sticky;
    top: var(--app-top, 68px);
    z-index: 20;
    background: var(--bg-primary);
    margin-top: calc(-1 * var(--mc-pad-y, 22px));
    padding: 10px 0;
    margin-bottom: 8px;
    border-bottom: 1px solid var(--border);
}
.league-bar-icon {
    font-size: 14px;
    line-height: 1;
    color: var(--text-muted);
}
#league-bar .league-bar-role {
    margin-left: 2px;
}
/* Thin divider between the league group and the session group. */
.league-bar-sep {
    width: 1px;
    align-self: stretch;
    margin: 3px 2px;
    background: var(--border);
}
#league-bar #sidebar-session-wrap select {
    max-width: 200px;
}

.league-role-badge {
    display: inline-block;
    margin-left: 10px;
    padding: 3px 10px;
    border-radius: 20px;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    font-size: 11px;
    font-weight: 600;
    color: var(--text-secondary);
    vertical-align: middle;
}

/* ── Stats layout (content + date sidebar) ──── */
.stats-layout {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.stats-content {
    width: 100%;
}

/* Matches tab: two views of every evening (static/js/func.js: showMatchesView). */
.matches-view-tabs {
    margin-bottom: 12px;
}

#leagues.view-standings .matches-layout > .matches-card,
#leagues.view-standings [id^="date-attendance-wrap-"],
#leagues.view-matches .matches-layout > .matches-col-left {
    display: none !important;
}

/* An evening with no ranking yet (to come, schedule not made): say so in Standings. */
.standings-empty {
    display: none;
    padding: 24px 12px;
    text-align: center;
    font-style: italic;
    font-size: 13px;
    color: var(--text-muted);
}

#leagues.view-standings .stat:not(:has(.matches-col-left)):not(:has(.empty-state)) .standings-empty {
    display: block;
}

/* ── Date bar (horizontal) ──────────────────── */
.date-sidebar {
    display: flex;
    flex-direction: row;
    gap: 0;
    overflow-x: auto;
    overflow-y: hidden;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 10px;
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
}

.date-sidebar::-webkit-scrollbar {
    height: 4px;
}

/* Touch screens: a sideways swipe on the dates changes the evening (func.js:
   _bindDateBarSwipe), so the bar does not scroll under the finger. */
@media (pointer: coarse) {
    .date-sidebar {
        touch-action: pan-y;
    }
}

.date-sidebar::-webkit-scrollbar-track {
    background: transparent;
}

.date-sidebar::-webkit-scrollbar-thumb {
    background: var(--border);
    border-radius: 2px;
}

.date-sidebar-header {
    padding: 0 12px;
    font-size: 9px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 1px;
    color: var(--text-muted);
    border-right: 1px solid var(--border);
    display: flex;
    align-items: center;
    white-space: nowrap;
    flex-shrink: 0;
}

.date-item {
    padding: 8px 12px;
    font-size: 11px;
    font-weight: 500;
    color: var(--text-secondary);
    cursor: pointer;
    border-bottom: 2px solid transparent;
    border-left: none;
    transition: background 0.1s, color 0.1s, border-color 0.1s;
    text-align: center;
    line-height: 1.3;
    white-space: nowrap;
    flex-shrink: 0;
}

.date-item:hover {
    background: var(--bg-hover);
    color: var(--text-primary);
}

.date-item.no-data {
    opacity: 0.4;
}

.date-item.active {
    color: var(--accent-light);
    border-bottom-color: var(--accent-light);
    border-left-color: transparent;
    background: rgba(249, 115, 22, 0.08);
    font-weight: 700;
}

.date-item.cancelled {
    color: var(--red);
    opacity: 1;
    text-decoration: line-through;
}

.date-item.cancelled .date-item-year {
    color: var(--red);
    opacity: 0.7;
}

.date-item-day {
    display: block;
    font-size: 15px;
    font-weight: 700;
    line-height: 1.2;
}

.date-item-month {
    display: block;
    font-size: 10px;
    text-transform: uppercase;
}

.date-item-year {
    display: block;
    font-size: 9px;
    color: var(--text-muted);
}

/* ── Slide ──────────────────────────────────── */
.stat {
    display: none;
}

.fade {
    animation: fadeIn 0.25s ease;
}

@keyframes fadeIn {
    from {
        opacity: 0;
        transform: translateY(5px);
    }

    to {
        opacity: 1;
        transform: translateY(0);
    }
}

/* ── Two-column grid ────────────────────────── */
.content-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 14px;
    margin-bottom: 14px;
}

/* ── Card ───────────────────────────────────── */
.card {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 10px;
    overflow: hidden;
}

.card-header {
    padding: 10px 14px;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 1px;
    border-bottom: 1px solid var(--border);
}

.card-header.blue {
    background: linear-gradient(90deg, rgba(30, 58, 95, .7), transparent);
    color: #60a5fa;
}

.card-header.orange {
    background: linear-gradient(90deg, rgba(124, 45, 18, .7), transparent);
    color: var(--accent-light);
}

.card-header.purple {
    background: linear-gradient(90deg, rgba(76, 29, 149, .7), transparent);
    color: #a78bfa;
}

/* Collapsible cards (overall standings, evening standings…). The chevron rotates
   in pure CSS; content is hidden by the class set in _toggleCardCollapse (static/js/app/layout.js). */
.card-header[data-collapsible] {
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: space-between;
    user-select: none;
}

.card-header[data-collapsible] .collapse-chevron {
    transition: transform .15s ease;
    font-size: 9px;
    opacity: .7;
}

.card-collapsed .collapse-chevron {
    transform: rotate(-90deg);
}

.card-collapsed>*:not(.card-header) {
    display: none !important;
}

/* ── Leaderboard table ──────────────────────── */
.leaderboard {
    width: 100%;
    border-collapse: collapse;
}

.leaderboard thead th {
    padding: 7px 12px;
    color: var(--text-muted);
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.4px;
    text-align: right;
    border-bottom: 1px solid var(--border);
}

.leaderboard thead th:nth-child(2) {
    text-align: left;
}

.leaderboard tbody tr:hover td {
    background: var(--bg-hover);
}

.leaderboard tbody td {
    padding: 8px 12px;
    border-bottom: 1px solid rgba(45, 53, 97, .4);
    text-align: right;
    vertical-align: middle;
    white-space: nowrap;
}

.rank-cell {
    display: flex;
    align-items: center;
    gap: 4px;
}

.rank-num-cell {
    text-align: right;
    padding-right: 2px !important;
    white-space: nowrap;
}

.rank-badge-cell {
    padding-left: 0 !important;
    padding-right: 4px !important;
    white-space: nowrap;
}

.rank-num {
    font-weight: 700;
    font-size: 13px;
    width: 18px;
    text-align: right;
    color: var(--text-secondary);
}

.rank-num.gold {}

.rank-num.silver {}

.rank-num.bronze {}

.rank-badge {
    font-size: 9px;
    width: 28px;
    text-align: left;
    color: var(--text-muted);
}

.rank-badge.up {
    color: var(--green);
}

.rank-badge.down {
    color: var(--red);
}

.player-name-cell {
    text-align: left !important;
    font-weight: 600;
    color: var(--text-primary);
    padding-left: 6px !important;
}

.pts-val {
    font-weight: 700;
    color: var(--accent-light);
}

.wl-val {
    color: var(--text-secondary);
}

.delta-val {
    font-weight: 600;
}

.delta-val.pos {
    color: var(--green);
}

.delta-val.neg {
    color: var(--red);
}

.delta-val.zero {
    color: var(--text-muted);
}

/* ── Match cards grid ───────────────────────── */
.matches-grid {
    padding: 12px;
    display: grid;
    /* Always 2 columns on desktop, each with a minimum width so names never get cut.
       If the box is too narrow for two, it scrolls (overflow:auto on .matches-card)
       instead of stacking. One column only below 768px. */
    grid-template-columns: repeat(2, minmax(210px, 1fr));
    gap: 8px;
}

.matches-card>.matches-grid .match-players {
    white-space: nowrap;
}

/* Matches of a finalised evening, inside a "Wave X" group. Columns are 210px
   each, so cards keep their size and extra space stays empty. An explicit
   width:100% is needed, otherwise the grid sizes to its content. See
   docs/styles.md#match-card-grid for the sizing details. */
.wave-matches-grid {
    width: 100%;
    grid-template-columns: repeat(auto-fill, minmax(min(210px, 100%), 210px));
}

/* Correction mode (JS, see startCorrectMode in static/js/app/results.js): one column per court
   actually used that evening, in the same wave order as the original schedule. */
.matches-grid.court-columns {
    display: flex;
    gap: 8px;
    align-items: flex-start;
}

.matches-grid.court-columns>.court-column {
    display: flex;
    flex-direction: column;
    gap: 8px;
    flex: 1;
    min-width: 190px;
}

/* Rencontres tab: a resizable box (native handle, bottom-right) that also grows
   with the window (flex-grow:1). min-width is one card, since the grid stacks to a
   single column when short of room. max-width is --card-max-w (set inline by
   templates/leagues.html), so growth stops once the evening's courts fit.
   Full width on mobile. See docs/styles.md#matches-box. */
/* Rencontres tab (desktop): standings (overall, evening, per team in matchup mode)
   side by side in one row, with the Rencontres / evening schedule card below.
   Stacks on mobile (see "Rencontres tab: stack everything" below). */
.matches-layout {
    display: flex;
    flex-direction: column;
    gap: 10px;
    align-items: flex-start;
}

.matches-col-left {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    align-items: flex-start;
    width: 100%;
}

.matches-col-left>.card {
    flex: 0 1 360px;
    min-width: 0;
}

/* The parent is a column, so the card width is set with width (a flex-basis
   would become a height): full width, capped by max-width. */
.matches-card {
    flex: none;
    width: 100%;
    max-width: var(--card-max-w, 100%);
    min-width: 250px;
    resize: horizontal;
    overflow: auto;
}

/* Evening schedule (preview/draft): same 2-column grid as .matches-grid;
   a wider box would only leave empty space on the right. */
.draft-schedule-card {
    min-width: 480px;
    max-width: 560px;
}

/* "WAVE A/B/C..." label above the matches played at the same time in that wave
   (finalised Rencontres view). Rebuilt by slicing `matches` into chunks of n_courts
   (see app.py), because the matches table does not keep the round's label. Letters
   follow the default round label of a template (se-round-label in static/js/app/). */
.match-wave-label {
    font-family: ui-monospace, 'SF Mono', 'Cascadia Code', Menlo, Consolas, monospace;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 1.5px;
    color: #a78bfa;
    padding: 10px 12px 4px;
}

.match-card {
    background:
        repeating-linear-gradient(0deg, rgba(255, 255, 255, .015) 0px, rgba(255, 255, 255, .015) 1px, transparent 1px, transparent 18px),
        repeating-linear-gradient(90deg, rgba(255, 255, 255, .015) 0px, rgba(255, 255, 255, .015) 1px, transparent 1px, transparent 18px),
        var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 10px;
    overflow: hidden;
}

.match-team {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 9px 12px;
    gap: 8px;
}

.match-team.winner {
    background: rgba(34, 197, 94, .07);
}

.match-team.loser {
    opacity: 1;
}

.match-players {
    font-size: 12px;
    font-weight: 700;
    line-height: 1.55;
    letter-spacing: .1px;
    color: var(--text-primary);
    flex: 1;
}

.match-team.loser .match-players {
    color: var(--text-secondary);
}

.match-score {
    font-family: ui-monospace, 'SF Mono', 'Cascadia Code', Menlo, Consolas, monospace;
    font-size: 17px;
    font-weight: 800;
    min-width: 26px;
    text-align: right;
}

.match-team.winner .match-score {
    color: var(--green);
}

.match-team.loser .match-score {
    color: var(--text-muted);
}

.match-divider {
    height: 1px;
    background: var(--border);
}

/* Per-player results analysis (static/js/app/results.js: toggleResultsAnalysis). */
.ra-btn {
    padding: 5px 9px;
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: 12px;
    font-weight: 700;
}

.matches-card.ra-active .ra-btn {
    background: rgba(255, 255, 255, .18);
}

.ra-bar {
    padding: 10px 12px 2px;
}

.ra-pick {
    display: flex;
    gap: 8px;
    align-items: center;
}

.ra-select {
    flex: 1;
    min-width: 0;
    font: inherit;
    font-size: 16px;
    padding: 8px 10px;
    border-radius: 8px;
    border: 1px solid var(--border);
    background: var(--bg-secondary);
    color: var(--text-primary);
}

.ra-close {
    padding: 8px 12px;
}

.ra-summary {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 14px;
    align-items: center;
    padding: 10px 2px 4px;
    font-size: 13px;
    color: var(--text-secondary);
}

.ra-summary b {
    color: var(--text-primary);
}

.ra-total {
    margin-left: auto;
    font-family: ui-monospace, 'SF Mono', 'Cascadia Code', Menlo, Consolas, monospace;
    font-size: 17px;
    font-weight: 800;
}

/* Win/loss of the match, to the right of the scores, vertically centred on the card. */
.match-card.ra-mine {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 58px;
}

.match-card.ra-mine>.match-team,
.match-card.ra-mine>.match-divider {
    grid-column: 1;
}

.ra-diff {
    grid-column: 2;
    grid-row: 1 / span 3;
    display: flex;
    align-items: center;
    justify-content: center;
    border-left: 1px solid var(--border);
}

.ra-diff b {
    font-family: ui-monospace, 'SF Mono', 'Cascadia Code', Menlo, Consolas, monospace;
    font-size: 15px;
    font-weight: 800;
}

.ra-me {
    color: #fbbf24;
}

/* Analysis mode: wave titles hidden, the player's matches in a single grid.
   Cards are wider (260px) so names stay on one line next to the win/loss column. */
.ra-grid {
    display: grid;
    padding: 12px;
    gap: 8px;
    grid-template-columns: repeat(auto-fill, minmax(min(260px, 100%), 260px));
}

.ra-grid>.match-wave-label,
.ra-grid>.wave-toggle.match-wave-label {
    display: none;
}

.ra-grid>.wave-matches-grid {
    display: contents;
}

.ra-diff.pos, .ra-total.pos { color: var(--green); }
.ra-diff.neg, .ra-total.neg { color: var(--red); }
.ra-diff.zero, .ra-total.zero { color: var(--text-muted); }
.ra-diff.pos { background: rgba(34, 197, 94, .08); }
.ra-diff.neg { background: rgba(239, 68, 68, .08); }

.draft-standings-card .leaderboard thead th {
    padding: 6px 6px;
}

.draft-standings-card .leaderboard tbody td {
    padding: 6px 6px;
}

.draft-standings-card .player-name-cell {
    white-space: nowrap;
}

.draft-preview .match-card {
    border-radius: 6px;
}

.draft-preview .match-team {
    padding: 4px 8px;
    gap: 6px;
    align-items: flex-start;
}

/* min-height = 2 lines of names, so score fields line up across cards whether a name wraps or not. */
.draft-preview .match-players {
    font-size: 10px;
    line-height: 1.35;
    padding-top: 2px;
    min-height: 27px;
}

.draft-preview .matches-grid {
    grid-template-columns: repeat(3, 1fr);
    gap: 5px;
}

.draft-preview .draft-score-input {
    font-size: 13px;
    width: 28px;
}

.draft-score-col {
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex-shrink: 0;
}

.draft-score-inputs {
    display: flex;
    gap: 8px;
}

.att-player {
    display: inline;
    white-space: nowrap;
}

.att-dot {
    font-size: 7px;
    vertical-align: middle;
    margin-right: 3px;
    color: #2e7d32;
    line-height: 1;
}

.att-dot.att-absent {
    color: #c62828;
}

.att-dot.att-pending {
    color: #555;
}

.att-player.att-absent {
    color: var(--text-muted);
    text-decoration: line-through;
}

.match-pos {
    font-size: 9px;
    color: var(--text-muted);
    margin-right: 3px;
    vertical-align: middle;
}

/* Same font and size as finalised scores (.match-score, and 26px on mobile below),
   so the input does not look smaller. */
.draft-score-input {
    width: 36px;
    text-align: right;
    background: transparent;
    border: none;
    color: var(--text-primary);
    font-family: ui-monospace, 'SF Mono', 'Cascadia Code', Menlo, Consolas, monospace;
    font-size: 17px;
    font-weight: 800;
    /* Inputs do not inherit line-height; without this, rows shift in correction mode. */
    line-height: inherit;
    padding: 0;
    outline: none;
    flex-shrink: 0;
    -moz-appearance: textfield;
}

.draft-score-input:focus {
    outline: none;
}

.draft-score-input[readonly] {
    cursor: default;
    opacity: .65;
}

.draft-score-input::placeholder {
    color: var(--text-muted);
    font-weight: 400;
    font-size: 13px;
}

.draft-score-input::-webkit-outer-spin-button,
.draft-score-input::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

/* ── Scoreboard (grouped matches) ───────────── */
.match-scoreboard {
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 8px;
    overflow: hidden;
}

.match-sb-row {
    display: flex;
    align-items: center;
    padding: 9px 12px;
    gap: 10px;
}

.match-sb-row+.match-sb-row {
    border-top: 1px solid var(--border);
}

.match-sb-players {
    flex: 1;
    font-size: 12px;
    font-weight: 700;
    color: var(--text-primary);
    line-height: 1.45;
}

.match-sb-scores {
    display: flex;
    gap: 10px;
    align-items: center;
}

.match-sb-score {
    font-size: 13px;
    font-weight: 400;
    color: var(--text-muted);
    min-width: 20px;
    text-align: center;
}

.match-sb-score.win {
    font-weight: 800;
    color: var(--text-primary);
}


/* ── Players grid ───────────────────────────── */
.players-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(175px, 1fr));
    gap: 12px;
    margin-bottom: 24px;
}

.player-card {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 18px 14px 14px;
    text-align: center;
    transition: background 0.12s, border-color 0.12s;
    position: relative;
}

.player-card:hover {
    background: var(--bg-hover);
}

.player-card.inactive {
    opacity: .55;
}

.btn-add-player {
    margin-top: 8px;
    width: 100%;
    padding: 5px 0;
    border-radius: 6px;
    font-size: 11px;
    font-weight: 700;
    color: var(--accent-light);
    background: rgba(249, 115, 22, 0.08);
    border: 1px solid rgba(249, 115, 22, 0.25);
    cursor: pointer;
    transition: background 0.12s, border-color 0.12s;
}

.btn-add-player:hover {
    background: rgba(249, 115, 22, 0.18);
    border-color: var(--accent);
}

.btn-remove-player {
    position: absolute;
    top: 5px;
    right: 5px;
    width: 18px;
    height: 18px;
    padding: 0;
    border-radius: 50%;
    font-size: 10px;
    line-height: 1;
    font-weight: 700;
    color: var(--red);
    background: rgba(239, 68, 68, 0.12);
    border: 1px solid rgba(239, 68, 68, 0.3);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.12s, border-color 0.12s;
    opacity: 0;
}

.player-card:hover .btn-remove-player {
    opacity: 1;
}

.btn-remove-player:hover {
    background: rgba(239, 68, 68, 0.28);
    border-color: var(--red);
}

/* ── Permanent league roster (search / add) ──────────────── */
.roster-manager {
    margin-bottom: 20px;
    padding-bottom: 16px;
    border-bottom: 1px solid var(--border);
}

.roster-search-bar {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
    margin: 8px 0 10px;
}

.roster-search-bar .modal-input {
    flex: 1 1 200px;
    width: auto;
    min-width: 0;
}

.roster-search-bar .roster-new-btn {
    flex: 0 0 auto;
    white-space: nowrap;
}

.roster-search-results {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 8px;
    margin-bottom: 14px;
}

.roster-search-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 6px 4px;
    font-size: 13px;
}

.roster-search-row > span:first-child {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.roster-search-row .btn-add-player {
    width: auto;
    flex-shrink: 0;
    margin-top: 0;
    padding: 5px 12px;
}

.roster-search-row + .roster-search-row {
    border-top: 1px solid var(--border);
}

.roster-search-already {
    font-size: 11px;
    color: var(--text-muted);
    font-style: italic;
}

.roster-search-empty {
    font-size: 12px;
    color: var(--text-muted);
    font-style: italic;
    padding: 4px;
}

.roster-search-new-toggle {
    margin-top: 6px;
    padding: 6px 4px;
    font-size: 12px;
    color: var(--accent-light);
    cursor: pointer;
    border-top: 1px solid var(--border);
}

.roster-search-new-toggle:hover {
    text-decoration: underline;
}

.roster-new-player-form {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    margin-top: 8px;
}

.roster-new-player-form .modal-input {
    flex: 1 1 140px;
}

.player-avatar.has-photo {
    overflow: hidden;
    padding: 0;
}

.player-avatar.has-photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 50%;
    display: block;
}

.player-avatar {
    width: 52px;
    height: 52px;
    border-radius: 50%;
    background: var(--bg-secondary);
    border: 2px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0 auto 10px;
    font-size: 17px;
    font-weight: 700;
    color: var(--accent-light);
    letter-spacing: -1px;
}

.player-avatar.gold {
    border-color: var(--gold);
    color: var(--gold);
}

.player-avatar.silver {
    border-color: var(--silver);
    color: var(--silver);
}

.player-avatar.bronze {
    border-color: var(--bronze);
    color: var(--bronze);
}

.player-card-rank {
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 1px;
    color: var(--text-muted);
    margin-bottom: 2px;
}

.player-card-rank.gold {
    color: var(--gold);
}

.player-card-rank.silver {
    color: var(--silver);
}

.player-card-rank.bronze {
    color: var(--bronze);
}

.player-card-name {
    font-size: 13px;
    font-weight: 700;
    color: var(--text-primary);
    margin-bottom: 10px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.player-card-stats {
    display: flex;
    justify-content: center;
    gap: 10px;
    border-top: 1px solid var(--border);
    padding-top: 10px;
}

.pstat {
    text-align: center;
}

.pstat-val {
    font-size: 15px;
    font-weight: 700;
    color: var(--text-primary);
    line-height: 1;
}

.pstat-val.pts {
    color: var(--accent-light);
}

.pstat-val.pos {
    color: var(--green);
}

.pstat-val.neg {
    color: var(--red);
}

.pstat-label {
    font-size: 9px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--text-muted);
    margin-top: 2px;
}

.players-section-title {
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 1.2px;
    color: var(--text-muted);
    margin-bottom: 10px;
}

/* Boxes / list view toggle (Players tab). */
.view-toggle {
    display: flex;
    border: 1px solid var(--border);
    border-radius: 7px;
    overflow: hidden;
    flex-shrink: 0;
}

.view-toggle-btn {
    background: var(--bg-secondary);
    border: none;
    color: var(--text-muted);
    font-size: 13px;
    line-height: 1;
    padding: 5px 9px;
    cursor: pointer;
    transition: background .12s, color .12s;
}

.view-toggle-btn+.view-toggle-btn {
    border-left: 1px solid var(--border);
}

.view-toggle-btn:hover {
    color: var(--text-primary);
}

.view-toggle-btn.active {
    background: var(--accent);
    color: #fff;
}

/* List view: player cards as compact rows instead of a grid of boxes. */
.players-subpanel.list-view .players-grid {
    grid-template-columns: 1fr;
    gap: 4px;
}

.players-subpanel.list-view .player-card {
    display: flex;
    align-items: center;
    text-align: left;
    padding: 8px 12px;
    gap: 10px;
}

.players-subpanel.list-view .player-avatar {
    width: 30px;
    height: 30px;
    font-size: 11px;
    margin: 0;
    flex-shrink: 0;
}

.players-subpanel.list-view .player-card-name {
    margin-bottom: 0;
    flex: 1;
    text-align: left;
    white-space: normal;
}

.players-subpanel.list-view .btn-remove-player {
    position: static;
    opacity: 1;
    flex-shrink: 0;
}

.players-subpanel.list-view .btn-add-player {
    margin-top: 0;
    width: auto;
    padding: 4px 14px;
    flex-shrink: 0;
}

/* ── Tabs ───────────────────────────────────── */
/* ── Session bar ────────────────────────────── */
.session-bar {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 10px 0 12px;
    flex-wrap: wrap;
}

.session-pill {
    display: flex;
    align-items: center;
    gap: 5px;
    padding: 5px 12px;
    border-radius: 20px;
    font-size: 12px;
    font-weight: 600;
    color: var(--text-secondary);
    background: var(--bg-card);
    border: 1px solid var(--border);
    cursor: pointer;
    transition: all 0.15s;
}

.session-pill:hover {
    border-color: var(--accent);
    color: var(--text-primary);
}

.session-pill.active {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
}

.session-edit-btn {
    font-size: 13px;
    color: var(--text-muted);
    cursor: pointer;
    padding: 4px 6px;
    transition: color 0.15s;
}

.session-edit-btn:hover {
    color: var(--accent);
}

.session-add-btn {
    padding: 5px 10px;
    border-radius: 20px;
    font-size: 14px;
    font-weight: 700;
    color: var(--text-muted);
    background: transparent;
    border: 1px dashed var(--border);
    cursor: pointer;
    transition: all 0.15s;
}

.session-add-btn:hover {
    border-color: var(--accent);
    color: var(--accent);
}

/* ── Tab bar ─────────────────────────────────── */
.tab-bar {
    display: flex;
    gap: 2px;
    border-bottom: 1px solid var(--border);
    margin-bottom: 16px;
}

.tab {
    padding: 9px 18px;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-muted);
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    cursor: pointer;
    font-family: inherit;
    transition: color 0.12s, border-color 0.12s;
}

.tab:hover {
    color: var(--text-secondary);
}

.tab.active {
    color: var(--accent-light);
    border-bottom-color: var(--accent-light);
}

.tab-badge {
    display: inline-block;
    margin-left: 5px;
    background: #ef4444;
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    border-radius: 10px;
    padding: 1px 6px;
    line-height: 1.3;
    vertical-align: middle;
}

/* ── Planned attendance (future date without a schedule) ── */
.date-attendance-list {
    padding: 6px 14px 14px;
}

.date-attendance-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 8px 0;
    border-bottom: 1px solid var(--border);
}

.date-attendance-row:last-child {
    border-bottom: none;
}

.date-attendance-name {
    font-weight: 500;
    flex: 1;
}

.date-attendance-handle {
    cursor: grab;
    color: var(--text-muted);
    font-size: 14px;
    line-height: 1;
    flex-shrink: 0;
    user-select: none;
}

.date-attendance-row[draggable="true"]:active .date-attendance-handle {
    cursor: grabbing;
}

.date-attendance-row.dragging {
    opacity: 0.4;
}

.date-attendance-row.drag-over {
    border-top: 2px solid var(--accent);
}

.date-attendance-toggle {
    display: flex;
    gap: 6px;
    flex-shrink: 0;
}

.date-attendance-btn {
    border: 1px solid var(--border);
    background: var(--bg-card);
    color: var(--text-secondary);
    border-radius: 6px;
    padding: 4px 10px;
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
    width: 86px;
    text-align: center;
}

.date-attendance-btn:disabled {
    cursor: default;
    opacity: 0.5;
}

.date-attendance-btn.present.active {
    background: var(--green);
    border-color: var(--green);
    color: #fff;
}

.date-attendance-btn.absent.active {
    background: var(--red);
    border-color: var(--red);
    color: #fff;
}

/* Evening echo on the Home read-only cards (static/js/app/home-echo.js); label and
   waiting line reuse the quiz styles. */
.home-echo {
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid var(--border);
}

.home-echo-text {
    font-size: 15px;
    line-height: 1.5;
    color: var(--text-primary);
}

/* Daily quiz on the Home league cards (static/js/app/home-quiz.js). */
.home-quiz {
    margin-top: 16px;
    padding-top: 12px;
    border-top: 1px solid var(--border);
}

.home-quiz-label {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.7px;
    text-transform: uppercase;
    color: var(--text-secondary);
    margin-bottom: 8px;
}

.home-quiz-question {
    font-size: 15px;
    font-weight: 600;
    line-height: 1.45;
    color: var(--text-primary);
    margin-bottom: 12px;
}

.home-quiz-wait {
    font-size: 14px;
    font-style: italic;
    color: var(--text-secondary);
}

.home-quiz-choices {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
}

.home-quiz-choice {
    border: 1px solid var(--border);
    background: transparent;
    color: var(--text-primary);
    border-radius: 8px;
    padding: 10px 12px;
    font-size: 14px;
    font-weight: 600;
    text-align: left;
    cursor: pointer;
    transition: background-color 120ms ease, border-color 120ms ease;
}

.home-quiz-choice:hover:not(:disabled) {
    background: var(--bg-hover);
    border-color: var(--accent);
}

.home-quiz-choice:disabled {
    cursor: default;
    color: var(--text-secondary);
}

.home-quiz-choice.right {
    background: rgba(34, 197, 94, .14);
    border-color: var(--green);
    color: var(--text-primary);
}

.home-quiz-choice.wrong {
    background: rgba(239, 68, 68, .12);
    border-color: var(--red);
    color: var(--text-primary);
}

.home-quiz-reveal {
    margin-top: 12px;
    font-size: 14px;
    line-height: 1.5;
    color: var(--text-secondary);
}

.home-quiz-reveal.right::before { content: "✓ "; color: var(--green); font-weight: 700; }
.home-quiz-reveal.wrong::before { content: "✗ "; color: var(--red); font-weight: 700; }

.home-quiz-head {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 8px;
}

.home-quiz-head .home-quiz-label {
    margin-bottom: 0;
}

.home-quiz-hide {
    margin-left: auto;
    font-size: 12px;
    padding: 4px 12px;
}

.home-quiz-folded {
    display: flex;
    align-items: center;
    gap: 10px;
}

.home-quiz-folded .home-quiz-label {
    margin-bottom: 0;
}

.home-quiz-folded-result {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-secondary);
}

.home-quiz-folded-result.right { color: var(--green); }
.home-quiz-folded-result.wrong { color: var(--red); }

.home-quiz-reopen {
    margin-left: auto;
    font-size: 12px;
    padding: 4px 12px;
}

.home-quiz-streak {
    margin-top: 8px;
    font-size: 12px;
    color: var(--text-secondary);
}

.date-attendance-add-row {
    display: flex;
    gap: 8px;
    padding: 10px 14px;
    border-top: 1px solid var(--border);
}

.date-attendance-add-row select {
    flex: 1;
    min-width: 0;
    background: var(--bg-card);
    color: var(--text-primary);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 4px 8px;
    font-size: 13px;
}

.date-attendance-remove-btn {
    border: none;
    background: transparent;
    color: var(--text-muted);
    cursor: pointer;
    font-size: 13px;
    padding: 4px 4px;
    line-height: 1;
    transition: color 0.12s;
}

.date-attendance-remove-btn:hover {
    color: var(--red);
}

/* ── Chat (global menu, one channel per league/session) ── */
.chat-layout {
    display: flex;
    gap: 0;
    height: calc(100vh - 150px);
    min-height: 420px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 10px;
    overflow: hidden;
}

.chat-channel-list {
    width: 240px;
    flex-shrink: 0;
    overflow-y: auto;
    border-right: 1px solid var(--border);
    padding: 8px 0;
}

/* League list in the global chat (see _renderChatChannelList and
   _chatSelectedLeagueId): step 1 is the leagues, step 2 the sessions of the
   clicked league, so the whole list is never expanded at once. One row per
   league (one thread each), with the last message preview and time, Messenger-style. */
.chat-league-main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.chat-league-top,
.chat-league-bottom {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    min-width: 0;
}

.chat-league-row .chat-channel-name {
    color: var(--text-primary);
    font-weight: 600;
    font-size: 14px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.chat-league-time {
    flex-shrink: 0;
    font-size: 11px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.chat-league-preview {
    min-width: 0;
    padding-left: 12px;  /* Indented under the league name. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 12px;
    color: var(--text-muted);
}

/* Unread: league name in the accent colour, preview in bold. */
.chat-league-row.unread .chat-channel-name {
    color: var(--accent);
    font-weight: 700;
}

.chat-league-row.unread .chat-league-preview {
    color: var(--text-primary);
    font-weight: 600;
}

.chat-league-row.unread .chat-league-time {
    color: var(--accent-light, #748ffc);
    font-weight: 600;
}

/* Season marker in the league thread ("— Winter 2027 —"). */
.chat-session-divider {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--text-muted);
}

.chat-session-divider::before,
.chat-session-divider::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--border);
}

.chat-channel-item {
    padding-top: 6px;
    padding-bottom: 6px;
    padding-left: 24px;
    font-size: 12px;
}

.chat-channel-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 9px 14px;
    cursor: pointer;
    color: var(--text-secondary);
    font-size: 13px;
    font-weight: 500;
    border-left: 3px solid transparent;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
}

.chat-channel-item:hover,
.chat-channel-item.active {
    background: var(--bg-hover);
    color: var(--text-primary);
    border-left-color: var(--accent);
}

.chat-conversation {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.chat-conversation-header {
    padding: 14px 18px;
    border-bottom: 1px solid var(--border);
    font-weight: 700;
    color: var(--text-primary);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
}

/* Back to the conversation list: mobile only (see below). */
/* Library: template list on the left, open template on the right. */
.template-layout {
    display: flex;
    gap: 16px;
    align-items: flex-start;
}

.template-layout #schedules-list {
    flex: 1;
    min-width: 0;
}

.template-layout #template-detail {
    flex: 1;
    max-width: 480px;
    min-width: 320px;
    flex-shrink: 0;
}

/* Count chips per number of players (a single line that scrolls on mobile). */
.template-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: 10px 0 14px;
    /* Stays visible while the list scrolls. */
    position: sticky;
    top: var(--lib-chips-top, var(--app-top, 0px));
    z-index: 5;
    padding: 8px 0;
    background: var(--bg-primary);
}

/* The page scrolls, not .main-content: its overflow:auto would become the
   sticky container and the chips would scroll away with the list. Limited to the library. */
.main-content:has(.template-chips) {
    overflow: visible;
    /* clip (not hidden): nothing overflows horizontally, without creating a scroll container that would break the sticky. */
    overflow-x: clip;
    min-width: 0;  /* Otherwise the chip row widens the page. */
}

.template-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border-radius: 999px;
    border: 1px solid var(--border);
    background: transparent;
    color: var(--text-secondary);
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    white-space: nowrap;
    cursor: pointer;
}

.template-chip:hover {
    background: var(--bg-hover);
}

.template-chip.active {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
}

.template-chip-count {
    font-size: 11px;
    font-weight: 500;
    opacity: .75;
}

.template-fav {
    font-size: 12px;
}

/* Note on the right: league and date of last use. */
.template-last-use {
    flex-shrink: 0;
    max-width: 45%;
    margin-left: 12px;
    text-align: right;
    font-size: 11px;
    line-height: 1.35;
    color: var(--text-secondary);
}

/* Usage history in a template preview. */
.template-uses {
    margin-bottom: 18px;
}

.template-uses-title {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--text-muted);
    padding-bottom: 4px;
    margin-bottom: 4px;
    border-bottom: 1px solid var(--border);
}

.template-uses-table {
    width: auto;
    border-collapse: collapse;
    font-size: 13px;
}

.template-uses-table td {
    padding: 3px 0;
}

.template-uses-table .guh-date {
    color: var(--text-secondary);
    padding-right: 24px;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.template-uses-empty {
    font-size: 12px;
    font-style: italic;
    color: var(--text-muted);
}

.template-last-use-league {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Template rounds: a table so "&" and "vs" line up. */
.template-rounds-table {
    width: auto;
    align-self: flex-start;  /* .modal-body is a flex column: do not stretch. */
    border-collapse: collapse;
    font-size: 13px;
    font-variant-numeric: tabular-nums;
}

.template-rounds-table td {
    padding: 3px 0;
    white-space: nowrap;
}

.template-rounds-table .grt-head th {
    text-align: left;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--text-muted);
    padding: 14px 0 4px;
    border-bottom: 1px solid var(--border);
}

.template-rounds-table tr:first-child .grt-head th,
.template-rounds-table .grt-head:first-child th {
    padding-top: 0;
}

.template-rounds-table .grt-label {
    color: var(--text-muted);
    font-size: 11px;
    padding-right: 36px;
}

/* Positions right-aligned (units under units). */
.template-rounds-table .grt-num {
    text-align: right;
    min-width: 2.2ch;
}

.template-rounds-table .grt-sep {
    text-align: center;
    padding: 3px 8px;
    color: var(--text-secondary);
}

.template-rounds-table .grt-vs {
    text-align: center;
    padding: 3px 16px;
    color: var(--text-muted);
}

.template-rounds-table .grt-bye td {
    color: var(--text-muted);
}

.template-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-bottom: 14px;
}

.template-action {
    font-size: 12px;
    padding: 5px 10px;
}

/* Language menu (globe, desktop): Automatic / French / English. */
.header-locale-option {
    display: flex;
    align-items: center;
    gap: 6px;
    width: 100%;
    text-align: left;
    padding: 11px 16px;
    font-size: 13px;
    font-family: inherit;
    color: var(--text-primary);
    background: none;
    border: none;
    border-bottom: 1px solid var(--border);
    cursor: pointer;
}

.header-locale-option:last-child {
    border-bottom: none;
}

.header-locale-option:hover {
    background: var(--bg-secondary);
}

.header-locale-check {
    display: inline-block;
    width: 14px;
    color: var(--accent);
}

/* Account menu (mobile): Auto | FR | EN. */
.header-menu-locale {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 9px 12px 9px 16px;
    border-bottom: 1px solid var(--border);
    color: var(--text-secondary);
}

.header-locale-seg {
    flex: 1;
    padding: 5px 0;
    border-radius: 6px;
    border: 1px solid var(--border);
    background: transparent;
    color: var(--text-secondary);
    font-family: inherit;
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
}

.header-locale-seg.active {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
}

/* Schedule: the top area (schedule picker + rest report) scrolls on its own and
   never takes more than 45% of the screen. Without the cap, showing the rests
   pushed it to ~830px and squeezed the schedule below to 0px. See docs/styles.md#schedule-top-area. */
#schedule-shared-controls {
    flex: 0 0 auto;
    min-height: 0;
    /* vh/dvh: a percentage would not resolve, since the parent has no fixed height. */
    max-height: 45vh;
    max-height: 45dvh;
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
}

#schedule-rounds {
    min-height: 0;
}

/* Schedule: compact top bar (saves space). The list and the auto / "Rest" buttons share one line when there is room. */
#schedule-shared-controls {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    column-gap: 8px;
}

#schedule-picker {
    flex: 1 1 0;
    min-width: 0;
}

.schedule-tools {
    /* Icon row under the list, full width; the buttons share it equally. */
    flex: 0 0 100%;
    display: flex;
    gap: 10px;
    margin: 2px 0 8px;
}

.schedule-tools .schedule-icon-btn {
    flex: 1 1 0;
    width: auto;
}

.schedule-auto-slot,
.schedule-auto-slot .schedule-auto-controls {
    display: contents;
}

.schedule-auto-slot .schedule-auto-controls[hidden] {
    display: none;
}

.schedule-auto-panels {
    flex: 0 0 100%;
}

#rest-report-panel {
    flex: 0 0 100%;
}

.schedule-pick-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 8px;
    margin-bottom: 6px;
}

.schedule-pick-select {
    flex: 0 1 240px;
    min-width: 140px;
    padding: 6px 8px;
    font-size: 13px;
}

.schedule-pick-details {
    font-size: 11px;
    flex-shrink: 0;
}

.schedule-auto-controls {
    display: inline-flex;
    flex-wrap: wrap;
    gap: 6px;
}

.schedule-auto-controls[hidden] {
    display: none;
}

/* Schedule: one row per court, as on the printed sheet. Each team on 2 lines
   (one player per line, no "&"), on desktop as on mobile. Fixed columns keep the
   names aligned from row to row. */
.schedule-court-rows {
    display: flex;
    flex-direction: column;
}

.schedule-court-row {
    display: grid;
    grid-template-columns: 5.5em minmax(0, 1fr) 2em minmax(0, 1fr);
    align-items: center;
    column-gap: 8px;
    padding: 6px 4px;
    border-top: 1px solid var(--border);
}

.schedule-court-row:first-child {
    border-top: 0;
}

.scr-court {
    font-size: 11px;
    font-weight: 600;
    color: var(--text-secondary);
    white-space: nowrap;
}

.scr-court-short {
    display: none;
}

.scr-team {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    min-width: 0;
}

.scr-team .schedule-player,
.scr-team .sched-slot {
    min-width: 0;
    white-space: normal;
}

.scr-amp {
    display: none;
}

/* Wave rest, shown as one more court. */
.schedule-court-row.scr-rest .schedule-player {
    color: var(--text-secondary);
    font-style: italic;
}

.scr-vs {
    font-size: 10px;
    color: var(--text-muted);
    text-align: center;
}

/* Automatic schedule: kept proposals (📌) as chips under the bar. */
.schedule-kept {
    flex: 0 0 100%;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin: 0 0 6px;
}

.schedule-kept[hidden] {
    display: none;
}

.schedule-kept-chip {
    display: inline-flex;
    align-items: stretch;
    border: 1px solid var(--border);
    border-radius: 999px;
    overflow: hidden;
    font-size: 11px;
}

.schedule-kept-chip.active {
    border-color: var(--accent, #6366f1);
    background: rgba(99, 102, 241, .18);
}

.schedule-kept-chip.stale {
    opacity: .6;
}

.schedule-kept-show,
.schedule-kept-del {
    background: transparent;
    border: 0;
    color: var(--text);
    font: inherit;
    cursor: pointer;
    padding: 3px 8px;
}

.schedule-kept-show {
    font-family: ui-monospace, Menlo, monospace;
    letter-spacing: .04em;
}

/* Code of a proposal (📌): larger and white. */
.schedule-code {
    font-family: ui-monospace, Menlo, monospace;
    font-size: 14px;
    font-weight: 700;
    color: #fff;
    letter-spacing: .06em;
    vertical-align: -1px;
}

/* Right of the list: "📌 CODE" button (keep), or the code alone once the proposal is kept. */
.schedule-cur-code {
    flex-shrink: 0;
    background: transparent;
    border: 1px solid transparent;
    border-radius: 999px;
    padding: 3px 10px;
    font: inherit;
    font-size: 13px;
    color: var(--text);
    cursor: default;
}

.schedule-cur-code .schedule-code {
    font-size: 16px;
}

.schedule-cur-code.can-keep {
    border-color: var(--border);
    background: var(--surface2);
    cursor: pointer;
}

.schedule-cur-code[hidden] {
    display: none;
}

.schedule-kept-del {
    color: var(--text-muted);
    padding: 3px 7px 3px 2px;
}

/* Schedule: ▲▼ to reorder the waves. */
.schedule-round-label {
    display: flex;
    align-items: center;
}

.schedule-round-moves {
    margin-left: auto;
    display: inline-flex;
    gap: 4px;
}

.schedule-round-move {
    font-size: 10px;
    line-height: 1;
    padding: 4px 8px;
    border-radius: 5px;
    border: 1px solid var(--border);
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
}

.schedule-round-move:disabled {
    opacity: .3;
    cursor: default;
}

/* Schedule buttons as icon-only and larger: 🔄 other proposal, 💾 template,
   😴 rest requested, 📊 rest report. */
.schedule-icon-btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 52px;
    height: 42px;
    padding: 0;
    border-radius: 10px;
    border: 1px solid var(--border);
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
}

.schedule-icon-btn:hover {
    color: var(--text);
    border-color: var(--text-secondary);
}

.schedule-icon-badge {
    position: absolute;
    top: -6px;
    right: -6px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 999px;
    background: var(--accent);
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    line-height: 16px;
}

.schedule-must-rest-btn.active {
    border-color: var(--accent);
    color: var(--accent);
}

.schedule-must-rest {
    margin-top: 6px;
}

.schedule-must-rest-hint {
    font-size: 11px;
    color: var(--text-muted);
    margin-bottom: 6px;
}

.schedule-must-rest-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 5px;
}

.schedule-must-rest-chip {
    font-size: 12px;
    padding: 4px 9px;
    border-radius: 999px;
    border: 1px solid var(--border);
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
    font-family: inherit;
}

.schedule-must-rest-chip.active {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
}

/* Schedule: message while computing, or an error (e.g. fewer than 4 players). */
.schedule-generating {
    padding: 40px 16px;
    text-align: center;
    color: var(--text-muted);
    font-size: 14px;
}

.schedule-generating-error {
    color: #e05252;
    font-weight: 600;
}

.se-head-grid {
    display: grid;
    grid-template-columns: 1fr auto auto;
    gap: 10px;
    margin-bottom: 14px;
    align-items: end;
}

.chat-back-btn {
    display: none;
    background: none;
    border: none;
    color: var(--accent-light);
    font-size: 28px;
    line-height: 1;
    padding: 0 6px 2px 0;
    cursor: pointer;
    font-family: inherit;
}

.chat-member-count {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-muted);
    flex-shrink: 0;
}

.chat-messages {
    flex: 1;
    overflow-y: auto;
    padding: 14px 18px;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.chat-message-header {
    display: flex;
    align-items: baseline;
    gap: 8px;
}

.chat-message-author {
    font-weight: 700;
    font-size: 13px;
    color: var(--accent-light);
}

.chat-message-date {
    font-size: 11px;
    color: var(--text-muted);
}

/* Messenger-style bubbles: others on the left (neutral background, with their
   name), my messages on the right (accent colour). Rendered by _renderChatMessages. */
.chat-message {
    max-width: 80%;
    align-self: flex-start;
}

.chat-message-mine {
    align-self: flex-end;
}

.chat-message-mine .chat-message-header,
.chat-message-mine .chat-seen-by {
    justify-content: flex-end;
}

.chat-message-body {
    font-size: 14px;
    line-height: 1.45;
    color: var(--text-primary);
    white-space: pre-wrap;
    word-break: break-word;
    margin-top: 3px;
    padding: 8px 12px;
    border-radius: 16px 16px 16px 4px;
    background: var(--bg-hover);
    display: inline-block;
}

.chat-message-mine .chat-message-body {
    background: var(--accent);
    color: #fff;
    border-radius: 16px 16px 4px 16px;
}

.chat-message-mine {
    text-align: right;
}

.chat-message-mine .chat-message-body {
    text-align: left;
}

.chat-seen-by {
    display: flex;
    margin-top: 6px;
}

.chat-seen-by-avatar {
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: var(--bg-hover);
    border: 1.5px solid var(--bg-card);
    color: var(--text-secondary);
    font-size: 10px;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-left: -6px;
}

.chat-seen-by-avatar:first-child {
    margin-left: 0;
}

.chat-input-row {
    display: flex;
    gap: 10px;
    align-items: flex-end;
    padding: 12px 18px;
    border-top: 1px solid var(--border);
}

.chat-input {
    flex: 1;
    min-width: 0;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 7px;
    color: var(--text-primary);
    font-size: 13px;
    padding: 9px 12px;
    outline: none;
    font-family: inherit;
    resize: none;
    box-sizing: border-box;
    min-height: 40px;
    max-height: 120px;
    overflow-y: auto;
    line-height: 20px;
    transition: border-color 0.12s;
}

.chat-input:focus {
    border-color: var(--accent);
}

.chat-input::placeholder {
    color: var(--text-muted);
}

.modal-textarea {
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 7px;
    color: var(--text-primary);
    font-size: 13px;
    padding: 9px 12px;
    outline: none;
    width: 100%;
    font-family: inherit;
    resize: vertical;
    transition: border-color 0.12s;
    margin-bottom: 8px;
    min-height: 90px;
}

.modal-textarea:focus {
    border-color: var(--accent);
}

.modal-textarea::placeholder {
    color: var(--text-muted);
}

/* ── Toasts ─────────────────────────────────── */
.toast {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    min-width: 260px;
    max-width: 360px;
    padding: 13px 16px;
    border-radius: 10px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    box-shadow: 0 10px 30px rgba(0, 0, 0, .4);
    font-size: 13px;
    color: var(--text-primary);
    line-height: 1.5;
    animation: toast-in 0.2s ease-out;
}

.toast.success {
    border-left: 3px solid #22c55e;
}

.toast.error {
    border-left: 3px solid #ef4444;
}

.toast.info {
    border-left: 3px solid var(--accent, #4c6ef5);
}

.toast-icon {
    font-size: 16px;
    line-height: 1;
    flex-shrink: 0;
}

.toast-close {
    background: none;
    border: none;
    cursor: pointer;
    color: var(--text-muted);
    font-size: 14px;
    line-height: 1;
    padding: 0;
    margin-left: auto;
    flex-shrink: 0;
}

.toast-close:hover {
    color: var(--text-primary);
}

@keyframes toast-in {
    from {
        opacity: 0;
        transform: translateY(8px);
    }

    to {
        opacity: 1;
        transform: translateY(0);
    }
}

/* ── Sidebar add button ─────────────────────── */
.sidebar-add {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 10px 10px 0;
    padding: 9px 14px;
    cursor: pointer;
    color: var(--accent-light);
    font-weight: 600;
    font-size: 13px;
    border: 1px dashed var(--border);
    border-radius: 8px;
    transition: background 0.12s, border-color 0.12s;
}

.sidebar-add:hover {
    background: rgba(232, 97, 26, 0.1);
    border-color: var(--accent);
}

/* ── Global Player Management ── */
.player-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px 14px;
    border-radius: 8px;
    margin-bottom: 4px;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    transition: background 0.12s;
}

.player-row:hover {
    background: var(--bg-card);
}

.player-name {
    font-weight: 500;
    color: var(--text-primary);
    font-size: 14px;
}

.player-avatar {
    width: 38px;
    height: 38px;
    border-radius: 50%;
    background: var(--accent);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: 14px;
    flex-shrink: 0;
}

.gp-birth {
    font-size: 12px;
    color: var(--text-secondary);
    margin-top: 2px;
    display: block;
}

#players-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 5px;
}

/* Player list, list view (☰ button, setGpViewMode in static/js/app/library.js): one row per player,
   details in aligned columns. */
#players-list.list-view {
    display: block;
    border: 1px solid var(--border);
    border-radius: 8px;
    overflow: hidden;
}

.gp-list-row {
    display: grid;
    grid-template-columns: minmax(200px, 2fr) 50px 90px minmax(120px, 1.3fr) minmax(110px, 1fr) minmax(140px, 1.5fr);
    align-items: center;
    gap: 12px;
    padding: 6px 14px;
    background: var(--bg-secondary);
    border-bottom: 1px solid var(--border);
    font-size: 13px;
    color: var(--text-secondary);
}

.gp-list-row:last-child {
    border-bottom: none;
}

.gp-list-row:not(.gp-list-head):hover {
    background: var(--bg-card);
}

.gp-list-head {
    background: var(--bg-card);
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .5px;
    color: var(--text-muted);
}

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

.gp-list-name .player-avatar {
    width: 28px;
    height: 28px;
    font-size: 11px;
    margin: 0;
}

.gp-list-name .player-name,
.gp-list-cell {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.gp-list-row a {
    color: var(--accent-light);
    text-decoration: none;
}

.gp-none {
    color: var(--text-muted);
}

.gp-list-row .gp-icon {
    display: none;
}

/* Player linked to a user account: badge in the boxes view, "Account" column in
   the list view. In the boxes view the badge wraps under the name when there is no room. */
.gp-card-body {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
    width: 100%;
}

.gp-card-text {
    flex: 1;
    min-width: 0;
}

.player-name.gp-card-name {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 2px 6px;
    white-space: normal;
    overflow: visible;
}

.gp-card-name .gp-account-badge {
    margin-left: 0;
}

.gp-name-text {
    min-width: 0;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.gp-account-badge {
    display: inline-flex;
    align-items: center;
    margin-left: 6px;
    color: #86efac;
    line-height: 1;
    vertical-align: middle;
    white-space: nowrap;
}

.gp-account {
    color: #86efac;
}

/* ── Homonym grouping (admin players panel): one card/row per name, clubs in the detail ── */
.gp-group-badge {
    display: inline-flex;
    align-items: center;
    margin-left: 6px;
    padding: 1px 7px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 600;
    color: var(--text-secondary);
    background: var(--surface-2, rgba(255, 255, 255, .06));
    border: 1px solid var(--border);
    white-space: nowrap;
}
.gp-group-sub {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 3px;
}
.gp-group-sub .gp-birth {
    white-space: nowrap;
}
/* Link icon pushed to the right of a grouped card. */
.gp-group-right {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    flex: 0 0 auto;
}
/* The per-club list inside the group window. */
.gp-group-detail {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.gp-group-club {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 6px 8px;
    border-radius: 8px;
    font-size: 13px;
}
.gp-group-club:hover {
    background: var(--surface-2, rgba(255, 255, 255, .05));
}
.gp-group-club-name {
    color: var(--text-primary);
    font-weight: 500;
}
.gp-group-linked {
    color: #86efac;
}
.gp-group-unlinked {
    color: var(--text-muted);
    font-style: italic;
}
.gp-list-grouphead .gp-list-name {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* ── Admin "person" window (Modifier le joueur): account + member code + CLUBS ── */
/* Lightbox look like the QR zoom: a dark transparent backdrop with the content floating on it
   (no card chrome); swipe up on the header handle to close. */
#person-modal {
    background: rgba(0, 0, 0, .82);
}
.modal.person-sheet {
    background: transparent;
    border: none;
    box-shadow: none;
    overscroll-behavior: contain;
    transition: transform .14s ease, opacity .14s ease;
}
.person-grab {
    position: relative;
    cursor: grab;
    touch-action: none;
    padding-top: 16px;
}
.person-sheet .modal-close {
    font-size: 24px;
    width: 40px;
    height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 2.5px solid var(--text-muted);
    border-radius: 8px;
    background: var(--bg-secondary);
    color: var(--text-secondary);
}
.person-sheet .modal-close:hover {
    color: var(--text-primary);
    border-color: var(--text-primary);
}
.person-grabber {
    position: absolute;
    top: 7px;
    left: 50%;
    transform: translateX(-50%);
    width: 38px;
    height: 4px;
    border-radius: 999px;
    background: var(--text-muted);
    opacity: .5;
}
.person-name {
    font-size: 18px;
    font-weight: 700;
    color: var(--text-primary);
    margin-bottom: 14px;
}
.person-field {
    margin-bottom: 14px;
}
.person-nick-row {
    display: flex;
    align-items: center;
    gap: 8px;
}
.person-nick-row .modal-input {
    flex: 1;
    min-width: 0;
    margin-bottom: 0;
}
.person-nick-btn {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border: 2.5px solid var(--text-muted);
    border-radius: 8px;
    background: var(--bg-secondary);
    cursor: pointer;
    transition: border-color .12s ease, background .12s ease, color .12s ease, opacity .12s ease;
}
.person-nick-btn:disabled {
    opacity: .4;
    cursor: default;
}
.person-nick-save {
    color: #86efac;
    border-color: #86efac;
}
.person-nick-save:not(:disabled) {
    background: rgba(134, 239, 172, .14);
}
.person-nick-save:not(:disabled):hover {
    background: rgba(134, 239, 172, .24);
}
.person-nick-cancel {
    color: var(--text-secondary);
}
.person-nick-cancel:not(:disabled):hover {
    border-color: var(--text-primary);
    color: var(--text-primary);
}
.person-genders {
    display: flex;
    gap: 10px;
}
/* Home "M'ajouter comme joueur ?" confirm row (manager not yet a player). ✓ = add, ✕ = not playing.
   Same ✓/✕ language as the nickname row. */
.home-selfadd-row {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}
.home-selfadd-label {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
    margin-right: 2px;
}
.home-selfadd-btn {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border: 2.5px solid var(--text-muted);
    border-radius: 8px;
    background: var(--bg-secondary);
    cursor: pointer;
    transition: border-color .12s ease, background .12s ease, color .12s ease, opacity .12s ease;
}
.home-selfadd-btn:disabled {
    opacity: .5;
    cursor: default;
}
.home-selfadd-yes {
    color: #86efac;
    border-color: #86efac;
    background: rgba(134, 239, 172, .14);
}
.home-selfadd-yes:not(:disabled):hover {
    background: rgba(134, 239, 172, .26);
}
.home-selfadd-no {
    color: var(--text-secondary);
}
.home-selfadd-no:not(:disabled):hover {
    border-color: var(--red, #f87171);
    color: var(--red, #f87171);
}
/* Home "what to do next" guidance for a manager's league card. */
.home-onboard {
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--bg-secondary);
    padding: 12px 14px;
    margin-bottom: 14px;
}
/* "Try the demo" card on an empty Home (web/pages.py: show_demo_cta). */
.home-demo-cta {
    border-color: var(--accent);
    background: rgba(232, 97, 26, .08);
}
.home-demo-cta-title {
    font-size: 15px;
    font-weight: 700;
    color: var(--text-primary);
    margin-bottom: 6px;
}
.home-demo-cta-text {
    font-size: 13px;
    color: var(--text-secondary);
    line-height: 1.6;
    margin-bottom: 14px;
}
.home-onboard-counts {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
    margin-bottom: 8px;
}
.home-onboard-msg {
    font-size: 13px;
    line-height: 1.5;
    color: var(--text-secondary);
    margin-bottom: 10px;
}
.home-onboard-cta {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: var(--accent, #e8611a);
    color: #fff;
    border: none;
    border-radius: 8px;
    padding: 8px 14px;
    font-size: 13px;
    font-weight: 700;
    cursor: pointer;
    transition: filter .12s ease;
}
.home-onboard-cta:hover {
    filter: brightness(1.08);
}
.person-gender {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 9px 16px;
    border: 1px solid var(--border);
    border-radius: 8px;
    font-size: 13px;
    color: var(--text-secondary);
    cursor: pointer;
    transition: border-color .12s ease, background .12s ease, color .12s ease;
}
.person-gender input {
    margin: 0;
}
.person-gender:has(input:checked) {
    border-color: var(--accent);
    color: var(--text-primary);
    background: rgba(99, 102, 241, .1);
}
.person-section-title {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .7px;
    color: var(--text-muted);
    margin: 16px 0 8px;
    padding-top: 12px;
    border-top: 1px solid var(--border);
}
.person-account {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--bg-secondary);
}
.person-account .player-avatar {
    flex: 0 0 auto;
    width: 60px;
    height: 60px;
    font-size: 20px;
}
.person-account-info {
    display: flex;
    flex-direction: column;
    gap: 5px;
    min-width: 0;
    flex: 1;
}
.person-account-email {
    font-weight: 600;
    color: var(--text-primary);
    font-size: 14px;
    word-break: break-all;
}
.person-code {
    display: flex;
    align-items: center;
    gap: 8px;
}
.person-code .member-code {
    font-size: 16px;
}
.person-unlinked {
    font-size: 13px;
    color: var(--text-muted);
    font-style: italic;
    line-height: 1.5;
}
.person-clubs {
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.person-club {
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--bg-secondary);
}
.person-club-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 4px;
}
.person-club-resp {
    font-weight: 600;
    color: var(--text-primary);
    font-size: 14px;
}
.person-tolink {
    color: #fbbf24;
    font-size: 12px;
    font-weight: 600;
}
.person-link-btn {
    flex: 0 0 auto;
    font-size: 12px;
    padding: 5px 12px;
    color: #fbbf24;
    border: 1px solid #fbbf24;
    white-space: nowrap;
}
.person-link-btn:hover {
    background: rgba(251, 191, 36, .12);
}
.person-noleague {
    color: var(--text-muted);
    font-size: 12px;
    font-style: italic;
}
.person-club .account-linked-leagues {
    margin: 2px 0 0 0;
}

/* ── "Liaisons joueurs" modal (gestionnaire): roster with link status + code field ── */
.ll-hint {
    font-size: 13px;
    color: var(--text-muted);
    line-height: 1.5;
    margin-bottom: 14px;
}
/* Right after adding a player: the invitation-link fallback under the code field, then "Plus tard". */
.ll-hint.ll-hint-after {
    margin: 14px 0 0;
}
.ll-later {
    display: flex;
    justify-content: flex-end;
    margin-top: 12px;
}
.ll-list {
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.ll-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 9px 2px;
    border-bottom: 1px solid var(--border);
    font-size: 14px;
}
.ll-row:last-child {
    border-bottom: none;
}
.ll-name {
    color: var(--text-primary);
    font-weight: 500;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.ll-code-row {
    display: flex;
    align-items: center;
    gap: 6px;
    flex: 0 0 auto;
}
.ll-code-input {
    width: 140px;
    margin-bottom: 0;
    padding: 6px 8px;
    font-size: 13px;
}
/* Member-code inputs: same look as the displayed code (uppercase, monospace). */
.bz-code-input {
    text-transform: uppercase;
    font-family: ui-monospace, Menlo, monospace;
    letter-spacing: 1px;
}
.bz-code-input::placeholder {
    text-transform: none;
    letter-spacing: normal;
}
.ll-link-btn {
    font-size: 12px;
    padding: 6px 12px;
    white-space: nowrap;
}
.ll-scan-btn, .bz-scan-btn {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 7px 11px;
    line-height: 1;
}
.ll-empty {
    font-size: 13px;
    color: var(--text-muted);
    font-style: italic;
    padding: 8px 0;
}
.pl-status {
    font-size: 14px;
    line-height: 1.5;
    padding: 6px 0;
}

/* 🔗 link icon on a roster card (top-left), colored by link status. */
.btn-card-link {
    position: absolute;
    top: 5px;
    left: 5px;
    width: 20px;
    height: 20px;
    padding: 0;
    border-radius: 50%;
    font-size: 10px;
    line-height: 1;
    border: 1px solid var(--border);
    background: var(--bg-secondary);
    cursor: pointer;
    opacity: .55;
    filter: grayscale(1);
    transition: opacity .12s ease, filter .12s ease, border-color .12s ease;
}
.btn-card-link:hover {
    opacity: 1;
    filter: none;
}
.btn-card-link.is-linked {
    opacity: 1;
    filter: none;
    border-color: #86efac;
    background: rgba(134, 239, 172, .14);
}
.btn-card-link.is-pending {
    opacity: 1;
    filter: none;
    border-color: #fbbf24;
    background: rgba(251, 191, 36, .14);
}

/* ── Modal ──────────────────────────────────── */
.modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, .65);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1000;
    animation: fadeIn 0.15s ease;
}

.modal {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 12px;
    width: 380px;
    max-height: 90vh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    box-shadow: 0 20px 60px rgba(0, 0, 0, .5);
}

.modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 18px;
    border-bottom: 1px solid var(--border);
    font-weight: 700;
    font-size: 15px;
}

.modal-close {
    cursor: pointer;
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 18px;
    line-height: 1;
    padding: 0 2px;
    transition: color 0.12s;
}

.modal-close:hover {
    color: var(--text-primary);
}

.modal-body {
    padding: 18px;
    display: flex;
    flex-direction: column;
    gap: 6px;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
}

.modal-label {
    font-size: 11px;
    font-weight: 700;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.6px;
}

.modal-input {
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 7px;
    color: var(--text-primary);
    font-size: 14px;
    padding: 9px 12px;
    outline: none;
    width: 100%;
    transition: border-color 0.12s;
    font-family: inherit;
}

.modal-input:focus {
    border-color: var(--accent);
}

.modal-input::placeholder {
    color: var(--text-muted);
}

.modal-error {
    color: var(--red);
    font-size: 12px;
    min-height: 16px;
}

/* iOS-style switch (hidden checkbox + styled track and knob). A clear ON/OFF for
   settings such as "Force password change", easier to spot than a checkbox in a form. */
.ios-toggle {
    position: relative;
    display: inline-block;
    width: 46px;
    height: 26px;
    flex-shrink: 0;
}

.ios-toggle input {
    opacity: 0;
    width: 0;
    height: 0;
    position: absolute;
}

.ios-toggle-track {
    position: absolute;
    inset: 0;
    background: var(--border);
    border-radius: 999px;
    transition: background .15s;
}

.ios-toggle-track::before {
    content: "";
    position: absolute;
    left: 3px;
    top: 3px;
    width: 20px;
    height: 20px;
    background: #fff;
    border-radius: 50%;
    transition: transform .15s;
}

.ios-toggle input:checked+.ios-toggle-track {
    background: var(--accent);
}

.ios-toggle input:checked+.ios-toggle-track::before {
    transform: translateX(20px);
}

.modal-footer {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    padding: 12px 18px;
    border-top: 1px solid var(--border);
}

.btn {
    padding: 8px 16px;
    border-radius: 7px;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    border: 1px solid var(--border);
    font-family: inherit;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
}

.btn-ghost {
    background: transparent;
    color: var(--text-secondary);
}

.btn-ghost:hover {
    background: var(--bg-hover);
    color: var(--text-primary);
}

.gp-filter-btn {
    font-size: 12px;
    padding: 4px 12px;
}

.gp-filter-btn.active {
    background: var(--accent);
    color: #fff;
}

/* ── "⚙ Config" menu (the "Evening schedule — preview" card) ── */
.schedule-config-menu {
    display: flex;
    flex-direction: column;
    padding: 4px;
}

.schedule-config-item {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 8px 12px;
    background: transparent;
    border: none;
    border-radius: 6px;
    color: var(--text-primary);
    font-size: 13px;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
    white-space: nowrap;
    transition: background 0.12s;
}

.schedule-config-item:hover {
    background: var(--bg-hover);
}

.schedule-config-chevron {
    margin-left: auto;
    font-size: 10px;
    color: var(--text-muted);
    transition: transform 0.12s;
}

.schedule-config-item.open .schedule-config-chevron {
    transform: rotate(90deg);
}

.schedule-config-submenu {
    display: flex;
    flex-direction: column;
    padding-left: 14px;
}

.schedule-config-subitem {
    font-size: 12px;
    color: var(--text-secondary);
}

.btn-primary {
    background: var(--accent);
    color: #fff;
    border-color: var(--accent);
}

.btn-primary:hover {
    background: var(--accent-light);
    border-color: var(--accent-light);
}

.btn-primary:disabled {
    opacity: .5;
    cursor: not-allowed;
}

.btn-danger {
    background: transparent;
    color: var(--red);
    border-color: rgba(239, 68, 68, 0.35);
}

.btn-danger:hover {
    background: rgba(239, 68, 68, 0.1);
    border-color: var(--red);
}

.btn-danger.confirm {
    background: var(--red);
    color: #fff;
    border-color: var(--red);
}

.btn-danger.confirm:hover {
    background: #dc2626;
    border-color: #dc2626;
}

/* ── League info modal ──────────────────────── */
.league-info-header {
    display: flex;
    align-items: center;
    gap: 10px;
}

.league-info-section {
    margin-bottom: 16px;
}

.league-info-label {
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 1px;
    color: var(--text-muted);
    margin-bottom: 4px;
}

.league-info-value {
    font-size: 14px;
    color: var(--text-primary);
    line-height: 1.6;
    white-space: pre-wrap;
    word-break: break-word;
}

.league-info-empty {
    font-size: 13px;
    color: var(--text-muted);
    font-style: italic;
}

.league-info-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
}

/* ── Edit button (in league-header) ──────── */
.league-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 16px;
}

/* ── Player list (in the edit modal) ─────── */
.player-list {
    max-height: 190px;
    overflow-y: auto;
    border: 1px solid var(--border);
    border-radius: 7px;
    background: var(--bg-secondary);
    margin-bottom: 6px;
}

.player-list:empty::after {
    content: "Aucun joueur";
    display: block;
    padding: 10px 12px;
    color: var(--text-muted);
    font-size: 12px;
}

.player-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 7px 10px;
    border-bottom: 1px solid var(--border);
    font-size: 13px;
}

.player-row:last-child {
    border-bottom: none;
}

/* Selected row (e.g. the template shown in the detail box). */
.player-row.active {
    background: var(--bg-hover);
    box-shadow: inset 3px 0 0 var(--accent);
}

.player-remove {
    background: none;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    font-size: 14px;
    line-height: 1;
    padding: 0 2px;
    transition: color 0.12s;
    flex-shrink: 0;
}

.player-remove:hover {
    color: var(--red);
}

.add-player-row {
    display: flex;
    gap: 6px;
}

/* ── Schedule modal ──────────────────────────────────────────────────────── */

.schedule-modal {
    background: var(--surface);
    border-radius: 12px;
    /* One row per court, teams on 2 lines: 600px is enough. */
    width: 600px;
    max-width: 96vw;
    max-height: 88vh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.schedule-setup-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 10px;
    margin-bottom: 4px;
}

.schedule-player-checks {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 6px;
    margin-top: 6px;
    max-height: 220px;
    overflow-y: auto;
    padding: 2px;
}

.schedule-player-check {
    display: flex;
    align-items: center;
    gap: 7px;
    font-size: 13px;
    padding: 6px 8px;
    border-radius: 6px;
    background: var(--surface2);
    cursor: pointer;
    user-select: none;
}

.schedule-player-check input {
    cursor: pointer;
    accent-color: var(--blue);
}

.schedule-rounds-body {
    overflow-y: auto;
    flex: 1;
    padding: 0 2px 4px;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.schedule-round {
    background: var(--surface2);
    border-radius: 8px;
    padding: 10px 12px;
}

/* "Wave" and "Court" labels are lighter: --text-muted was too dark on the card background. */
.schedule-round-label {
    font-size: 12px;
    font-weight: 700;
    color: var(--text-secondary);
    letter-spacing: .06em;
    text-transform: uppercase;
    margin-bottom: 8px;
}

.schedule-player {
    font-size: 12px;
    font-weight: 500;
    color: var(--text);
    white-space: nowrap;
}

/* Schedule: "#13" and the name in 2 columns, like a table. A name that wraps
   stays aligned under the start of the name, and all names in a card start at the same place. */
.schedule-player,
.sched-slot {
    display: inline-grid;
    grid-template-columns: 1.7em minmax(0, 1fr);
    column-gap: 3px;
    align-items: baseline;
}

.schedule-player .match-pos,
.sched-slot .match-pos {
    grid-column: 1;
    margin-right: 0;
    text-align: right;
}

.schedule-player-name {
    grid-column: 2;
    min-width: 0;
}

/* ── Adjusting an evening's combinations ─────────────────────── */
.sched-edit-hint {
    font-size: 11px;
    color: var(--text-muted);
    background: var(--surface2);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 6px 10px;
    margin-bottom: 10px;
}

.sched-slot {
    font-size: 12px;
    font-weight: 500;
    color: var(--text);
    white-space: nowrap;
    background: transparent;
    border: 1px dashed var(--border);
    border-radius: 5px;
    padding: 1px 6px;
    cursor: pointer;
}

.sched-slot:hover {
    border-color: var(--blue);
    color: var(--blue);
}

.sched-slot.is-selected {
    border-style: solid;
    border-color: var(--blue);
    background: rgba(37, 99, 235, 0.18);
    color: var(--text);
}

/* Dropdown on a player slot. */
.sched-slot-pop {
    position: fixed;
    z-index: 2000;
    min-width: 190px;
    max-height: 320px;
    overflow-y: auto;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
    padding: 4px;
}

.sched-slot-pop-hd {
    font-size: 12px;
    font-weight: 700;
    color: var(--text);
    padding: 6px 8px 4px;
}

.sched-slot-pop-grp {
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--text-muted);
    padding: 8px 8px 3px;
}

.sched-slot-pop-item {
    display: block;
    width: 100%;
    text-align: left;
    background: transparent;
    border: 0;
    border-radius: 5px;
    padding: 6px 8px;
    font-size: 13px;
    color: var(--text);
    cursor: pointer;
}

.sched-slot-pop-item:hover {
    background: var(--surface2);
    color: var(--blue);
}

.sched-replace-grid {
    display: flex;
    gap: 14px;
    flex-wrap: wrap;
    margin-bottom: 8px;
}

.sched-replace-grid label {
    display: flex;
    flex-direction: column;
    gap: 3px;
    font-size: 11px;
    color: var(--text-muted);
}

.sched-replace-grid select {
    font-size: 13px;
    padding: 4px 6px;
    background: var(--surface);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 5px;
}

.sched-replace-waves {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 14px;
    margin-bottom: 10px;
}

.sched-wave-check {
    font-size: 12px;
    color: var(--text);
    display: flex;
    align-items: center;
    gap: 4px;
}

.sched-replace-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
}

.schedule-scores {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    flex-shrink: 0;
}

.score-input {
    width: 34px;
    text-align: center;
    background: var(--surface2);
    border: 1px solid var(--border);
    border-radius: 5px;
    color: var(--text);
    font-size: 13px;
    font-weight: 600;
    padding: 4px 2px;
    -moz-appearance: textfield;
}

.score-input::-webkit-outer-spin-button,
.score-input::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.score-input:focus {
    outline: none;
    border-color: var(--blue);
}

.score-sep {
    font-size: 14px;
    color: var(--text-muted);
}

.tab-schedule {
    margin-left: auto;
    background: var(--blue);
    color: #fff;
    border-radius: 6px;
}

.tab-schedule:hover {
    background: #1a6fd4;
}

/* ── Schedule editor (template) ──────────────────────────────────────────── */

.se-round {
    background: var(--surface2);
    border-radius: 7px;
    padding: 7px 10px;
}

.se-round-header {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 6px;
}

.se-round-label-prefix {
    font-size: 10px;
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: .05em;
}

.se-add-court-btn {
    font-size: 10px;
    padding: 2px 8px;
    margin-left: auto;
}

.se-remove-round {
    background: none;
    border: none;
    cursor: pointer;
    color: var(--text-muted);
    font-size: 11px;
    padding: 2px 3px;
    transition: color .12s;
}

.se-remove-round:hover {
    color: var(--red);
}

.se-courts-body {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.se-court-row {
    display: flex;
    align-items: center;
    gap: 4px;
    flex-wrap: nowrap;
}

.se-terrain-label {
    font-size: 10px;
    color: var(--text-muted);
    min-width: 50px;
    flex-shrink: 0;
}

.se-rank-input {
    width: 34px;
    text-align: center;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 4px;
    color: var(--text);
    font-size: 11px;
    font-weight: 600;
    padding: 3px 2px;
    -moz-appearance: textfield;
}

.se-rank-input::-webkit-outer-spin-button,
.se-rank-input::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.se-rank-input:focus {
    outline: none;
    border-color: var(--blue);
}

.se-amp {
    font-size: 10px;
    color: var(--text-muted);
    flex-shrink: 0;
}

.se-vs {
    font-size: 10px;
    color: var(--text-muted);
    font-weight: 600;
    flex-shrink: 0;
    padding: 0 3px;
}

.se-remove-court {
    background: none;
    border: none;
    cursor: pointer;
    color: var(--text-muted);
    font-size: 11px;
    padding: 2px 3px;
    transition: color .12s;
    flex-shrink: 0;
}

.se-remove-court:hover {
    color: var(--red);
}

.se-remove-court:disabled {
    opacity: .3;
    cursor: default;
}

#schedule-editor-overlay .modal-label {
    font-size: 11px;
}

#schedule-editor-overlay .modal-input {
    font-size: 12px;
    padding: 6px 9px;
}

/* ── Schedule generation — ranked player list ────────────────────────────── */

.schedule-ranked-list {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-top: 6px;
    max-height: 260px;
    overflow-y: auto;
}

.schedule-rank-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 10px;
    background: var(--surface2);
    border-radius: 6px;
    font-size: 13px;
}

.schedule-rank-num {
    font-size: 11px;
    font-weight: 700;
    color: var(--text-muted);
    min-width: 24px;
    flex-shrink: 0;
}

.schedule-rank-name {
    flex: 1;
    font-weight: 500;
}

.schedule-rank-btns {
    display: flex;
    gap: 2px;
    flex-shrink: 0;
}

.schedule-rank-btns button {
    background: none;
    border: 1px solid var(--border);
    border-radius: 4px;
    cursor: pointer;
    color: var(--text-muted);
    font-size: 12px;
    padding: 2px 6px;
    line-height: 1;
    transition: color .12s, border-color .12s;
}

.schedule-rank-btns button:hover:not(:disabled) {
    color: var(--text);
    border-color: var(--text-muted);
}

.schedule-rank-btns button:disabled {
    opacity: .3;
    cursor: default;
}

.schedule-rank-remove:hover:not(:disabled) {
    color: var(--red) !important;
    border-color: var(--red) !important;
}

/* ── Schedule preset buttons in session modal ────────────────────────────── */
.sch-preset-btn {
    font-size: 12px;
    padding: 4px 14px;
    transition: background .12s, color .12s, border-color .12s;
}

#session-schedule-checkboxes label:hover {
    color: var(--text);
}

/* ── Mobile bottom nav ─────────────────────── */
.mobile-bottom-nav {
    display: none;
}

/* Mobile menus (bottom bar, Ligue/Admin drawers): a long press must not select
   their text or open the iOS callout (Copy, Look Up…). */
.mobile-bottom-nav,
.mob-drawer {
    -webkit-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;
}

.mob-drawer-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, .55);
    z-index: 199;
}

.mob-drawer-overlay.open {
    display: block;
}

.mob-drawer {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    background: var(--bg-secondary);
    border-top: 1px solid var(--border);
    border-radius: 16px 16px 0 0;
    z-index: 200;
    transform: translateY(100%);
    transition: transform .25s ease;
    max-height: 70vh;
    overflow-y: auto;
}

.mob-drawer.open {
    transform: translateY(0);
}

.mob-drawer-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 16px 18px 12px;
    border-bottom: 1px solid var(--border);
}

.mob-drawer-body {
    /* + the iOS home-indicator area (0 elsewhere), so the last entry of the
       Ligue/Admin drawers is not under the gesture zone. */
    padding: 10px 0 calc(16px + env(safe-area-inset-bottom, 0px));
}

.mob-drawer-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 13px 20px;
    font-size: 15px;
    cursor: pointer;
    color: var(--text-secondary);
    transition: background .12s, color .12s;
}

.mob-drawer-item:hover,
.mob-drawer-item.active {
    background: var(--bg-card);
    color: var(--text-primary);
}

.mob-drawer-add {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 8px 14px 0;
    padding: 11px 14px;
    cursor: pointer;
    color: var(--accent-light);
    font-weight: 600;
    font-size: 14px;
    border: 1px dashed var(--border);
    border-radius: 8px;
}

/* ── Responsive — mobile (≤ 768px) ─────────── */
/* Mobile layout: narrow screens AND landscape phones (touch, under 500px high).
   A landscape iPhone is 844–932px wide, so without this it got the desktop layout:
   bottom bar hidden and sidebar too short for Rencontres / Statistiques. */
@media (max-width: 768px), (max-height: 500px) and (pointer: coarse) {

    /* Sidebar hidden on mobile */
    .sidebar {
        display: none;
    }

    .sidebar-resize-handle {
        display: none;
    }

    /* Bottom nav visible. It extends by env(safe-area-inset-bottom) (~34px on iPhone,
       0 elsewhere) so its buttons stay above the iOS home indicator, which otherwise
       takes touches and swipes. Needs viewport-fit=cover. See docs/styles.md#mobile-bottom-nav. */
    .mobile-bottom-nav {
        display: flex;
        position: fixed;
        bottom: 0;
        left: 0;
        right: 0;
        background: var(--bg-secondary);
        border-top: 1px solid var(--border);
        z-index: 100;
        height: calc(64px + env(safe-area-inset-bottom, 0px));
        padding-bottom: env(safe-area-inset-bottom, 0px);
        padding-left: env(safe-area-inset-left, 0px);
        padding-right: env(safe-area-inset-right, 0px);
    }

    .mob-nav-btn {
        flex: 1;
        /* Can shrink below its label width (the label is cut): the bar never scrolls
           horizontally, even with 8 buttons on a 320px screen. */
        min-width: 0;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 2px;
        background: none;
        border: none;
        color: var(--text-muted);
        cursor: pointer;
        padding: 6px 0;
        font-family: inherit;
        transition: color .12s;
        -webkit-tap-highlight-color: transparent;
    }

    .mob-nav-btn.active {
        color: var(--accent-light);
    }

    .mob-nav-icon {
        font-size: 24px;
        line-height: 1;
        position: relative;
        display: inline-flex;
    }

    /* Language: the globe sits just left of the avatar, compact so the BadZone name keeps
       its room; the account menu then has no language row. */
    .header-locale-wrap {
        flex: none;
    }

    #header-locale-btn {
        width: 30px !important;
        height: 30px !important;
    }

    #header-locale-menu {
        right: -40px !important;
    }

    /* Administration in the account menu on mobile too (the bottom bar has no Admin button):
       Access and Attendance appear there, and a long menu scrolls. */
    #header-user-menu .header-menu-mobile-only {
        display: block;
    }

    #header-user-menu {
        max-height: calc(100dvh - var(--app-top, 68px) - 16px);
        overflow-y: auto;
    }

    /* Matches (Standings / Matches) and Players (Regular / League) tabs share the full
       width, labels centred. */
    .matches-view-tabs .tab,
    .players-subtabs .tab {
        flex: 1;
        text-align: center;
        justify-content: center;
    }

    /* The whole page never slides sideways on mobile: anything that overflows is clipped.
       clip (not hidden) does not create a scroll container, so sticky headers keep working.
       Areas that scroll horizontally on purpose (chips, tables) keep their own scrolling. */
    html,
    body {
        overflow-x: clip;
    }

    /* Toasts (showToast) above the bottom bar (inline bottom:24px in index.html, hence !important). */
    #toast-container {
        bottom: calc(76px + env(safe-area-inset-bottom, 0px)) !important;
        right: 12px !important;
        left: 12px;
    }

    /* Larger icons for touch. */
    .mob-nav-icon svg {
        width: 24px;
        height: 24px;
    }

    .mob-nav-label {
        font-size: 10px;
        font-weight: 600;
        white-space: nowrap;
    }

    /* With the per-league tabs (Rencontres/Statistiques/Joueurs/Chat) added between
       Home and Ligue, the bar can hold up to 9 buttons (admin): scroll horizontally
       instead of squeezing labels unreadably. (Stale: the next comment says there is no horizontal scroll.) */
    /* No horizontal scroll: a sideways swipe at the bottom is the iOS app-switch gesture
       and would win over the bar's own scrolling. The buttons (7 at most, admin entries
       grouped behind "Admin") share the width: each takes its label's width ("Statistiques"
       more than "Chat"), then the rest is shared. "…" only if the screen is really too narrow. */
    .mobile-bottom-nav {
        overflow-x: hidden;
    }

    .mob-nav-btn {
        flex: 1 1 auto;
        min-width: 0;
        padding: 6px 2px;
    }

    .mob-nav-btn .mob-nav-label {
        max-width: 100%;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* Chat badge (#mob-chat-badge) as a dot on the icon rather than inline,
       since there is no room for the desktop sidebar's inline badge. */
    .mob-nav-icon .tab-badge {
        position: absolute;
        top: -6px;
        right: -10px;
        margin-left: 0;
        font-size: 9px;
        padding: 1px 5px;
    }

    /* Header compact */
    .header-inner {
        /* + side notch when the phone is in landscape (0 otherwise). */
        padding: 6px calc(12px + env(safe-area-inset-right, 0px)) 6px calc(12px + env(safe-area-inset-left, 0px));
        gap: 10px;
    }

    .header-logo {
        font-size: 30px;
    }

    .header-logo img {
        height: 38px;
    }

    .header-title {
        font-size: 23px;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    .header-subtitle {
        display: none;
    }

    .header-user-email {
        max-width: 90px;
        overflow: hidden;
    }

    .header-user-email>div {
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    .header-user-chevron {
        display: none;
    }

    /* Show the icon on mobile, hide it on desktop. flex, not inline, which would
       cancel the centring of the role icon in its circle. */
    .header-user-icon {
        display: flex;
    }

    /* The only access to sign-out on mobile (sidebar hidden here). */
    #header-account-btn {
        display: flex;
    }

    /* Main content full width, bottom padding for the nav bar. Minimum height = the
       VISIBLE area (100dvh) minus the fixed header (--app-top, already reserved by the
       body padding-top). 100vh is only the fallback for old browsers: it ignores
       Safari's toolbar, so it is too tall on iPhone. See docs/styles.md#mobile-viewport-height. */
    .main-content {
        --mc-pad-y: 14px;  /* reused by #league-bar's negative top margin (see base rule) */
        padding: var(--mc-pad-y) calc(12px + env(safe-area-inset-right, 0px)) calc(80px + env(safe-area-inset-bottom, 0px)) calc(12px + env(safe-area-inset-left, 0px));
        min-height: calc(100vh - var(--app-top, 58px));
        min-height: calc(100dvh - var(--app-top, 58px));
    }

    /* Page title pinned below the header (Help & support). Fixed, so it does not move
       with scrolling or the iOS bounce (a sticky title would bounce with the content,
       as the header used to). Fixed 50px height, matched by .has-fixed-title. */
    .page-title-bar {
        position: fixed;
        top: var(--app-top, 58px);
        left: 0;
        right: 0;
        z-index: 140;
        height: 50px;
        margin: 0 !important;
        padding: 0 calc(12px + env(safe-area-inset-right, 0px)) 0 calc(12px + env(safe-area-inset-left, 0px));
        display: flex;
        align-items: center;
        background: var(--bg-primary);
        border-bottom: 1px solid var(--border);
    }

    .has-fixed-title {
        padding-top: 44px;
    }

    /* Help section scrolled into view on open (static/js/app/): below the fixed title, above
       the bottom bar. (#support-panel: overrides the base .help-item rule further down.) */
    #support-panel .help-item {
        /* With html scroll-padding-top (header + 8px), this lands just below the 50px fixed title. */
        scroll-margin-top: 50px;
        scroll-margin-bottom: calc(72px + env(safe-area-inset-bottom, 0px));
    }

    /* App layout, no flex gap (the rule sets only min-height). */
    .app-layout {
        min-height: calc(100vh - var(--app-top, 58px));
        min-height: calc(100dvh - var(--app-top, 58px));
    }

    /* Scrollable tab bar. */
    .tab-bar {
        overflow-x: auto;
        overflow-y: hidden;
        flex-wrap: nowrap;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
        gap: 0;
        margin-bottom: 12px;
    }

    .tab-bar::-webkit-scrollbar {
        display: none;
    }

    .tab {
        padding: 8px 13px;
        font-size: 12px;
        white-space: nowrap;
        flex-shrink: 0;
    }

    /* Full-screen modals. */
    .modal-overlay {
        align-items: flex-end;
        padding: 0;
    }

    .modal {
        width: 100% !important;
        max-width: 100% !important;
        border-radius: 16px 16px 0 0;
        max-height: 92vh;
        overflow-y: auto;
    }

    /* Small confirmation dialogs (password, "Confirmation"): centred, not a panel
       stuck to the bottom like the forms. */
    .modal-overlay.modal-center {
        align-items: center;
        padding: 16px;
    }

    .modal-overlay.modal-center .modal {
        max-width: 400px !important;
        border-radius: 12px;
    }

    /* Compact match cards, one column: the old auto-fill/minmax(150px) could still
       force 2 columns that were too narrow, overflowing the screen with long names. */
    .matches-grid {
        grid-template-columns: 1fr;
        padding: 8px;
        gap: 6px;
    }

    .ra-grid {
        grid-template-columns: 1fr;
        padding: 8px;
        gap: 6px;
    }

    .match-card {
        min-width: 0;
    }

    .match-team {
        padding: 6px 10px;
        gap: 5px;
    }

    .match-players {
        font-size: 14px;
        line-height: 1.3;
    }

    /* Below 768px the columns are narrow: names may wrap. */
    .matches-card>.matches-grid .match-players {
        white-space: normal;
    }

    .match-score {
        font-size: 26px;
        min-width: 34px;
    }

    .draft-score-input {
        font-size: 26px;
        width: 44px;
    }

    /* Player list, list view: gender and birth hidden for lack of room, phone and
       email reduced to an icon. The name keeps its width. */
    .gp-list-row {
        grid-template-columns: minmax(0, 1fr) 32px 32px 32px;
        gap: 8px;
        padding: 6px 10px;
        font-size: 12px;
    }

    .gp-col-gender,
    .gp-col-birth,
    .gp-list-row .gp-text {
        display: none;
    }

    .gp-list-row .gp-icon {
        display: inline;
        font-size: 14px;
    }

    .gp-list-row>span:nth-child(n+4) {
        text-align: center;
    }

    .gp-list-name .player-name {
        font-size: 12px;
    }

    /* Rencontres tab: stack everything vertically, full width */
    .matches-layout {
        align-items: stretch;
    }

    .matches-col-left {
        flex-direction: column;
        align-items: stretch;
        width: 100%;
    }

    .matches-col-left>.card {
        flex: none;
    }

    /* Rencontres card full width; the resize handle is useless on touch.
       overflow:visible so the box grows with its content instead of scrolling inside. */
    .matches-card {
        flex: none;
        width: 100%;
        max-width: 100%;
        min-width: 0;
        resize: none;
        overflow: visible;
    }

    /* Leaderboard table compact */
    .leaderboard thead th {
        font-size: 10px;
        padding: 5px 4px;
        letter-spacing: 0;
    }

    .leaderboard tbody td {
        font-size: 14px;
        padding: 5px 4px;
    }

    .player-name-cell {
        font-size: 14px;
        padding-left: 3px !important;
    }

    /* leaderboard-wide: tables with 8+ columns (cumulative stats, overall standings).
       A long compound name (e.g. "Jean-Francois Chevarie") could push the table off
       screen and the numeric columns on the right out of view, with no visible scrollbar.
       The name width is capped and truncated with "…" so the numeric columns always stay visible. */
    .leaderboard-wide .player-name-cell {
        max-width: 92px;
        overflow: hidden;
        text-overflow: ellipsis;
        /* Stays at 12px: only the numeric columns below shrink, not the name. */
        font-size: 12px;
    }

    /* Smaller font than the other .leaderboard tables: these 2 tables have 8-9 columns
       (4-6 elsewhere), so they are tighter on mobile. Numbers (#, Elo, PP, PC, %, W/L…)
       shrink more than the name, which stays the readable main element of the row. */
    .leaderboard-wide thead th {
        font-size: 9px;
    }

    .leaderboard-wide tbody td {
        font-size: 11px;
    }

    .rank-num {
        font-size: 13px;
        width: 16px;
    }

    .rank-badge {
        font-size: 11px;
        width: 32px;
    }

    .pts-val,
    .wl-val,
    .delta-val {
        font-size: 14px;
    }

    /* Headers (Dates, overall / evening standings, Rencontres, Wave A/B/C...): meant to keep
       their small desktop size (9-10px) on mobile, with no earlier override for them.
       (Stale: the rules below set 11-12px.) */
    .date-sidebar-header {
        font-size: 11px;
    }

    .date-item {
        padding: 7px 10px;
        font-size: 13px;
    }

    .date-item-day {
        font-size: 17px;
    }

    .date-item-month {
        font-size: 11px;
    }

    .date-item-year {
        font-size: 10px;
    }

    .card-header {
        font-size: 12px;
    }

    .match-wave-label {
        font-size: 12px;
    }

    .player-row {
        padding: 6px 8px;
        border-radius: 6px;
        margin-bottom: 0;
        min-width: 0;
        flex-direction: column;
        align-items: flex-start;
        gap: 4px;
    }

    .player-name {
        font-size: 11px;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        width: 100%;
    }

    /* Player cards compact */
    .players-grid {
        grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));
        gap: 8px;
        margin-bottom: 16px;
    }

    .player-card {
        padding: 10px 6px 8px;
        border-radius: 8px;
    }

    .player-avatar {
        width: 34px;
        height: 34px;
        font-size: 12px;
        margin-bottom: 6px;
    }

    .player-card-name {
        font-size: 11px;
        margin-bottom: 4px;
    }

    .btn-add-player {
        font-size: 10px;
        padding: 3px 0;
        margin-top: 5px;
    }

    .players-section-title {
        font-size: 10px;
        margin-bottom: 8px;
    }

    /* Rencontres (evening already played): the per-court columns (.court-column,
       min-width:190px each on desktop) overflowed to the right instead of scrolling.
       .matches-card is overflow:visible on mobile (see above), so the overflow went
       off screen. Stacked in a column, each court takes the full available width. */
    .matches-grid.court-columns {
        flex-direction: column;
    }

    .matches-grid.court-columns>.court-column {
        min-width: 0;
        width: 100%;
    }

    /* Evening schedule preview, "by team" mode (.draft-preview): forced to 3 fixed
       columns on desktop, far too narrow on mobile, so 1 column here too. */
    .draft-preview .matches-grid {
        grid-template-columns: 1fr !important;
    }

    /* One row per court on mobile: "T1", each team on 2 lines (4 name columns do not fit on a phone). */
    .schedule-court-row {
        grid-template-columns: 1.8em minmax(0, 1fr) 1.6em minmax(0, 1fr);
        column-gap: 4px;
    }

    .scr-court-long {
        display: none;
    }

    .scr-court-short {
        display: inline;
    }

    /* Schedule picker: shrinks so the schedule label stays on its line. */
    .schedule-pick-select {
        flex: 1 1 120px;
        min-width: 120px;
    }

    .schedule-player {
        white-space: normal;
    }

    /* Home (dashboard): tighter spacing and smaller fonts on mobile. The template
       (_home_panel.html) computes sizes and margins inline with Jinja (values vary
       with context), so only !important can override them here. */
    #home-panel .home-title {
        font-size: 19px !important;
        margin-bottom: 10px !important;
    }

    #home-panel .home-message {
        font-size: 15px !important;
        margin-bottom: 14px !important;
    }

    #home-panel .home-cards-wrap {
        gap: 8px !important;
    }

    #home-panel .home-league-card {
        padding: 14px 16px !important;
    }

    #home-panel .home-league-name {
        font-size: 16px !important;
        margin-bottom: 8px !important;
    }

    #home-panel .home-stat-line {
        font-size: 14px !important;
        margin-bottom: 6px !important;
    }

    #home-panel .home-upcoming-line {
        font-size: 14px !important;
    }

    /* "Next match:" alone on its line, the date on the same line as the Present/Absent
       buttons. display:contents makes the label and the date flex items of
       .home-upcoming-row, while they inherit the size and colour of .home-upcoming-line. */
    #home-panel .home-upcoming-row {
        row-gap: 6px !important;
        column-gap: 8px !important;
    }

    #home-panel .home-upcoming-line {
        display: contents;
    }

    #home-panel .home-upcoming-label {
        flex-basis: 100%;
    }

    #home-panel .home-upcoming-date {
        white-space: nowrap;
    }

    /* Very narrow screens (≤ 370px): without the year, the date and Present/Absent still fit on one line. */
    @media (max-width: 370px) {
        #home-panel .home-upcoming-year {
            display: none;
        }
    }

    #home-panel .date-attendance-btn {
        font-size: 14px !important;
        padding: 7px 11px !important;
    }

    /* Statistics > position trend: the chart (flex:1) and its legend (fixed 300px) sat
       side by side. On a phone the legend (one name per player) took all the room and the
       chart was invisible (~0px wide). Stacked: legend on top (height-limited, scrolls),
       chart full width below. */
    .ranking-chart-row {
        flex-direction: column !important;
        height: auto !important;
        gap: 14px !important;
    }

    .ranking-chart-canvas-wrap {
        height: 220px !important;
        width: 100% !important;
    }

    #ranking-chart-legend {
        width: 100% !important;
        grid-auto-flow: row !important;
        grid-template-columns: repeat(2, 1fr) !important;
    }

    /* Full-screen chat, Messenger-style. Three rules:
       - the page does not scroll (body.chat-open, set by selectChatPanel); the chat is
         fixed between the header (--app-top) and the bottom bar, and follows the visible
         area while the iOS keyboard is open;
       - two screens: the conversation list, or one conversation (.chat-has-conversation)
         with a back button;
       - only the list and the messages scroll, without bounce.
       The list stays a vertical column: the chat spans several leagues, and a horizontal
       strip was a regression on iPhone. See docs/styles.md#mobile-chat. */
    html:has(body.chat-open),
    body.chat-open {
        overflow: hidden;
        overscroll-behavior: none;
    }

    body.chat-open #chat-panel {
        position: fixed;
        top: var(--app-top, 58px);
        left: 0;
        right: 0;
        bottom: calc(64px + env(safe-area-inset-bottom, 0px));
        padding: 8px calc(8px + env(safe-area-inset-right, 0px)) 8px calc(8px + env(safe-area-inset-left, 0px));
        z-index: 40;
    }

    /* Keyboard open (body.kb-open, see _syncVisualViewport): iOS scrolled the page by
       --vv-top. The chat fills exactly the visible area above the keyboard (below the
       header if it is still visible), and the bottom bar, which would float above the
       keyboard, is hidden. */
    body.chat-open.kb-open #chat-panel {
        top: max(var(--app-top, 58px), var(--vv-top, 0px));
        bottom: auto;
        height: calc(var(--vv-top, 0px) + var(--vv-h, 100vh) - max(var(--app-top, 58px), var(--vv-top, 0px)));
        padding-bottom: 6px;
    }

    body.chat-open.kb-open #mobile-bottom-nav,
    body.chat-open.chat-input-focus #mobile-bottom-nav {
        display: none;
    }

    /* Score entry: bottom bar hidden while a score field has focus (static/js/app/, focusin on .draft-score-input).
       Same for any text field (layout.js: text-input-focus), so iOS never leaves the bar above the keyboard. */
    body.text-input-focus #mobile-bottom-nav,
    body.score-input-focus #mobile-bottom-nav {
        display: none;
    }

    /* "Ask BadZone": bottom bar hidden while the question is typed (static/js/app/: focus/blur
       on #ai-input); the input moves to the very bottom. */
    body.ai-input-focus #mobile-bottom-nav {
        display: none;
    }

    body.ai-input-focus .ai-compose {
        bottom: env(safe-area-inset-bottom, 0px);
    }

    /* Active message field: the bottom bar is hidden and the chat extends to the bottom
       of the screen (above the keyboard once kb-open). */
    body.chat-open.chat-input-focus:not(.kb-open) #chat-panel {
        bottom: env(safe-area-inset-bottom, 0px);
    }

    .chat-layout {
        flex-direction: column;
        height: 100%;
        min-height: 0;
    }

    .chat-channel-list {
        width: 100%;
        flex: 1;
        overflow-y: auto;
        overflow-x: hidden;
        overscroll-behavior: contain;
        border-right: none;
        padding: 6px 0;
    }

    .chat-layout.chat-has-conversation .chat-channel-list,
    .chat-layout:not(.chat-has-conversation) .chat-conversation {
        display: none;
    }

    .chat-league-row .chat-channel-name {
        font-size: 16px;
    }

    .chat-league-preview {
        font-size: 14px;
    }

    .chat-league-time {
        font-size: 12px;
    }

    .chat-channel-item {
        border-radius: 0;
        padding: 14px;
        font-size: 15px;
    }

    .chat-conversation {
        flex: 1;
        min-height: 0;
    }

    .chat-conversation-header {
        padding: 10px 12px;
        justify-content: flex-start;
    }

    .chat-conversation-header #chat-conversation-title {
        flex: 1;
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .chat-back-btn {
        display: inline-flex;
    }

    /* Library: list OR open template (✕ goes back to the list). */
    .template-layout {
        display: block;
    }

    .template-layout #template-detail {
        min-width: 0;
        max-width: none;
        width: 100%;
    }

    .template-layout:not(.has-detail) #template-detail,
    .template-layout.has-detail #schedules-list {
        display: none;
    }

    .template-chips {
        /* Below the fixed mobile header (and its banners). */
        top: var(--app-top, 58px);
        flex-wrap: nowrap;
        overflow-x: auto;
        overscroll-behavior-x: contain;
        /* Edge to edge, exactly on the .main-content margin (12px + notch). With a 16px
           negative margin the row overflowed by 4px and the whole page slid sideways. */
        margin-left: calc(-12px - env(safe-area-inset-left, 0px));
        margin-right: calc(-12px - env(safe-area-inset-right, 0px));
        padding: 8px calc(12px + env(safe-area-inset-right, 0px)) 8px calc(12px + env(safe-area-inset-left, 0px));
        scrollbar-width: none;
        -webkit-overflow-scrolling: touch;
    }

    .template-chips::-webkit-scrollbar {
        display: none;
    }

    .template-chip {
        flex-shrink: 0;
    }

    /* Template: name on the left, last-use note on the right (.player-row becomes a column on mobile). */
    .player-row.template-row {
        flex-direction: row;
        align-items: center;
    }

    /* Schedule name across the full width, Players / Courts below. */
    .se-head-grid {
        grid-template-columns: auto auto;
        justify-content: start;
    }

    .se-head-grid .se-name-field {
        grid-column: 1 / -1;
    }

    .chat-messages {
        padding: 12px;
        overscroll-behavior: contain;
        -webkit-overflow-scrolling: touch;
    }

    .chat-input-row {
        padding: 8px 10px;
    }

    /* iOS zooms on fields under 16px. */
    .chat-input {
        font-size: 16px;
    }
}

/* Landscape phone: barely ~390px high. The header is not pinned (it scrolls with
   the page) to leave room for content; the admin/preview banners stick to the top instead. */
@media (max-height: 500px) and (pointer: coarse) {
    #header {
        position: static;
    }

    body {
        padding-top: 0;
    }

    #admin-mode-banner,
    #view-as-banner {
        position: sticky !important;
        top: 0 !important;
    }

    html {
        scroll-padding-top: 8px;
    }
}

/* ── DB Admin Modal ─────────────────────────────────────────────────────── */
.db-admin-header {
    padding-top: calc(10px + env(safe-area-inset-top, 0px)) !important;
    padding-left: calc(20px + env(safe-area-inset-left, 0px)) !important;
    padding-right: calc(20px + env(safe-area-inset-right, 0px)) !important;
}

.db-back-btn {
    display: none;
}


.db-sidebar {
    width: 210px;
    min-width: 160px;
    background: var(--bg-secondary);
    border-right: 1px solid var(--border);
    overflow-y: auto;
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
}

.db-sidebar-hdr {
    padding: 10px 14px;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--text-muted);
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
}

.db-tbl-item {
    padding: 8px 14px;
    cursor: pointer;
    font-size: 12px;
    color: var(--text-secondary);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 6px;
    transition: background .1s;
    border-left: 3px solid transparent;
}

.db-tbl-item:hover {
    background: var(--bg-card);
}

.db-tbl-item.active {
    background: var(--bg-card);
    color: var(--text-primary);
    font-weight: 600;
    border-left-color: var(--accent-light);
}

.db-tbl-count {
    font-size: 10px;
    color: var(--text-muted);
    background: var(--bg-primary);
    padding: 1px 6px;
    border-radius: 10px;
    flex-shrink: 0;
}

.db-main {
    flex: 1;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.db-toolbar {
    padding: 8px 16px;
    border-bottom: 1px solid var(--border);
    display: flex;
    align-items: center;
    gap: 10px;
    background: var(--bg-card);
    flex-shrink: 0;
    flex-wrap: wrap;
}

.db-content {
    flex: 1;
    overflow: auto;
}

/* Scroll end clears the iPhone's rounded corners / home bar even when the pagination bar (which
   carries the safe-area padding) is hidden on a one-page table. A spacer, not padding: scroll
   containers don't reliably count bottom padding past a table. */
.db-content::after {
    content: "";
    display: block;
    height: calc(12px + env(safe-area-inset-bottom, 0px));
}

/* SQL query window + saved queries (static/js/db-admin.js: dbSelectQuery). */
.db-query-item { font-weight: 600; border-bottom: 1px solid var(--border); }
.dbq-pane { flex: 1; flex-direction: column; min-height: 0; overflow: hidden; }
.dbq-body {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 14px 16px calc(16px + env(safe-area-inset-bottom, 0px));
}
.dbq-saved { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.dbq-saved-label {
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.7px;
    color: var(--text-muted);
    margin-right: 4px;
}
.dbq-saved-empty { font-size: 12px; font-style: italic; color: var(--text-muted); }
.dbq-chip {
    appearance: none;
    font-size: 12px;
    font-weight: 600;
    color: var(--text-secondary);
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 5px 11px;
    cursor: pointer;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    transition: color 0.12s ease, background 0.12s ease, border-color 0.12s ease;
}
.dbq-chip:hover { color: var(--text-primary); border-color: var(--text-muted); }
.dbq-chip.active { color: #fff; background: var(--accent); border-color: var(--accent); }
.dbq-name, .dbq-sql {
    width: 100%;
    box-sizing: border-box;
    padding: 9px 11px;
    font-size: 13px;
    color: var(--text-primary);
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 8px;
}
.dbq-name:focus, .dbq-sql:focus { outline: none; border-color: var(--accent); }
.dbq-sql {
    min-height: 140px;
    resize: vertical;
    line-height: 1.5;
    tab-size: 4;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.dbq-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.dbq-hint { font-size: 11px; color: var(--text-muted); }
.dbq-spacer { flex: 1; }
.dbq-del:hover { color: #f87171; }
.dbq-err { font-size: 12.5px; color: #f87171; white-space: pre-wrap; }
.dbq-meta { font-size: 12px; color: var(--text-muted); }
.dbq-err:empty, .dbq-meta:empty, .dbq-result:empty { display: none; }
.dbq-result {
    flex-shrink: 0;
    max-height: 65vh;
    overflow: auto;
    border: 1px solid var(--border);
    border-radius: 10px;
}
@media (max-width: 700px) {
    .dbq-body { padding-left: calc(12px + env(safe-area-inset-left, 0px)); padding-right: calc(12px + env(safe-area-inset-right, 0px)); }
    .dbq-hint { display: none; }
    /* 16px: below that, iOS Safari zooms the page on focus. */
    .dbq-name, .dbq-sql { font-size: 16px; }
    .dbq-actions { gap: 6px; }
    .dbq-actions .btn-sm { padding: 7px 10px; }
}

.db-grid {
    width: 100%;
    border-collapse: collapse;
    font-size: 12px;
}

.db-grid th {
    position: sticky;
    top: 0;
    z-index: 10;
    background: var(--bg-secondary);
    padding: 7px 10px;
    text-align: left;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--text-muted);
    border-bottom: 2px solid var(--border);
    white-space: nowrap;
}

.db-grid th.pk {
    color: var(--accent-light);
}

.db-grid td {
    padding: 5px 10px;
    border-bottom: 1px solid var(--border);
    color: var(--text-secondary);
    vertical-align: middle;
    max-width: 240px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.db-grid tr:hover td {
    background: rgba(255, 255, 255, .03);
}

/* Cell opened by a click (db-admin.js): full value, over several lines. */
.db-grid td.db-cell-open {
    white-space: pre-wrap;
    word-break: break-word;
    overflow: visible;
    max-width: 520px;
    min-width: 260px;
    vertical-align: top;
    color: var(--text-primary);
}

.db-grid td.db-null {
    color: var(--text-muted);
    font-style: italic;
    font-size: 11px;
}

.db-grid td.db-pk {
    color: var(--accent-light);
    font-size: 11px;
    font-weight: 600;
}

.db-grid td.db-editing {
    padding: 0;
}

.db-grid td.db-editing input {
    width: 100%;
    padding: 5px 10px;
    background: var(--bg-primary);
    border: none;
    outline: 2px solid var(--accent-light);
    color: var(--text-primary);
    font-size: 12px;
    font-family: inherit;
}

.db-actions-col {
    width: 56px;
    text-align: right;
    white-space: nowrap;
}

.db-row-btn {
    background: none;
    border: none;
    cursor: pointer;
    padding: 2px 4px;
    border-radius: 4px;
    font-size: 12px;
    color: var(--text-muted);
    transition: background .1s, color .1s;
}

.db-row-btn:hover {
    background: var(--bg-primary);
    color: var(--text-primary);
}

.db-row-btn.db-del:hover {
    color: #f87171;
}

.db-empty {
    padding: 40px;
    text-align: center;
    color: var(--text-muted);
    font-style: italic;
    font-size: 13px;
}

.db-pagination {
    padding: 7px 16px;
    border-top: 1px solid var(--border);
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 12px;
    color: var(--text-muted);
    background: var(--bg-card);
    flex-shrink: 0;
}

/* Phone: one pane at a time, full width (tables, then the chosen table). */
@media (max-width: 700px) {
    .db-admin-header {
        padding-left: calc(14px + env(safe-area-inset-left, 0px)) !important;
        padding-right: calc(14px + env(safe-area-inset-right, 0px)) !important;
    }

    .db-demo-text { display: none; }

    .db-admin-title {
        font-size: 14px !important;
        min-width: 0;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    .db-admin-body .db-sidebar {
        width: 100%;
        min-width: 0;
        border-right: none;
        padding-bottom: env(safe-area-inset-bottom, 0px);
    }

    .db-admin-body .db-main {
        display: none;
    }

    .db-admin-body.db-show-table .db-sidebar {
        display: none;
    }

    .db-admin-body.db-show-table .db-main {
        display: flex;
    }

    .db-back-btn {
        display: inline-flex;
    }

    .db-tbl-item {
        padding: 12px 16px;
        font-size: 15px;
    }

    .db-tbl-count {
        font-size: 12px;
    }

    .db-toolbar {
        padding: 8px 12px;
    }

    .db-pagination {
        padding-bottom: calc(8px + env(safe-area-inset-bottom, 0px)) !important;
    }
}

/* ── Team Draft Modal ─────────────────────────────────────────────────── */

/* Pool panel */
.td-pool-panel {
    width: 240px;
    min-width: 200px;
    flex-shrink: 0;
    border-right: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    background: var(--bg-secondary);
}

.td-pool-hdr {
    padding: 10px 14px;
    flex-shrink: 0;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--text-muted);
    border-bottom: 1px solid var(--border);
}

.td-pool-search {
    width: 100%;
    box-sizing: border-box;
    padding: 6px 10px;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 6px;
    color: var(--text-primary);
    font-size: 12px;
    font-family: inherit;
    flex-shrink: 0;
}

.td-pool-search:focus {
    outline: none;
    border-color: var(--accent);
}

.td-pool-list {
    flex: 1;
    overflow-y: auto;
    padding: 8px 10px;
}

.td-pool-footer {
    padding: 10px 12px;
    border-top: 1px solid var(--border);
    flex-shrink: 0;
}

.td-add-toggle {
    font-size: 12px;
    color: var(--accent-light);
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 5px;
    user-select: none;
}

.td-add-icon {
    font-size: 16px;
    line-height: 1;
}

/* Chips (draggable player rows) */
.td-chip {
    margin-bottom: 3px;
    border: 1px solid var(--border);
    border-radius: 8px;
    cursor: grab;
    user-select: none;
    transition: border-color .1s, background .1s;
}

.td-chip * {
    pointer-events: none;
}

.td-chip:hover {
    border-color: var(--accent-light);
}

.td-chip-pool {
    padding: 8px 10px;
    background: var(--bg-card);
    font-size: 13px;
    color: var(--text-primary);
}

.td-chip-pool:hover {
    background: var(--bg-hover);
}

.td-chip-other {
    padding: 7px 10px;
    background: var(--bg-primary);
    font-size: 13px;
    color: var(--text-muted);
}

.td-chip-other:hover {
    background: var(--bg-card);
}

.td-chip-team {
    padding: 7px 10px;
    background: var(--bg-primary);
    font-size: 12px;
    color: var(--text-primary);
    border-radius: 6px;
}

.td-chip-team:hover {
    border-color: var(--accent-light);
}

.td-chip-team.td-reorder-active {
    border-color: var(--accent-light);
    background: var(--bg-hover);
}

.td-reorder-btns {
    display: none;
}

/* Team columns */
[data-team="1"] {
    --team-color: #3b82f6;
}

[data-team="2"] {
    --team-color: #22c55e;
}

[data-team="3"] {
    --team-color: #f59e0b;
}

[data-team="4"] {
    --team-color: #ef4444;
}

.td-team-col {
    background: var(--bg-card);
    border: 2px solid var(--border);
    border-top: 3px solid var(--team-color);
    border-radius: 10px;
    padding: 12px;
    display: flex;
    flex-direction: column;
    transition: border-color .15s, background .15s;
}

.td-team-col.td-drag-over {
    border-color: var(--accent-light);
    background: var(--bg-hover);
}

/* Simple player list (schedule modal): reorder by drag and drop, same mechanism as the
   team draft columns (insertion line + highlight). */
.schedule-flat-row {
    border: 1px solid transparent;
    border-radius: 6px;
    transition: border-color .1s, background .1s;
}

.schedule-flat-row:hover {
    border-color: var(--border);
}

.schedule-drag-handle {
    cursor: grab;
    color: var(--text-muted);
    font-size: 12px;
    flex-shrink: 0;
}

/* Substitute inserted in the "Present" list, distinct from the regulars. */
.schedule-sub-row {
    border-left: 2px solid var(--gold);
    background: rgba(245, 158, 11, .08);
}

.schedule-sub-row:hover {
    border-color: var(--gold);
}

.schedule-sub-badge {
    font-size: 9px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--gold);
    background: rgba(245, 158, 11, .15);
    border-radius: 4px;
    padding: 1px 5px;
    flex-shrink: 0;
}

#schedule-player-checkboxes {
    border: 2px solid transparent;
    transition: border-color .1s;
}

#schedule-player-checkboxes.td-drag-over {
    border-color: var(--accent-light);
}

.td-team-hdr {
    display: flex;
    align-items: center;
    margin-bottom: 10px;
    gap: 6px;
}

.td-team-name {
    font-size: 13px;
    font-weight: 700;
    color: var(--team-color);
    cursor: pointer;
    flex: 1;
}

.td-team-count {
    font-size: 11px;
    color: var(--text-muted);
    pointer-events: none;
}

.td-captain-row {
    display: flex;
    align-items: center;
    gap: 5px;
    margin-bottom: 8px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--border);
}

.td-captain-icon {
    font-size: 13px;
    flex-shrink: 0;
}

.td-captain-select {
    flex: 1;
    font-size: 16px;
    font-weight: 600;
    font-family: inherit;
    background: var(--bg-card);
    color: var(--text-primary);
    border: 0;
    border-radius: 6px;
    padding: 6px 8px;
    cursor: pointer;
}

.td-captain-none {
    font-size: 11px;
    color: var(--text-muted);
    font-style: italic;
}

.td-captain-empty {
    border: 1px dashed var(--border);
    border-radius: 6px;
    padding: 7px 10px;
    font-size: 12px;
    color: var(--text-muted);
    font-style: italic;
    pointer-events: none;
}

.td-divider {
    height: 1px;
    background: var(--border);
    margin: 8px 0;
    pointer-events: none;
}

.td-insert-line {
    height: 2px;
    background: var(--accent-light);
    border-radius: 1px;
    margin: 2px 0;
    pointer-events: none;
}

/* Confirm close dialog */
.td-confirm-box {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 24px 28px;
    width: 320px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, .4);
}

/* ── Mobile tab bar ── */
.td-mobile-tabs {
    display: none;
    flex-shrink: 0;
}

/* ── Mobile bottom sheet ── */
.td-sheet-overlay {
    position: fixed;
    inset: 0;
    z-index: 4000;
    display: flex;
    align-items: flex-end;
    background: rgba(0, 0, 0, .45);
}

.td-sheet {
    background: var(--bg-card);
    border-radius: 16px 16px 0 0;
    padding: 16px 12px calc(env(safe-area-inset-bottom, 0px) + 16px);
    width: 100%;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.td-sheet-title {
    font-size: 14px;
    font-weight: 700;
    color: var(--text-primary);
    padding: 0 4px 10px;
    border-bottom: 1px solid var(--border);
    margin-bottom: 4px;
}

.td-sheet-btn {
    width: 100%;
    padding: 13px 16px;
    border-radius: 10px;
    border: 1px solid var(--border);
    background: var(--bg-secondary);
    color: var(--text-primary);
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    font-family: inherit;
    text-align: left;
    -webkit-tap-highlight-color: transparent;
}

.td-sheet-btn:active {
    background: var(--bg-hover);
}

.td-sheet-btn-danger {
    color: #ef4444;
    border-color: rgba(239, 68, 68, .3);
}

.td-sheet-cancel {
    color: var(--text-muted);
    margin-top: 4px;
    background: transparent;
}

/* ── Responsive: mobile layout ── */
@media (max-width: 599px) {

    /* Show tab bar */
    .td-mobile-tabs {
        display: flex;
        border-top: 1px solid var(--border);
        background: var(--bg-card);
        padding-bottom: env(safe-area-inset-bottom, 0px);
    }

    .td-tab {
        flex: 1;
        padding: 8px 4px;
        font-size: 11px;
        font-weight: 600;
        border: none;
        border-top: 2px solid transparent;
        background: transparent;
        color: var(--text-muted);
        cursor: pointer;
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 2px;
        font-family: inherit;
        transition: color .15s, border-color .15s;
        -webkit-tap-highlight-color: transparent;
    }

    .td-tab-icon {
        font-size: 14px;
    }

    .td-tab.td-tab-active {
        color: var(--accent-light);
        border-top-color: var(--accent-light);
    }

    .td-tab-badge {
        font-size: 10px;
        font-weight: 700;
        background: rgba(255, 255, 255, .18);
        color: rgba(255, 255, 255, .85);
        border-radius: 10px;
        padding: 0 6px;
        min-width: 18px;
        text-align: center;
        line-height: 17px;
    }

    .td-tab.td-tab-active .td-tab-badge {
        background: var(--accent);
        color: #fff;
    }

    /* Vertical body layout */
    #td-body {
        flex-direction: column;
    }

    /* Pool: full width */
    .td-pool-panel {
        width: 100% !important;
        min-width: 0 !important;
        border-right: none !important;
        border-bottom: 1px solid var(--border);
        max-height: 100%;
    }

    /* Teams wrap: single column grid */
    #td-teams-wrap {
        padding: 12px !important;
    }

    #td-teams-grid {
        grid-template-columns: 1fr !important;
        min-width: 0 !important;
        gap: 10px !important;
    }

    /* Team chips: bigger tap targets, no hover border on touch */
    .td-chip-team {
        padding: 11px 12px !important;
        font-size: 14px !important;
        display: flex !important;
        align-items: center !important;
    }

    .td-chip-team:hover {
        border-color: var(--border);
    }

    .td-chip-pool {
        padding: 11px 12px !important;
        font-size: 14px !important;
    }

    /* Re-enable pointer events on interactive children (overrides .td-chip * rule) */
    .td-chip-label,
    .td-reorder-btn {
        pointer-events: auto;
    }

    .td-chip-label {
        flex: 1;
        min-width: 0;
        cursor: pointer;
        padding: 6px 0;
    }

    .td-reorder-btns {
        display: flex;
        flex-direction: row;
        align-items: center;
        gap: 6px;
        margin-left: 10px;
        flex-shrink: 0;
    }

    .td-reorder-btn {
        background: rgba(255, 255, 255, .15);
        border: none;
        border-radius: 6px;
        color: inherit;
        cursor: pointer;
        font-size: 20px;
        line-height: 1;
        width: 36px;
        height: 36px;
        display: flex;
        align-items: center;
        justify-content: center;
        -webkit-tap-highlight-color: transparent;
        touch-action: manipulation;
    }

    .td-reorder-btn:active {
        background: rgba(255, 255, 255, .35);
    }

    .td-reorder-gap {
        display: block;
        width: 36px;
        height: 36px;
    }

    /* Simple list (schedule modal): the drag handle is useless on touch; the ↑/↓ buttons are enough. */
    .schedule-drag-handle {
        display: none;
    }

    /* Panels hidden by JS when not active tab */
    .td-panel-hidden {
        display: none !important;
    }

    .td-team-col.td-team-hidden {
        display: none !important;
    }
}

/* ── Pools tab (Bad Boys league) ────────────────────────────────────── */
.pools-toolbar {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 14px;
    flex-wrap: wrap;
}

.pools-toolbar input[type="date"] {
    background: var(--bg-card);
    color: var(--text-primary);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 6px 10px;
    font-family: inherit;
}

.pools-hint {
    color: var(--text-muted);
    font-size: 13px;
    margin-bottom: 12px;
}

.pools-error {
    color: #f87171;
    font-weight: 600;
    font-size: 13px;
    margin: 8px 0;
}

/* Two columns: "Joueurs disponibles" (available players) on the left, and one box on
   the right grouping the 3 pools stacked (Pool A above Pool B above Pool C). */
.pools-layout {
    display: flex;
    gap: 16px;
    align-items: flex-start;
    flex-wrap: wrap;
}

.pool-box {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 10px 12px;
    min-height: 56px;
}

.pool-box.pool-unassigned {
    flex: 0 0 220px;
}

.pool-box.drag-over {
    border-color: var(--accent);
    background: var(--bg-hover);
}

.pool-box h4 {
    margin: 0 0 8px;
    font-size: 13px;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: .04em;
}

.pool-box.pool-unassigned h4 {
    color: var(--text-muted);
}

/* The box grouping the 3 pools owns the visual frame; each pool inside (.pool-section)
   has no frame of its own, only a separator from the previous pool. */
.pools-group-box {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 14px;
    flex: 1 1 320px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.pool-box.pool-section {
    background: transparent;
    border: none;
    border-radius: 0;
    padding: 0;
    min-height: 0;
}

.pool-box.pool-section+.pool-box.pool-section {
    border-top: 1px solid var(--border);
    padding-top: 14px;
}

/* Vertical list of players (not a horizontal row). */
.pool-chip-row {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-height: 34px;
}

.pool-chip {
    display: flex;
    align-items: center;
    gap: 8px;
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: 7px;
    padding: 6px 10px;
    cursor: grab;
    font-size: 13px;
    color: var(--text-primary);
}

.pool-chip:active {
    cursor: grabbing;
}

.pool-chip .pool-chip-pos {
    color: var(--accent-light);
    font-weight: 700;
    font-size: 11px;
    width: 18px;
    text-align: center;
    flex-shrink: 0;
}

.pools-readonly .pool-chip {
    cursor: default;
}

/* "Present" (top) and "Absent" (bottom) sections in the left box: same principle as the evening schedule. */
.pool-chip-absent {
    opacity: .5;
    cursor: default;
}

.pool-chip .pool-present-toggle {
    width: 14px;
    height: 14px;
    cursor: pointer;
    accent-color: var(--accent);
    flex-shrink: 0;
}

.pools-sep {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 8px 0 2px;
}

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

.pools-sep span {
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--text-muted);
}

/* ── Guided tour (static/js/tour.js) ──
   #tour-root covers the screen and blocks clicks on the app. The highlighted spot
   (.tour-spot) darkens the rest with a huge box-shadow. With no target (centred step),
   .tour-dim darkens the whole screen. */
#tour-root {
    position: fixed;
    inset: 0;
    z-index: 5000;
    -webkit-user-select: none;
    user-select: none;
}

#tour-root.tour-dim {
    background: rgba(0, 0, 0, .65);
}

.tour-spot {
    position: fixed;
    border-radius: 12px;
    box-shadow: 0 0 0 9999px rgba(0, 0, 0, .65);
    outline: 2px solid var(--accent);
    pointer-events: none;
    transition: left .2s, top .2s, width .2s, height .2s;
}

.tour-bubble {
    position: fixed;
    width: min(340px, calc(100vw - 32px));
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 16px 18px 14px;
    box-shadow: 0 12px 32px rgba(0, 0, 0, .5);
    color: var(--text-primary);
}

.tour-count {
    font-size: 11px;
    font-weight: 600;
    color: var(--text-muted);
    margin-bottom: 4px;
}

/* Optional icon above the title (tour.js: step.icon, e.g. the swipe gesture). */
.tour-icon {
    color: var(--accent-light);
    margin: 2px 0 6px;
    line-height: 0;
}

.tour-title {
    font-size: 16px;
    font-weight: 700;
    margin-bottom: 6px;
}

.tour-text {
    font-size: 14px;
    line-height: 1.5;
    color: var(--text-secondary);
}

/* Demo in progress (e.g. the filters of the recent standings). */
.tour-demo {
    margin-top: 10px;
    font-size: 12px;
    font-weight: 600;
    color: var(--accent-light);
}

/* Button "tapped" by the demo. */
.tour-tap {
    outline: 3px solid var(--accent) !important;
    outline-offset: 2px;
    animation: tour-tap .9s ease-out;
}

@keyframes tour-tap {
    0% { transform: scale(1); }
    25% { transform: scale(.9); }
    60% { transform: scale(1.05); }
    100% { transform: scale(1); }
}

.tour-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 14px;
}

.tour-actions .btn {
    padding: 7px 14px;
    font-size: 13px;
}

.tour-skip {
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 13px;
    cursor: pointer;
    padding: 7px 0;
    font-family: inherit;
}


/* ── Help & support: collapsible sections (templates/index.html) ── */
/* Desktop: the title stays in place and only the help scrolls below it (the page
   scrolls in the window, where a sticky title would not hold: .main-content has
   overflow:auto). On mobile the title is fixed (.page-title-bar, mobile block) and
   the page scrolls normally. */
@media (min-width: 769px) and (min-height: 501px), (min-width: 769px) and (pointer: fine) {
    #support-panel .has-fixed-title {
        display: flex;
        flex-direction: column;
        height: calc(100vh - var(--app-top, 68px) - 44px);
    }

    #support-panel .page-title-bar {
        flex: none;
    }

    #support-panel .help-scroll {
        flex: 1;
        min-height: 0;
        overflow-y: auto;
        padding-right: 6px;
    }
}

.help-intro {
    margin-bottom: 14px;
}
.help-intro .help-tour-btn + .help-tour-btn { margin-left: 8px; }
.info-back-btn { font-size: 13px; padding: 6px 12px; margin-bottom: 16px; }

.help-intro p {
    margin: 0 0 10px;
    color: var(--text-secondary);
    font-size: 14px;
}

.help-item {
    scroll-margin: 0;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 12px;
    margin-bottom: 8px;
    overflow: hidden;
}

.help-item summary {
    list-style: none;
    cursor: pointer;
    padding: 14px 16px;
    font-size: 15px;
    font-weight: 600;
    color: var(--text-primary);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    -webkit-tap-highlight-color: transparent;
    -webkit-user-select: none;
    user-select: none;
}

.help-summary-label,
.help-title,
.help-tour-btn {
    display: inline-flex;
    align-items: center;
    gap: 10px;
}

.help-tour-btn {
    gap: 8px;
}

.help-item summary .help-icon {
    color: var(--accent-light);
    flex: none;
}

.help-item summary::-webkit-details-marker {
    display: none;
}

.help-item summary::after {
    content: '▾';
    color: var(--text-muted);
    transition: transform .15s;
}

.help-item[open] summary::after {
    transform: rotate(180deg);
}

/* An open section: space under the list so it can scroll to the top, even when it is the last one (static/js/app/, toggle .help-item). */
#support-panel.help-open .help-scroll {
    padding-bottom: 75vh;
}

.help-body {
    padding: 0 16px 12px;
    border-top: 1px solid var(--border);
}

.help-body p {
    margin: 12px 0 0;
    font-size: 14px;
    line-height: 1.55;
    color: var(--text-secondary);
}

.help-body strong {
    color: var(--text-primary);
}

.help-contacts {
    margin: 8px 0 0;
    padding-left: 18px;
    font-size: 14px;
    line-height: 1.6;
    color: var(--text-secondary);
}

.help-contacts a {
    color: var(--accent-light);
    word-break: break-word;
}

.help-contacts li {
    margin-bottom: 6px;
}

/* Email: icon only (the address is not shown), with a comfortable tap area. */
.help-mail-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    margin-left: 4px;
    vertical-align: middle;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--bg-secondary);
}


/* Count of present players in the "Planned attendance" header (leagues.html). */
/* "Relancer" the players without an answer (push), under the planned attendance list. */
.date-attendance-remind {
    padding: 12px 14px 0;
    border-top: 1px solid var(--border);
    margin-top: 4px;
}
.date-attendance-remind .btn {
    width: 100%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    font-size: 13px;
}

.date-attendance-count {
    margin-left: auto;
    padding-left: 10px;
    white-space: nowrap;
    font-weight: 600;
    opacity: .85;
    text-transform: none;
    letter-spacing: 0;
}

.date-attendance-count + .btn {
    margin-left: 10px;
}


/* Name, with the starting rating (new player, Elo mode) underneath. */
.date-attendance-who {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
}

.date-attendance-seed {
    font-size: 11px;
    font-weight: 600;
    color: var(--accent-light);
    background: rgba(232, 97, 26, .12);
    border-radius: 6px;
    padding: 1px 6px;
}


/* Role badge (A/G/P/M/I) next to the user's name. */
.role-chip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    border: 1.5px solid var(--accent);
    color: var(--accent-light);
    font-size: 11px;
    font-weight: 700;
    line-height: 1;
    margin-left: 6px;
}


/* Rencontres: league name and session picker on the same line (wraps if the screen is too narrow). */
.league-header.league-header-session {
    justify-content: flex-start;
    flex-wrap: wrap;
    column-gap: 14px;
    row-gap: 6px;
    margin-bottom: 12px;
}

.league-header-session .session-bar {
    padding: 0;
    flex: 1 1 200px;
    min-width: 0;
    flex-wrap: nowrap;
}

/* The session list shrinks (text cut with "…") rather than wrapping the whole bar;
   it fits beside the name on a phone. */
.league-header-session #sidebar-session-wrap {
    flex: 0 1 auto;
    min-width: 110px;
}

.league-header-session #sidebar-session-select {
    /* Natural width (the option text): inside a container sized by it, width:100%
       cut the text even when there was room. */
    width: auto !important;
    max-width: 100%;
    min-width: 0;
    text-overflow: ellipsis;
}

/* Phone: tighter spacing so the full session name fits beside the league name. */
@media (max-width: 768px) {
    .league-header.league-header-session {
        column-gap: 10px;
    }

    .league-header-session .session-bar {
        gap: 4px;
    }

    .league-header-session #sidebar-session-select {
        padding-left: 8px;
        padding-right: 4px;
        font-size: 13px;
    }

    .league-header-session .session-add-btn {
        padding: 4px 8px;
    }
}


/* League window: session management buttons. */
.info-session-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 8px;
}

.info-session-actions .btn {
    font-size: 13px;
    padding: 6px 12px;
}


/* Collapsible waves (Rencontres), static/js/app/attendance.js: toggleWave. */
.wave-toggle {
    cursor: pointer;
    -webkit-user-select: none;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
}

.wave-toggle.match-wave-label,
.wave-toggle > div {
    display: flex;
    align-items: center;
    gap: 8px;
}

.wave-count {
    font-family: inherit;
    font-size: .85em;
    font-weight: 600;
    letter-spacing: 0;
    text-transform: none;
    opacity: 0;
    transition: opacity .15s;
}

.wave-collapsed .wave-count {
    opacity: .75;
}

.wave-chevron {
    margin-left: auto;
    font-size: 1.2em;
    letter-spacing: 0;
    transition: transform .15s;
}

.wave-collapsed .wave-chevron {
    transform: rotate(-90deg);
}

/* Guest in all their leagues: no chat, so the tab is hidden (chat_allowed, web/pages.py:index). */
body.no-chat #nav-chat,
body.no-chat #mob-tab-chat {
    display: none !important;
}

/* Face ID: help shown when activation is refused or impossible (e.g. the Facebook in-app
   browser). Plain text, not a red error. */
.passkey-help {
    font-size: 12px;
    line-height: 1.5;
    color: var(--text-secondary);
    background: var(--surface2);
    border-radius: 8px;
    padding: 8px 10px;
}

/* Scores from a photo of the sheet (📷): status strip on the schedule card; doubtful
   scores in yellow (static/js/app/score-photos.js, _applyProposedScores). */
.score-photo-strip {
    margin: 8px 10px 0;
    padding: 8px 10px;
    border-radius: 8px;
    background: var(--surface2);
    color: var(--text-secondary);
    font-size: 12px;
    line-height: 1.5;
}

.score-photo-spinner {
    display: inline-block;
    width: 12px;
    height: 12px;
    margin-right: 8px;
    vertical-align: -2px;
    border: 2px solid var(--border);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: ptr-spin .8s linear infinite;
}

.score-photo-size {
    color: var(--text-muted);
}

.score-photo-bar {
    display: block;
    height: 4px;
    margin-top: 6px;
    border-radius: 2px;
    background: var(--border);
    overflow: hidden;
}

.score-photo-bar > span {
    display: block;
    height: 100%;
    background: var(--accent);
    transition: width .15s ease;
}

.score-photo-strip.done {
    background: rgba(99, 102, 241, .15);
    color: var(--text);
}

.score-photo-strip.error {
    background: rgba(239, 68, 68, .12);
    color: var(--text);
}

.score-photo-link {
    color: var(--accent);
    white-space: nowrap;
}

/* ✓ on each match read from the photo (score-photos.js: _addPhotoCheck), between the
   names and the scores; green once the manager has checked the score. */
.match-card.photo-check {
    position: relative;
    transition: border-color .15s ease;
}

.match-card.photo-check .match-players {
    padding-right: 36px;
}

.photo-check-btn {
    position: absolute;
    top: 50%;
    right: 58px;
    transform: translateY(-50%);
    width: 30px;
    height: 30px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border-radius: 50%;
    border: 1.5px solid var(--border);
    background: var(--bg-card);
    color: var(--text-muted);
    cursor: pointer;
    transition: background .15s ease, color .15s ease, border-color .15s ease;
}

.match-card.photo-checked {
    border-color: rgba(34, 197, 94, .55);
}

.match-card.photo-checked .photo-check-btn {
    background: var(--green);
    border-color: var(--green);
    color: #fff;
}

.photo-finalize-bar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 16px;
    z-index: 900;
    display: flex;
    justify-content: center;
    padding: 0 16px;
    pointer-events: none;
}

.photo-finalize-bar .btn {
    pointer-events: auto;
}

/* Room under the last match, so the fixed button never hides it. */
.draft-schedule-card.has-finalize-bar {
    padding-bottom: 72px;
}

.photo-finalize-bar .btn {
    width: 100%;
    max-width: 360px;
    padding: 12px 16px;
    font-size: 15px;
    font-weight: 700;
    box-shadow: 0 8px 24px rgba(0, 0, 0, .45);
}

.score-photo-count {
    color: var(--text-muted);
    white-space: nowrap;
}

.score-photo-count.all {
    color: var(--green);
    font-weight: 700;
}

@media (max-width: 768px), (max-height: 500px) and (pointer: coarse) {
    .photo-check-btn {
        right: 66px;
    }

    /* Above the bottom nav (64px + the iPhone home bar). */
    .photo-finalize-bar {
        bottom: calc(76px + env(safe-area-inset-bottom, 0px));
    }
}

.draft-score-input.score-doubt {
    background: rgba(250, 204, 21, .28);
    border-radius: 5px;
}

/* ── Ask BadZone: questions to the AI (static/js/app/ai.js: selectAiPanel) ── */
#ai-panel {
    max-width: 720px;
}

.ai-league-name {
    color: var(--text-secondary);
    font-size: 13px;
    margin: -4px 0 12px;
}

/* Title and league choice stay fixed while scrolling. Desktop: the page scrolls.
   .main-content (overflow:auto, but never itself scrolling) would stop position:sticky,
   so it is reset to visible while the AI panel is open (body.ai-open). Mobile: see the
   fixed rule below. */
body.ai-open .main-content {
    overflow: visible;
}

.ai-top {
    position: sticky;
    /* Just below the fixed app header. */
    top: var(--app-top, 68px);
    z-index: 20;
    background: var(--bg-primary);
    padding-top: 10px;
    margin-top: -10px;
}

.ai-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin: -4px 0 12px;
}

.ai-toolbar .ai-league-name {
    margin: 0;
    min-width: 0;
}

.ai-clear {
    display: flex;
    align-items: center;
    gap: 5px;
    padding: 6px 10px;
    font-size: 13px;
    flex: 0 0 auto;
}

.ai-league-select {
    width: auto;
    max-width: 100%;
    font-size: 15px;
    padding: 6px 10px;
}

.ai-thread {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding-bottom: 12px;
}

.ai-thread .chat-message {
    max-width: 88%;
}

.ai-hint {
    color: var(--text-secondary);
    font-size: 14px;
    padding: 12px 2px;
}

.ai-suggestions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 4px;
}

.ai-chip {
    font: inherit;
    font-size: 13px;
    padding: 7px 12px;
    border-radius: 999px;
    border: 1px solid var(--border);
    background: var(--bg-secondary);
    color: var(--text-primary);
    cursor: pointer;
}

.ai-chip:hover {
    border-color: var(--accent-light);
}

/* Input area pinned to the bottom of the screen (above the mobile bar). */
.ai-compose {
    position: sticky;
    bottom: 0;
    display: flex;
    gap: 8px;
    align-items: flex-end;
    padding: 10px 0;
    background: var(--bg-primary);
}

.ai-input {
    flex: 1;
    font-size: 16px;
}

/* Voice button (icon only), next to the input. */
.ai-voice-toggle {
    flex: 0 0 auto;
    width: 44px;
    height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 12px;
    border: 1px solid var(--border);
    background: var(--bg-secondary);
    color: var(--text-muted);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.ai-voice-toggle.on {
    color: var(--accent-light);
    border-color: var(--accent-light);
}

/* Dictation not available on this device: crossed-out, greyed-out mic. */
.ai-mic.unavailable {
    opacity: .45;
}

/* Help to enable the microphone (static/js/app/ai.js: _aiMicHelp). */
.ai-mic-help-body {
    padding: 14px 16px 16px;
    font-size: 15px;
    line-height: 1.5;
    color: var(--text-secondary);
}

.ai-mic-help-body p {
    margin: 0 0 8px;
    color: var(--text-primary);
}

.ai-mic-help-body ol {
    margin: 0 0 14px;
    padding-left: 20px;
}

.ai-mic-help-body li {
    margin-bottom: 6px;
}

.ai-mic-help-body .btn {
    width: 100%;
}

/* Microphone listening: pulsing red. */
.ai-mic.listening {
    color: #fff;
    background: var(--red);
    border-color: var(--red);
    animation: ai-mic-pulse 1.2s infinite;
}

@keyframes ai-mic-pulse {
    0% { box-shadow: 0 0 0 0 rgba(239, 68, 68, .55); }
    70% { box-shadow: 0 0 0 10px rgba(239, 68, 68, 0); }
    100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); }
}

.ai-replay {
    background: none;
    border: none;
    padding: 0 4px;
    color: var(--text-muted);
    cursor: pointer;
    line-height: 0;
}

.ai-replay:hover {
    color: var(--accent-light);
}

.ai-remaining {
    font-size: 12px;
    color: var(--text-muted);
    text-align: right;
    padding-bottom: 8px;
}

.ai-error {
    color: var(--red);
}

.ai-error-detail {
    display: block;
    margin-top: 4px;
    font-size: 11px;
    color: var(--text-muted);
}

/* "BadZone is thinking…": three bouncing dots. */
.ai-typing {
    display: inline-flex;
    gap: 4px;
    padding: 4px 2px;
}

.ai-typing i {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--text-secondary);
    animation: ai-bounce 1.2s infinite ease-in-out;
}

.ai-typing i:nth-child(2) { animation-delay: .15s; }
.ai-typing i:nth-child(3) { animation-delay: .3s; }

@keyframes ai-bounce {
    0%, 80%, 100% { transform: translateY(0); opacity: .4; }
    40% { transform: translateY(-5px); opacity: 1; }
}

/* ── League configuration (static/js/app/league-config.js: selectConfigPanel) ── */
#config-panel {
    max-width: 620px;
}

.config-card {
    padding: 14px 16px;
    margin-bottom: 14px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    align-items: flex-start;
}

.config-card-title {
    font-weight: 700;
    font-size: 15px;
    color: var(--text-primary);
    display: flex;
    align-items: center;
    gap: 8px;
}

.config-row {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 14px;
    color: var(--text-secondary);
}

.config-tag {
    font-size: 11px;
    font-weight: 700;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--bg-hover);
    color: var(--text-secondary);
}

.config-tag.on {
    background: rgba(34, 197, 94, .15);
    color: var(--green);
}

.config-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* AI engine choice, nested under the AI switch of the League card. */
.config-ai-engine {
    box-sizing: border-box;
    width: 100%;
    margin: 0 0 16px;
    padding: 14px 16px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--bg-secondary);
}

.ai-settings-body {
    display: flex;
    flex-direction: column;
    gap: 10px;
    width: 100%;
}

.ai-mode {
    display: block;
    font-size: 14px;
    color: var(--text-primary);
}

/* Settings panel sections: this league, then (admin) every league. */
.config-section-title {
    margin: 24px 0 8px;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--border);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.8px;
    text-transform: uppercase;
    color: var(--text-secondary);
}

.config-section-title:first-child {
    margin-top: 4px;
}

/* "Ask BadZone" group: frames the anecdotes sub-sections so they read as part of Ask BadZone,
   not as top-level Configuration sections. A faint accent wash marks it as Ask territory. */
.config-ask-group {
    margin-top: 24px;
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 2px 16px 16px;
    background: rgba(232, 97, 26, 0.045);
}
.config-ask-group-head {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 14px 0 10px;
    margin-bottom: 4px;
    border-bottom: 1px solid var(--border);
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.4px;
    color: var(--accent, #e8611a);
}
.config-ask-group-head .cfg-icon {
    width: 16px;
    height: 16px;
}
/* Sub-section labels inside the group: no divider line (the frame groups them), tighter rhythm. */
.config-ask-group .config-section-title {
    margin-top: 16px;
    border-bottom: none;
    padding-bottom: 2px;
}
.config-ask-group .config-section-title:first-child {
    margin-top: 10px;
}

.config-league-row {
    width: 100%;
    flex-wrap: wrap;
    margin-bottom: 4px;
}

/* League banner: names the league being configured, so every section below reads as its settings. */
.config-league-banner {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 2px 0 6px;
    padding-bottom: 14px;
    border-bottom: 2px solid var(--border);
}
.config-league-banner-icon {
    font-size: 22px;
    line-height: 1;
}
.config-league-banner .config-league-picker {
    font-size: 20px;
    font-weight: 700;
    color: var(--text-primary);
}
.config-league-banner select.ai-league-select {
    font-size: 20px;
    font-weight: 700;
    color: var(--text-primary);
    background: transparent;
    border: none;
    padding: 2px 4px 2px 0;
    cursor: pointer;
    max-width: 100%;
}
.config-league-banner select.ai-league-select:hover {
    color: var(--accent);
}
.config-league-banner .config-league-edit {
    margin-left: auto;
    flex: 0 0 auto;
}

/* League picker that opens the 3D wheel, styled as a heading (Config banner, Ask scope). */
.league-wheel-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    max-width: 100%;
    background: none;
    border: none;
    padding: 2px 0;
    cursor: pointer;
    color: var(--text-primary);
}
.league-wheel-name {
    font-size: 20px;
    font-weight: 700;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.league-wheel-chevron {
    flex: 0 0 auto;
    width: 18px;
    height: 18px;
    color: var(--text-muted);
    transition: color .12s ease;
}
.league-wheel-btn:hover .league-wheel-name,
.league-wheel-btn:hover .league-wheel-chevron {
    color: var(--accent);
}
/* In the Ask BadZone chat header the scope picker is smaller than a config banner. */
#ai-league-name .league-wheel-name {
    font-size: 16px;
}

/* League edit form, opened from the banner's "Modifier": a card under the banner. */
.config-league-edit-slot {
    width: 100%;
    margin: 0 0 8px;
    padding: 14px 16px 16px;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--bg-card);
}

.config-league-edit {
    margin-left: auto;
}

.config-league-edit.active {
    border-color: var(--accent);
    color: var(--text-primary);
}

/* Sessions, inside the League card above the AI switch (league-config.js: _configSessionsHtml). */
.config-sessions {
    width: 100%;
    margin: 4px 0 8px;
    padding: 12px 0;
    border-top: 1px solid var(--border);
    border-bottom: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.config-sessions-head {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 4px;
}

.config-sessions-head .btn {
    margin-left: auto;
}

.config-session-label {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
}

.config-session-item {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 10px;
    border-radius: 8px;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
}

.config-session-main {
    flex: 1;
    min-width: 0;
}

.config-session-name {
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
    cursor: pointer;
    text-align: left;
}

.config-session-name:hover {
    color: var(--accent-light);
    text-decoration: underline;
}

.config-session-item .config-tag {
    margin-left: 8px;
}

.config-session-item.prep .config-session-name {
    color: var(--text-secondary);
}

.config-session-dates {
    font-size: 12px;
    color: var(--text-muted);
    margin-top: 2px;
}

.config-session-prep {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    color: var(--text-secondary);
    cursor: pointer;
}

.config-session-del {
    padding: 6px 8px;
}

.config-session-del:disabled {
    opacity: 0.35;
    cursor: not-allowed;
}

.league-edit-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 4px;
}

.league-edit-actions #btn-delete {
    margin-left: auto;
}

.config-league-picker {
    font-size: 15px;
    font-weight: 600;
    color: var(--text-primary);
}

.config-section-hint {
    margin: -2px 0 10px;
    font-size: 12px;
    color: var(--text-muted);
}

/* On/off switch: a real checkbox (role="switch") drawn as a track and knob. */
.config-switch {
    position: relative;
    display: flex;
    align-items: center;
    gap: 12px;
    width: fit-content;
    font-size: 14px;
    color: var(--text-primary);
    cursor: pointer;
    margin-bottom: 6px;
}

/* Line icons of the settings panel (league-config.js: _cfgIcon). */
.cfg-icon {
    width: 16px;
    height: 16px;
    flex: none;
}

.cfg-icon-lg {
    width: 20px;
    height: 20px;
}

.cfg-label,
#config-panel .btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.config-section-title.cfg-label {
    display: flex;
}

.cfg-label:not(.btn) > .cfg-icon {
    color: var(--text-secondary);
}

.config-switch-info {
    display: inline-flex;
    color: var(--text-muted);
    cursor: help;
}

.config-switch-info .cfg-icon {
    width: 13px;
    height: 13px;
}

/* Same label width so the switches line up in a column. */
.config-switch > span:first-child {
    min-width: 220px;
}

.switch-input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
}

.switch-track {
    position: relative;
    flex: none;
    width: 44px;
    height: 24px;
    border-radius: 12px;
    background: var(--bg-hover);
    border: 1px solid var(--border);
    transition: background-color 150ms ease, border-color 150ms ease;
}

.switch-track::after {
    content: "";
    position: absolute;
    top: 2px;
    left: 2px;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--text-secondary);
    transition: transform 150ms ease, background-color 150ms ease;
}

.switch-input:checked + .switch-track {
    background: var(--accent);
    border-color: var(--accent);
}

.switch-input:checked + .switch-track::after {
    transform: translateX(20px);
    background: #fff;
}

.switch-input:focus-visible + .switch-track {
    outline: 2px solid var(--accent-light);
    outline-offset: 2px;
}

.ai-mode-hint {
    display: block;
    margin-left: 24px;
    font-size: 12px;
    color: var(--text-muted);
}

.ai-custom-prompt {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.ai-note-group {
    width: 100%;
    padding: 8px 0 4px;
    border-top: 1px solid var(--border);
}

.ai-note-groups {
    width: 100%;
}

.ai-note-groups > .ai-note-group:first-child {
    border-top: none;
}

.ai-note-group-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 6px;
}

.ai-note-group-name {
    font-size: 13px;
    font-weight: 700;
    color: var(--text-primary);
}

.ai-note-row {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    width: 100%;
    font-size: 14px;
    color: var(--text-secondary);
}

.ai-note-text {
    flex: 1;
    min-width: 0;
    padding-top: 6px;
}

/* One bullet per anecdote under the player's name. */
.ai-note-group .ai-note-text {
    position: relative;
    padding-left: 14px;
}

.ai-note-group .ai-note-text::before {
    content: '';
    position: absolute;
    left: 2px;
    top: 14px;
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--accent);
}

.ai-note-text b {
    color: var(--text-primary);
}

.ai-note-btn {
    padding: 4px 8px;
}

/* Individuel "+ New anecdote": players with no anecdote yet, one tap picks (openAiNotePlayerPicker). */
.ai-note-picker {
    display: flex;
    flex-direction: column;
    gap: 8px;
    width: 100%;
}

.ai-note-pick {
    display: flex;
    align-items: center;
    min-height: 36px;
    min-width: 0;
    padding: 0 8px;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: var(--text-primary);
    font: inherit;
    font-size: 14px;
    text-align: left;
    cursor: pointer;
    transition: background .12s ease;
}

.ai-note-pick:hover,
.ai-note-pick:focus-visible {
    background: var(--bg-hover);
}

.ai-note-pick span {
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Anecdotes page: the form opens in the section's slot (league-config.js: openAiNoteForm). */
.ai-note-slot {
    width: 100%;
}

.ai-note-group .ai-note-slot {
    margin: 8px 0 4px;
}

.ai-note-slot:empty {
    display: none;
}

.ai-mode-hint.notes-page-hint {
    margin: 0 0 14px;
}

.ai-note-form {
    display: flex;
    flex-direction: column;
    gap: 8px;
    width: 100%;
}

.ai-note-form-title {
    font-weight: 700;
    font-size: 14px;
    color: var(--text-primary);
    margin-top: 6px;
}

#ai-custom-prompt-view,
.ai-custom-prompt-form {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

#ai-custom-prompt-view .btn {
    align-self: flex-start;
}

.ai-custom-prompt-text {
    white-space: pre-wrap;
    font-size: 14px;
    line-height: 1.5;
    color: var(--text-primary);
    padding: 10px 12px;
    border-radius: 8px;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
}

/* Empty error lines would leave a gap in these flex columns. */
#ai-custom-prompt-error:empty,
#ai-settings-error:empty,
#ai-note-error:empty {
    display: none;
}

#ai-note-add {
    align-self: flex-start;
    margin-top: 4px;
}

.ai-note-players-label {
    margin-top: 4px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.7px;
    text-transform: uppercase;
    color: var(--text-secondary);
}

/* Players to tick (group anecdote), scrollable list. */
/* Rows keep their height (grid-auto-rows): with the scroll box, iOS Safari otherwise
   crushed them, the names overlapped and nobody could be ticked. */
.ai-note-players {
    max-height: 220px;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 4px 10px;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    grid-auto-rows: minmax(36px, auto);
    gap: 0 10px;
}

.ai-note-player {
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 36px;
    min-width: 0;
    font-size: 14px;
    color: var(--text-primary);
    cursor: pointer;
}

.ai-note-player input {
    flex-shrink: 0;
    width: 18px;
    height: 18px;
    margin: 0;
    accent-color: var(--accent);
}

.ai-note-player span {
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.ai-limit-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    font-size: 14px;
    color: var(--text-primary);
}

.ai-limit {
    width: 90px;
    text-align: center;
}

@media (max-width: 768px), (max-height: 500px) and (pointer: coarse) {
    /* Pinned above the mobile bottom bar (64px + the iOS home-indicator area). The page
       scrolls on mobile, not .main-content (its overflow:auto would break position:sticky). */
    .ai-compose {
        position: fixed;
        left: 0;
        right: 0;
        bottom: calc(64px + env(safe-area-inset-bottom, 0px));
        padding: 8px 12px;
        border-top: 1px solid var(--border);
        z-index: 90;
    }

    /* Room for the fixed input area. */
    #ai-panel {
        padding-bottom: 96px;
        padding-top: 104px;
    }

    /* Mobile: the page scrolls (not .main-content), so the title and league choice are
       fixed below the app header (--app-top, static/js/app/layout.js: _syncHeaderHeightVar). */
    .ai-top {
        position: fixed;
        top: var(--app-top, 58px);
        left: 0;
        right: 0;
        margin: 0;
        padding: 12px 12px 0;
        border-bottom: 1px solid var(--border);
        z-index: 90;
    }

    .ai-remaining {
        text-align: left;
    }
}

/* "Ask to join a league" (index.html: #join-request-overlay): name, then "Send" on the right. */
.join-request-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-bottom: 10px;
    max-height: 60vh;
    overflow-y: auto;
}

.join-request-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 10px;
    border-radius: 8px;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
}

.join-request-name {
    flex: 1;
    min-width: 0;
    font-size: 14px;
    color: var(--text-primary);
}

.join-request-btn {
    flex: none;
    font-size: 12px;
    padding: 5px 12px;
}

/* Members (admin), laid out like the players list (static/js/users.js: renderUsersList). */
.mb-count {
    font-size: 14px;
    color: var(--text-muted);
    font-weight: 400;
}

.mb-head-actions {
    display: flex;
    align-items: center;
    gap: 8px;
}

.mb-filters {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin-bottom: 14px;
}

/* Sort Récent / Nom, at the end of the filter row. */
.mb-sort {
    margin-left: auto;
}

.mb-sort .view-toggle-btn {
    width: auto;
    padding: 0 10px;
    font-size: 12px;
}

.mb-boxes {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 5px;
}

.mb-boxes .player-row {
    margin-bottom: 0;
    cursor: pointer;
}

.mb-card .gp-card-body {
    align-items: flex-start;
}

.mb-email {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Member code shown in the Membres list (users.js: _renderMembersRows). */
.mb-code {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 11px;
    letter-spacing: .5px;
    color: var(--text-secondary);
}
.mb-list-name .mb-code { margin-left: 8px; }

.mb-role {
    display: inline-block;
    padding: 1px 7px;
    border-radius: 999px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .3px;
    white-space: nowrap;
    background: var(--surface2);
    color: var(--text-secondary);
}

.mb-role-admin {
    background: rgba(249, 115, 22, .16);
    color: var(--accent-light);
}

.mb-role-gestionnaire {
    background: rgba(167, 139, 250, .16);
    color: #a78bfa;
}

.mb-role-privilegie {
    background: rgba(52, 211, 153, .14);
    color: #34d399;
}

.mb-flags {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 8px;
    margin-top: 3px;
}

.mb-flag {
    font-size: 10px;
    color: #f59e0b;
    white-space: nowrap;
}

.mb-list {
    border: 1px solid var(--border);
    border-radius: 8px;
    overflow: hidden;
}

.mb-list-row {
    display: grid;
    grid-template-columns: minmax(200px, 2fr) 110px minmax(180px, 2fr);
    align-items: center;
    gap: 12px;
    padding: 6px 14px;
    background: var(--bg-secondary);
    border-bottom: 1px solid var(--border);
    font-size: 13px;
    color: var(--text-secondary);
}

.mb-list-row:last-child {
    border-bottom: none;
}

.mb-list-row:not(.mb-list-head) {
    cursor: pointer;
}

.mb-list-row:not(.mb-list-head):hover {
    background: var(--bg-card);
}

.mb-list-row.mb-list-head {
    background: var(--bg-card);
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .5px;
    color: var(--text-muted);
}

.mb-list-name {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.mb-list-name .player-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

@media (max-width: 768px), (max-height: 500px) and (pointer: coarse) {
    /* Two columns on a phone, like the players list: smaller photo, details truncated. */
    .mb-boxes {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .mb-boxes .player-row {
        padding: 10px;
    }

    .mb-boxes .gp-card-body {
        gap: 8px;
    }

    .mb-boxes .player-avatar {
        width: 36px;
        height: 36px;
        font-size: 13px;
        flex: none;
        margin: 0;
    }

    .mb-boxes .gp-card-name {
        font-size: 13px;
    }

    .mb-boxes .mb-email {
        font-size: 11px;
    }

    /* List view on a phone: name and role; the email is in the box view. */
    .mb-list-row {
        grid-template-columns: minmax(0, 1fr) auto;
        gap: 8px;
        padding: 6px 10px;
        font-size: 12px;
    }

    .mb-col-email {
        display: none;
    }
}

/* Member dialog: email and names read-only until "Modifier" (users.js: unlockUserIdentity). */
.um-identity-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

.um-edit-btn {
    padding: 3px 10px;
    font-size: 12px;
    margin-bottom: 4px;
}

.modal-input.um-locked {
    background: transparent;
    border-color: transparent;
    padding-left: 0;
    color: var(--text-primary);
    cursor: default;
}

.modal-input.um-locked:focus {
    outline: none;
    box-shadow: none;
}

/* Member dialog: account type as radio buttons (users.js: setUserModalType). */
.um-types {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-bottom: 12px;
}

.um-type {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 8px 10px;
    border: 1px solid var(--border);
    border-radius: 8px;
    cursor: pointer;
    transition: border-color .12s ease, background .12s ease;
}

.um-type:has(input:checked) {
    border-color: var(--accent);
    background: rgba(249, 115, 22, .08);
}

.um-type input {
    margin: 2px 0 0;
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    accent-color: var(--accent);
}

.um-type-name {
    display: block;
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
}

.um-type-hint {
    display: block;
    font-size: 11px;
    color: var(--text-muted);
    margin-top: 1px;
}

/* Count of accounts to check, on the "À vérifier" filter (users.js: renderUsersList). */
.mb-check-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    margin-left: 4px;
    border-radius: 999px;
    background: #f59e0b;
    color: #1a1200;
    font-size: 11px;
    font-weight: 700;
    line-height: 1;
}

/* Member dialog: "Accès supplémentaire", one switch per extra access (users.js: _userModalGrants). */
.um-grants {
    margin-top: 6px;
}

.um-grant {
    width: 100%;
    box-sizing: border-box;
    padding: 8px 10px;
    border: 1px solid var(--border);
    border-radius: 8px;
}

.um-grant-text {
    flex: 1;
    min-width: 0;
}

/* "+ Ajouter" under a player's last anecdote, aligned with the anecdote text (league-config.js). */
.ai-note-add-more {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin: 4px 0 2px 10px;
    padding: 3px 10px;
    font-size: 12px;
}

/* Anecdote box: ✓ and ✕ icon buttons on the right of the text, stacked. */
.ai-note-edit-row {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    width: 100%;
}

.ai-note-edit-row textarea {
    flex: 1;
    min-width: 0;
    resize: none;
    overflow: hidden;
}

.ai-note-actions {
    display: flex;
    gap: 6px;
    flex: none;
}

/* ✓ in the accent colour, like a primary action, but the size of ✏. */
.ai-note-save {
    color: var(--accent);
    border-color: var(--accent);
}

.ai-note-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 32px;
    padding: 0;
}

.ai-note-icon-btn .cfg-icon {
    width: 18px;
    height: 18px;
    margin: 0;
}

/* Player list of "+ Nouvelle anecdote": its ✕ on the right. */
.ai-note-picker .ai-note-actions {
    justify-content: flex-end;
}


/* Anecdote window: centred in the visible part of the screen, above the keyboard once open.
   The top padding is set by league-config.js (_centerAiNoteModal, visual viewport). */
.modal-overlay.ai-note-modal-overlay {
    align-items: flex-start;
    padding: 0 12px;
}

.modal.ai-note-modal {
    width: min(520px, calc(100vw - 24px));
    padding: 14px 16px;
}

.ai-note-modal .ai-note-form-title {
    margin-bottom: 8px;
}

@media (max-width: 768px), (max-height: 500px) and (pointer: coarse) {
    /* Phones stick windows to the bottom, where the keyboard opens: this one is placed by
       _centerAiNoteModal instead. */
    .modal-overlay.ai-note-modal-overlay {
        align-items: flex-start;
        padding: 0 12px;
    }

    .ai-note-modal-overlay .modal.ai-note-modal {
        border-radius: 14px;
    }
}

/* In the anecdote window: ✓ and ✕ under the text, on the right, larger (easy to tap). */
.ai-note-modal .ai-note-edit-row {
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
}

.ai-note-modal .ai-note-actions {
    justify-content: flex-end;
    gap: 10px;
}

.ai-note-modal .ai-note-btn {
    width: 52px;
    height: 42px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.ai-note-modal .ai-note-btn .cfg-icon {
    width: 22px;
    height: 22px;
}

/* Anecdote window while the iPhone keyboard rises: invisible (still focusable), then shown in
   place (league-config.js: openAiNoteForm). The transition on its position is not needed. */
.ai-note-modal-overlay.ai-note-settling .ai-note-modal {
    opacity: 0;
}

.ai-note-modal-overlay .ai-note-modal {
    transition: opacity .15s ease;
}

/* Player choice of "+ Nouvelle anecdote" (Individuel): a centred window, ✕ in its corner. */
.ai-note-picker-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 8px;
}

/* 3D wheel to choose the player (league-config.js: openAiNotePlayerPicker): five rows visible,
   the centre one large and bold, the others smaller, paler and tilted (set while scrolling). */
.ai-wheel {
    position: relative;
    height: 280px;
    perspective: 600px;
    -webkit-mask-image: linear-gradient(to bottom, transparent, #000 25%, #000 75%, transparent);
    mask-image: linear-gradient(to bottom, transparent, #000 25%, #000 75%, transparent);
}

.ai-wheel-band {
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    height: 56px;
    transform: translateY(-50%);
    border-top: 1px solid var(--border);
    border-bottom: 1px solid var(--border);
    background: rgba(249, 115, 22, .06);
    border-radius: 8px;
    pointer-events: none;
}

.ai-wheel-list {
    height: 100%;
    overflow-y: auto;
    scroll-snap-type: y mandatory;
    padding: 112px 0;
    box-sizing: border-box;
    scrollbar-width: none;
    transform-style: preserve-3d;
}

.ai-wheel-list::-webkit-scrollbar {
    display: none;
}

.ai-wheel-item {
    height: 56px;
    line-height: 56px;
    text-align: center;
    font-size: 21px;
    color: var(--text-secondary);
    scroll-snap-align: center;
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    transform-origin: center center;
    user-select: none;
    -webkit-user-select: none;
}

.ai-wheel-item.active {
    font-size: 27px;
    font-weight: 700;
    color: var(--text-primary);
}

/* Muted tag after a wheel row's name (e.g. "invité" for a league where the account is a guest). */
.ai-wheel-tag {
    margin-left: 8px;
    font-size: 13px;
    font-weight: 500;
    color: var(--text-muted);
}

/* Group caption above the wheel ("Mes ligues" / "Ligues où je joue"): follows the centred row. */
.ai-wheel-group {
    margin: 2px 0 6px;
    text-align: center;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .7px;
    text-transform: uppercase;
    color: rgba(255, 255, 255, .55);
    transition: opacity .15s ease;
}

.ai-wheel-actions {
    justify-content: flex-end;
    margin-top: 10px;
}

/* Player wheel: a half-transparent black window, no title, only ✓ and ✕. */
.modal.ai-wheel-modal {
    background: rgba(0, 0, 0, .55);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    border-color: rgba(255, 255, 255, .08);
}

.ai-wheel-modal .ai-wheel-item {
    color: rgba(255, 255, 255, .75);
}

.ai-wheel-modal .ai-wheel-item.active {
    color: #fff;
}

/* Under a player's anecdotes: "+ Ajouter" and "Essayer" side by side. */
.ai-note-group-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

/* "Essayer" window: BadZone's sample answers, one per anecdote (league-config.js: tryAiNotes). */
.ai-note-try-body {
    max-height: 65vh;
    overflow-y: auto;
}

.ai-note-try-wait {
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--text-secondary);
    font-size: 14px;
    padding: 12px 0;
}

.ai-note-try-league {
    font-size: 11px;
    color: var(--text-muted);
    margin-bottom: 8px;
}

.ai-note-try-text {
    white-space: pre-wrap;
    font-size: 14px;
    line-height: 1.55;
    color: var(--text-primary);
}

.ai-note-group-actions {
    margin: 4px 0 2px 10px;
}

.ai-note-group-actions .ai-note-add-more {
    margin: 0;
}

.ai-note-try-note {
    color: var(--accent-light);
    font-size: 12px;
    font-weight: 600;
    margin-top: 6px;
}

/* "Essayer" window in the wheel's half-transparent black, larger text. */
.ai-note-try .ai-note-form-title {
    font-size: 17px;
}

.ai-note-try .ai-note-try-text {
    font-size: 17px;
    line-height: 1.6;
    color: #fff;
}

.ai-note-try .ai-note-try-note {
    font-size: 14px;
    margin-top: 10px;
}

.ai-note-try .ai-note-try-league,
.ai-note-try .ai-note-try-wait {
    font-size: 13px;
    color: rgba(255, 255, 255, .6);
}

@media (max-width: 768px), (max-height: 500px) and (pointer: coarse) {
    /* "Essayer" on a phone: every text of the window larger, not only the answers. */
    .ai-note-try .ai-note-form-title {
        font-size: 22px;
    }

    .ai-note-try .ai-note-try-text {
        font-size: 20px;
        line-height: 1.55;
    }

    .ai-note-try .ai-note-try-note {
        font-size: 19px;
        margin-top: 14px;
    }

    .ai-note-try .ai-note-try-league,
    .ai-note-try .ai-note-try-wait {
        font-size: 17px;
    }

    .ai-note-try .ai-note-btn {
        width: 48px;
        height: 42px;
    }

    .ai-note-try .ai-note-btn .cfg-icon {
        width: 22px;
        height: 22px;
    }
}

@media (max-width: 768px), (max-height: 500px) and (pointer: coarse) {
    /* Anecdotes page on a phone: everything larger, not only BadZone's answers. */
    #config-body .ai-note-group-name {
        font-size: 17px;
    }

    #config-body .ai-note-text {
        font-size: 17px;
        line-height: 1.5;
    }

    #config-body .ai-note-group .ai-note-text::before {
        top: 16px;
    }

    #config-body .notes-page-hint,
    #config-body .config-section-hint,
    #config-body .ai-hint {
        font-size: 15px;
    }

    #config-body .config-section-title {
        font-size: 13px;
    }

    #config-body .ai-note-add,
    #config-body .ai-note-add-more {
        font-size: 15px;
    }

    .ai-note-modal .ai-note-form-title {
        font-size: 19px;
    }

    .ai-note-modal #ai-note-text {
        font-size: 18px;
        line-height: 1.45;
    }
}

/* Shared wheel picker (layout.js: openWheelPicker): above the other windows (Preview mode is 1100). */
.modal-overlay.wheel-picker-overlay {
    z-index: 1300;
}

/* A field that opens the wheel: looks like a select, shows the current value. */
.wheel-field {
    display: block;
    width: 100%;
    text-align: left;
    cursor: pointer;
    position: relative;
    padding-right: 32px;
}

.wheel-field::after {
    content: '';
    position: absolute;
    right: 12px;
    top: 50%;
    width: 7px;
    height: 7px;
    border-right: 2px solid var(--text-muted);
    border-bottom: 2px solid var(--text-muted);
    transform: translateY(-70%) rotate(45deg);
}

/* Select that opens the wheel picker (layout.js): the wrapper takes the tap, the select only
   shows the value (no native list). */
.wheel-select {
    display: inline-block;
    position: relative;
    cursor: pointer;
    max-width: 100%;
}

#sidebar-session-wrap .wheel-select {
    display: block;
}

.wheel-select > select {
    pointer-events: none;
}

/* Globe menu: Auto, FR, EN stacked, the current one in the accent colour. */
#header-locale-menu .header-menu-locale {
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
    min-width: 120px;
    padding: 10px;
    border-bottom: none;
}

#header-locale-menu .header-locale-seg {
    flex: none;
    padding: 9px 16px;
    font-size: 14px;
}

/* "Ask - BadZone" page: heading of the anecdotes part, under the instructions card. */
.ask-section-title {
    margin: 18px 0 6px;
    font-size: 16px;
}

/* Ask - BadZone, Ligues: one collapsed row per league (league-config.js: toggleAiLeague). */
.ai-league-list {
    padding: 4px 0;
    gap: 0;
}

.ai-league {
    width: 100%;
    border-top: 1px solid var(--border);
}

.ai-league:first-child {
    border-top: none;
}

.ai-league-head {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    min-height: 46px;
    padding: 0 16px;
    background: none;
    border: none;
    color: var(--text-primary);
    font: inherit;
    font-size: 15px;
    font-weight: 600;
    text-align: left;
    cursor: pointer;
}

.ai-league-row-name {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ai-league-count {
    min-width: 22px;
    padding: 1px 7px;
    border-radius: 999px;
    background: rgba(249, 115, 22, .16);
    color: var(--accent-light);
    font-size: 12px;
    font-weight: 700;
    text-align: center;
}

.ai-league-count.zero {
    background: var(--surface2);
    color: var(--text-muted);
}

.ai-league-chevron {
    color: var(--text-muted);
    transition: transform .15s ease;
}

.ai-league.open .ai-league-chevron {
    transform: rotate(90deg);
}

.ai-league-body {
    display: none;
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
    padding: 4px 16px 14px;
}

.ai-league.open .ai-league-body {
    display: flex;
}

/* Ask - BadZone, Individuel: one collapsed row per player, like the leagues
   (league-config.js: toggleAiNoteGroup). */
button.ai-note-group-head {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    min-height: 40px;
    padding: 0;
    background: none;
    border: none;
    color: var(--text-primary);
    font: inherit;
    text-align: left;
    cursor: pointer;
}

button.ai-note-group-head .ai-note-group-name {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ai-note-group.open .ai-league-chevron {
    transform: rotate(90deg);
}

.ai-note-group-body {
    display: none;
}

.ai-note-group.open .ai-note-group-body {
    display: block;
}

/* Ask - BadZone page: one type scale for every part (instructions, anecdotes, players, leagues).
   Titles 16, row names 15, texts and buttons 14, hints and section labels 13/12, counts 12.
   A phone gets the same steps, one size up. Overrides the scattered sizes of the parts. */
#config-body.ask-page .config-card-title,
#config-body.ask-page .ask-section-title {
    font-size: 16px;
    font-weight: 700;
}

#config-body.ask-page .config-section-title {
    font-size: 12px;
}

#config-body.ask-page .ai-mode-hint,
#config-body.ask-page .config-section-hint,
#config-body.ask-page .notes-page-hint,
#config-body.ask-page .ai-hint {
    font-size: 13px;
    line-height: 1.5;
    color: var(--text-muted);
}

#config-body.ask-page .ai-note-group-name,
#config-body.ask-page .ai-league-head {
    font-size: 15px;
    font-weight: 600;
}

#config-body.ask-page .ai-note-text,
#config-body.ask-page .ai-custom-prompt-text {
    font-size: 14px;
    line-height: 1.5;
}

#config-body.ask-page .btn,
#config-body.ask-page .ai-note-add,
#config-body.ask-page .ai-note-add-more {
    font-size: 14px;
}

#config-body.ask-page .ai-league-count {
    font-size: 12px;
}

#config-body.ask-page .ai-note-group .ai-note-text::before {
    top: 15px;
}

@media (max-width: 768px), (max-height: 500px) and (pointer: coarse) {
    #config-body.ask-page .config-card-title,
    #config-body.ask-page .ask-section-title {
        font-size: 18px;
    }

    #config-body.ask-page .config-section-title {
        font-size: 13px;
    }

    #config-body.ask-page .ai-mode-hint,
    #config-body.ask-page .config-section-hint,
    #config-body.ask-page .notes-page-hint,
    #config-body.ask-page .ai-hint {
        font-size: 15px;
    }

    #config-body.ask-page .ai-note-group-name,
    #config-body.ask-page .ai-league-head {
        font-size: 17px;
    }

    #config-body.ask-page .ai-note-text,
    #config-body.ask-page .ai-custom-prompt-text {
        font-size: 16px;
    }

    #config-body.ask-page .btn,
    #config-body.ask-page .ai-note-add,
    #config-body.ask-page .ai-note-add-more {
        font-size: 15px;
    }

    #config-body.ask-page .ai-league-count {
        font-size: 13px;
    }

    #config-body.ask-page .ai-note-group .ai-note-text::before {
        top: 16px;
    }
}

/* Admin "Forfait et modules" section (static/js/app/league-config.js: _configPlanHtml).
   One selectable card per plan, listing its modules. */
.config-plan-options {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 4px 0 8px;
}

.config-plan-option {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    width: 100%;
    text-align: left;
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: transparent;
    color: var(--text-primary);
    cursor: pointer;
    transition: border-color 120ms ease, background 120ms ease;
}

.config-plan-option:hover {
    border-color: var(--text-muted);
}

.config-plan-option.selected {
    border-color: var(--accent, #4c6ef5);
    background: rgba(76, 110, 245, 0.1);
}

.config-plan-radio {
    flex: 0 0 auto;
    width: 18px;
    height: 18px;
    margin-top: 1px;
    border-radius: 50%;
    border: 2px solid var(--text-muted);
}

.config-plan-option.selected .config-plan-radio {
    border-color: var(--accent, #4c6ef5);
    background: radial-gradient(circle, var(--accent, #4c6ef5) 0 5px, transparent 6px);
}

.config-plan-body {
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.config-plan-name {
    font-size: 15px;
    font-weight: 700;
}

.config-plan-mods {
    font-size: 13px;
    color: var(--text-secondary);
    line-height: 1.4;
}

.config-plan-addons-label {
    margin: 10px 0 2px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.6px;
    text-transform: uppercase;
    color: var(--text-muted);
}

/* API key field masked without being a password input (avoids iOS Face ID / autofill
   stealing focus when the Configuration panel opens). static/js/app/league-config.js. */
.masked-input {
    -webkit-text-security: disc;
    text-security: disc;
}

/* Disabled API key field (engine is not "Clé API"), static/js/app/league-config.js. */
.modal-input:disabled {
    opacity: 0.45;
    cursor: not-allowed;
}

/* Forfaits editor modal (static/js/app/league-config.js: openPlansEditor). */
.plans-editor-overlay {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 1300;
    background: rgba(0, 0, 0, 0.55);
    align-items: center;
    justify-content: center;
    padding: 16px;
}

.plans-editor-modal {
    width: 100%;
    max-width: 460px;
    max-height: 85vh;
    overflow-y: auto;
    padding: 20px;
}

.plans-editor-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 16px;
}

/* Modules × plans matrix: one row per module, one checkbox column per plan. */
.plans-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) repeat(var(--plan-cols, 2), 76px);
    border: 1px solid var(--border);
    border-radius: 12px;
    overflow: hidden;
}
.plans-grid > div {
    padding: 11px 14px;
    border-bottom: 1px solid var(--border);
    display: flex;
    align-items: center;
}
.pg-corner,
.pg-planhead {
    background: var(--bg-secondary);
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.6px;
    color: var(--text-muted);
}
.pg-planhead {
    justify-content: center;
    color: var(--text-secondary);
}
.pg-modname {
    font-size: 14px;
    color: var(--text-primary);
}
.pg-cell {
    justify-content: center;
}
/* Clip the last row's bottom border against the rounded container. */
.plans-grid > div:nth-last-child(-n + 3) {
    border-bottom: none;
}
.plans-editor-note {
    margin-top: 14px;
    font-size: 12px;
    color: var(--text-muted);
    line-height: 1.5;
}

/* Custom checkbox (the matrix cells). */
.plans-check {
    position: relative;
    display: inline-flex;
    cursor: pointer;
}
.plans-check input {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}
.plans-check-box {
    width: 20px;
    height: 20px;
    border-radius: 6px;
    border: 2px solid var(--border);
    background: var(--bg-card);
    transition: background 0.12s ease, border-color 0.12s ease;
}
.plans-check:hover .plans-check-box {
    border-color: var(--text-muted);
}
.plans-check input:checked + .plans-check-box {
    background: var(--accent);
    border-color: var(--accent);
}
.plans-check input:checked + .plans-check-box::after {
    content: '';
    position: absolute;
    left: 7px;
    top: 3px;
    width: 4px;
    height: 9px;
    border: solid #fff;
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
}
.plans-check input:focus-visible + .plans-check-box {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}


/* Clés API — Ask BadZone engine control centre (static/js/app/ask-admin.js). */
.ask-admin-modal { max-width: 640px; padding: 22px; overscroll-behavior: contain; }
.ia-tabs { margin-bottom: 16px; }
.ask-admin-body .qb-list { max-height: none; }
@media (max-width: 520px) { .ask-admin-modal { padding: 18px 16px; } }
/* While the control centre is open, lock the page behind it (no scroll chaining). */
body.ask-admin-open { overflow: hidden; }
.ask-admin-intro {
    margin: 0 0 16px;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--text-muted);
}
.ask-admin-empty {
    padding: 32px 16px;
    text-align: center;
    font-style: italic;
    color: var(--text-muted);
}
.ask-admin-body { display: flex; flex-direction: column; gap: 12px; }
.ask-admin-quiz {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px 12px;
    padding-bottom: 4px;
}
.ask-admin-quiz-hint { font-size: 12px; color: var(--text-muted); }

/* Quiz bank curation modal (static/js/app/ask-admin.js: _askOpenQuizBank) */
.qb-modal { max-width: 640px; }
.qb-intro { font-size: 13px; color: var(--text-secondary); margin: 0 0 12px; }
.qb-list { max-height: 60vh; overflow-y: auto; display: flex; flex-direction: column; gap: 2px; }
.qb-count { font-size: 11px; text-transform: uppercase; letter-spacing: .6px; color: var(--text-muted);
    font-weight: 600; margin-bottom: 8px; }
.qb-item { display: flex; align-items: center; gap: 12px; padding: 10px 2px;
    border-top: 1px solid var(--border); }
.qb-item:first-of-type { border-top: none; }
.qb-item.off { opacity: .45; }
.qb-main { flex: 1; min-width: 0; }
.qb-q { font-size: 13px; color: var(--text-primary); }
.qb-meta { font-size: 11px; color: var(--text-muted); margin-top: 2px; }
.qb-switch { position: relative; display: inline-flex; flex: none; cursor: pointer; }
.ask-card {
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--bg-secondary);
    padding: 14px 16px;
}
.ask-card-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 12px;
}
.ask-card-title {
    font-size: 15px;
    font-weight: 700;
    color: var(--text-primary);
    display: flex;
    align-items: center;
    gap: 8px;
}
.ask-card-new {
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.6px;
    color: #fff;
    background: var(--accent);
    border-radius: 999px;
    padding: 2px 7px;
}
.ask-card-owner {
    font-size: 12px;
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 48%;
}
/* Engine segmented control: Désactivé / Abonnement / Clé API. */
.ask-card-seg {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 4px;
    padding: 4px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 10px;
}
.ask-seg-btn {
    appearance: none;
    border: none;
    background: transparent;
    color: var(--text-secondary);
    font-size: 13px;
    font-weight: 600;
    padding: 8px 6px;
    border-radius: 7px;
    cursor: pointer;
    transition: background 0.12s ease, color 0.12s ease;
}
.ask-seg-btn:hover { color: var(--text-primary); }
.ask-seg-btn.active {
    background: var(--accent);
    color: #fff;
}
.ask-field-label {
    display: block;
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.7px;
    color: var(--text-muted);
    margin-bottom: 5px;
}
.ask-card-input {
    width: 100%;
    box-sizing: border-box;
    padding: 9px 11px;
    font-size: 13px;
    color: var(--text-primary);
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 8px;
}
.ask-card-input:focus {
    outline: none;
    border-color: var(--accent);
}
.ask-card-key { margin-top: 12px; }
.ask-key-line { display: flex; align-items: center; gap: 8px; }
.ask-key-line .ask-card-input { flex: 1; min-width: 0; }
/* Phase-2 placeholder: auto-generate a dedicated key (not wired yet). */
.ask-gen-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
    padding: 9px 12px;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-secondary);
    background: var(--bg-card);
    border: 1px dashed var(--border);
    border-radius: 8px;
    cursor: pointer;
    transition: color 0.12s ease, border-color 0.12s ease;
}
.ask-gen-btn:hover { color: var(--text-primary); border-color: var(--text-muted); }
.ask-soon {
    font-size: 9px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--text-muted);
    background: var(--bg-secondary);
    border-radius: 999px;
    padding: 2px 6px;
}
.ask-card-row {
    display: flex;
    align-items: flex-end;
    gap: 16px;
    margin-top: 12px;
}
.ask-card-field { flex: 0 0 160px; }
.ask-card-num { max-width: 110px; }
.ask-card-usage { flex: 1; min-width: 0; }
.ask-usage-val {
    display: block;
    font-size: 13px;
    color: var(--text-secondary);
    padding: 9px 0;
}
.ask-card-actions {
    display: flex;
    justify-content: flex-end;
    margin-top: 14px;
}
.btn-sm { padding: 7px 16px; font-size: 13px; }
/* Locked feature (module not in the league's plan): what it offers and which plan includes it
   (static/js/app/navigation.js: _showModuleUpsell). Not an error: an invitation. */
.upsell-modal { max-width: 380px; padding: 28px 24px 22px; text-align: center; }
.upsell-lock { font-size: 34px; line-height: 1; margin-bottom: 10px; }
.upsell-title { font-size: 18px; font-weight: 700; color: var(--text-primary); margin-bottom: 10px; }
.upsell-text { margin: 0 0 12px; font-size: 14px; line-height: 1.5; color: var(--text-secondary); }
.upsell-plan { margin: 0 0 18px; font-size: 13px; line-height: 1.5; color: var(--text-muted); }
.upsell-actions { display: flex; flex-direction: column; gap: 8px; }
.upsell-actions .btn { width: 100%; justify-content: center; }

/* Quiz tab of the IA BadZone hub (static/js/app/quiz-admin.js). Reuses .ask-card / .ask-admin-* framing. */
.qa-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; font-size: 12px; color: var(--text-secondary); margin-bottom: 8px; }
.qa-count { margin-left: auto; color: var(--text-muted); }
.qa-pill {
    font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.6px;
    padding: 2px 8px; border-radius: 999px; color: var(--text-secondary);
    background: var(--bg-card); border: 1px solid var(--border);
}
.qa-pill.league { color: #fff; background: var(--accent); border-color: var(--accent); }
.qa-question { font-size: 14px; font-weight: 600; line-height: 1.45; color: var(--text-primary); }
.qa-choices { margin: 8px 0 0; padding-left: 20px; font-size: 13px; color: var(--text-secondary); line-height: 1.6; }
.qa-choices .qa-right { color: var(--green); font-weight: 600; }
.qa-empty { font-size: 13px; font-style: italic; color: var(--text-muted); }
.qa-error { font-size: 13px; color: #f87171; }
.qa-left { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--border); font-size: 12px; color: var(--text-muted); }
.qa-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.qa-actions .btn[disabled] { opacity: 0.45; cursor: not-allowed; }
.qa-history { margin-top: 12px; font-size: 12.5px; }
.qa-history summary { cursor: pointer; color: var(--text-secondary); font-weight: 600; }
.qa-hist-item { padding: 10px 0; border-top: 1px solid var(--border); }
.qa-hist-item:first-of-type { border-top: none; }
.qa-hist-item .qa-question { font-size: 13px; font-weight: 500; }

/* Fallback engines card (static/js/app/ask-admin.js: _askFallbackCard). */
.ask-fb-intro { margin: -4px 0 12px; font-size: 12.5px; line-height: 1.5; color: var(--text-muted); }
.ask-fb-row { padding: 12px 0; border-top: 1px solid var(--border); }
.ask-fb-head { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 8px; margin-bottom: 8px; }
.ask-fb-rank {
    display: inline-flex; align-items: center; justify-content: center;
    width: 18px; height: 18px; border-radius: 999px;
    font-size: 10px; font-weight: 700; color: var(--text-muted);
    border: 1px solid var(--border);
}
.ask-fb-name { font-size: 13.5px; font-weight: 600; color: var(--text-primary); }
.ask-fb-status { font-size: 11px; font-weight: 600; color: var(--text-muted); }
.ask-fb-status.on { color: var(--green); }
.ask-fb-model {
    margin-left: auto; font-size: 11px; color: var(--text-muted);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.ask-fb-remove { padding: 7px 9px; }
.ask-fb-last { padding-top: 10px; border-top: 1px solid var(--border); font-size: 12px; color: var(--text-muted); }
@media (max-width: 520px) {
    .ask-fb-model { margin-left: 0; flex-basis: 100%; }
    .ask-fb-row .ask-key-line { flex-wrap: wrap; }
    .ask-fb-row .ask-key-line .ask-card-input { flex-basis: 100%; }
}
@media (max-width: 520px) {
    .ask-card-row { flex-direction: column; align-items: stretch; gap: 12px; }
    .ask-card-field { flex: none; }
    .ask-usage-val { padding: 0; }
}


/* League creation wizard (static/js/app/league-admin.js: openLeagueWizard). */
.league-wizard { max-width: 460px; }
.wiz-intro, .wiz-summary-name { margin-bottom: 12px; }
.wiz-intro { font-size: 13px; color: var(--text-secondary); }
.wiz-mods { display: flex; flex-direction: column; gap: 8px; }
.wiz-mod {
    display: flex; align-items: center; gap: 10px;
    padding: 10px 12px; border: 1px solid var(--border); border-radius: 10px; cursor: pointer;
}
.wiz-mod.on { border-color: var(--accent, #4c6ef5); background: rgba(76, 110, 245, 0.1); }
.wiz-mod input { width: 16px; height: 16px; accent-color: var(--accent); }
.wiz-mod-name { flex: 1; font-size: 14px; }
.wiz-mod-price { font-size: 13px; color: var(--text-secondary); font-weight: 600; }
/* The plan the wizard's selection meets ("Forfait Plus"). */
.wiz-plan { margin-top: 12px; font-size: 13px; font-weight: 600; color: var(--accent, #e8611a); }
.wiz-plan.wiz-plan-none { color: var(--text-muted); font-weight: 500; }
/* Under Rencontres: the modules bundled with it ("inclut Joueurs, Cédules, Accès"). */
.wiz-mod-includes { display: block; margin-top: 2px; font-size: 12px; color: var(--text-muted); }
.wiz-req, .wiz-addon {
    font-size: 10px; text-transform: uppercase; letter-spacing: 0.5px;
    padding: 1px 6px; border-radius: 999px; margin-left: 6px;
}
.wiz-req { background: var(--border); color: var(--text-muted); }
.wiz-addon { background: rgba(76,110,245,0.18); color: var(--accent-light, #748ffc); }
.wiz-total { margin-top: 14px; font-size: 15px; }
.wiz-total strong { color: var(--accent-light, #748ffc); }
.wiz-admin-note, .wiz-summary-name { color: var(--text-secondary); font-size: 13px; }
.wiz-summary-name { font-size: 16px; font-weight: 700; color: var(--text-primary); }
.wiz-summary-mods { margin: 0 0 8px; padding-left: 18px; font-size: 14px; color: var(--text-secondary); }
.wiz-summary-mods li { margin: 2px 0; }
.wiz-pay { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--border); }
.wiz-pay-test {
    font-size: 12px; color: #e8a33d; background: rgba(232,163,61,0.12);
    border-radius: 8px; padding: 8px 10px; margin-bottom: 10px;
}

/* Wizard: card already on file (no re-entry). static/js/app/league-admin.js */
.wiz-card-onfile { font-size: 13px; color: var(--text-secondary); padding: 4px 0; }

/* Season setup wizard choices (static/js/app/roster.js: openSeasonWizard). */
.sw-choices { display: flex; flex-direction: column; gap: 10px; }
.sw-choice {
    display: flex; align-items: flex-start; gap: 12px;
    padding: 12px 14px; border: 1px solid var(--border); border-radius: 12px; cursor: pointer;
}
.sw-choice.on { border-color: var(--accent, #4c6ef5); background: rgba(76, 110, 245, 0.1); }
.sw-choice input { margin-top: 3px; width: 16px; height: 16px; accent-color: var(--accent); }
.sw-choice-body { display: flex; flex-direction: column; gap: 3px; }
.sw-choice-title { font-size: 14px; font-weight: 700; color: var(--text-primary); }
.sw-choice-desc { font-size: 12px; color: var(--text-secondary); line-height: 1.45; }
.sw-reco {
    font-size: 10px; text-transform: uppercase; letter-spacing: .5px; padding: 1px 6px;
    border-radius: 999px; background: rgba(76,110,245,0.18); color: var(--accent-light, #748ffc); margin-left: 6px;
}

/* Configuration header "Retour" button (templates/index.html, #config-panel). */
.config-back-btn { flex: 0 0 auto; display: inline-flex; align-items: center; gap: 4px; font-size: 13px; white-space: nowrap; }

/* Players subtabs hint: explains "Réguliers" vs "Ligue" (templates/leagues.html). */
.players-subtab-hint {
    font-size: 12px;
    color: var(--text-secondary);
    line-height: 1.45;
    margin-bottom: 14px;
}

/* Member code card in My account (static/js/app/account.js). */
.member-code-card { text-align: center; }
.member-code-title { font-size: 13px; font-weight: 700; text-transform: uppercase; letter-spacing: .6px; color: var(--text-secondary); margin-bottom: 6px; }
.member-code-hint { font-size: 12px; color: var(--text-secondary); line-height: 1.45; margin-bottom: 14px; }
.member-code-row { display: flex; align-items: center; justify-content: center; gap: 10px; margin-bottom: 14px; }
.member-code { font-family: ui-monospace, Menlo, monospace; font-size: 22px; font-weight: 700; letter-spacing: 1px; color: var(--accent-light, #748ffc); }
.member-code-qr { display: flex; justify-content: center; margin-bottom: 14px; }
.member-code-qr img, .member-code-qr canvas { border-radius: 8px; background: #fff; padding: 8px; }
.member-code-regen { font-size: 12px; }

/* Member code shown at the top of My account, right of the photo buttons (account.js). */
.account-code-top { margin-left: auto; text-align: right; }
.account-code-label { display: block; font-size: 10px; text-transform: uppercase; letter-spacing: .6px; color: var(--text-muted); margin-bottom: 3px; }
.account-code-line { display: inline-flex; align-items: center; gap: 6px; }
.account-code-line .member-code { font-size: 16px; }
.account-code-copy { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; border: 1px solid var(--border); border-radius: 7px; background: transparent; color: var(--text-secondary); cursor: pointer; }
.account-code-copy:hover { color: var(--text-primary); border-color: var(--text-muted); }

/* Linked players in My account (static/js/app/account.js: _accountLinkedPlayersHtml). */
.account-linked-list { margin-bottom: 14px; display: flex; flex-direction: column; gap: 6px; }
.account-linked-row { font-size: 14px; color: var(--text-primary); }
.account-linked-id { color: var(--text-muted); font-size: 12px; font-weight: 600; }
.account-linked-leagues { margin: 4px 0 0 0; padding-left: 20px; }
/* One block per club the name is linked in, told apart by its manager. */
.account-linked-club { margin: 8px 0 0 18px; padding-left: 10px; border-left: 2px solid var(--border); }
.account-linked-manager { font-size: 12px; font-weight: 600; letter-spacing: .3px; color: var(--text-muted); }
.account-linked-club .account-linked-leagues { padding-left: 16px; }
.account-linked-leagues li { font-size: 13px; color: var(--text-secondary); line-height: 1.5; }
.account-linked-empty { margin-bottom: 14px; font-size: 13px; font-style: italic; color: var(--text-muted); }

/* Pending link requests to confirm in My account (account.js: _accountPendingClaimsHtml). */
.account-claims { margin-bottom: 14px; display: flex; flex-direction: column; gap: 10px; }
.account-claim { padding: 12px; border: 1px solid var(--accent); border-radius: 10px; background: rgba(99, 102, 241, .08); }
.account-claim-text { font-size: 14px; color: var(--text-primary); line-height: 1.5; }
.account-claim-text .account-linked-leagues { margin-top: 4px; }
.account-claim-actions { display: flex; gap: 8px; margin-top: 10px; }
.account-claim-actions .btn { font-size: 13px; padding: 6px 14px; }

/* Tappable QR (member code) and its enlarged full-screen view (account.js: _openQRZoom). */
.member-code-qr-tappable { cursor: zoom-in; }
.qr-zoom-overlay { position: fixed; inset: 0; z-index: 3000; display: flex; align-items: center; justify-content: center;
    background: rgba(0, 0, 0, .82); animation: qrZoomFade .18s ease; -webkit-tap-highlight-color: transparent; }
.qr-zoom-overlay.qr-zoom-closing { opacity: 0; transition: opacity .18s ease; }
.qr-zoom-box { display: flex; flex-direction: column; align-items: center; gap: 14px; padding: 16px;
    transition: transform .12s ease, opacity .12s ease; touch-action: none; }
.qr-zoom-img img, .qr-zoom-img canvas { background: #fff; padding: 14px; border-radius: 14px; display: block; }
.qr-zoom-code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 20px; letter-spacing: 1px; color: #fff; }
.qr-zoom-hint { font-size: 13px; color: rgba(255, 255, 255, .7); }
@keyframes qrZoomFade { from { opacity: 0; } to { opacity: 1; } }

/* ── Admin dashboard (static/js/app/admin-dashboard.js) ──────────────────────
   Platform overview: KPI tiles, role donut, attendance gauge, growth/modules
   bars and a recent-activity feed. Dark theme tokens (orange accent, green =
   positive). See docs/admin-dashboard.md. */
#admin-dashboard-panel { max-width: 1180px; }
.adash-head { display: flex; align-items: flex-start; justify-content: space-between;
    gap: 16px; margin-bottom: 20px; }
.adash-subtitle { font-size: 13px; color: var(--text-secondary); margin-top: 2px; }
.adash-loading { padding: 40px 0; text-align: center; color: var(--text-muted);
    font-style: italic; }

/* Config popover: toggle each section on/off */
.adash-head-actions { position: relative; display: flex; gap: 10px; align-items: flex-start; }
.adash-config-pop { position: absolute; top: calc(100% + 8px); right: 0; z-index: 50;
    width: 290px; background: var(--bg-card); border: 1px solid var(--border);
    border-radius: 12px; padding: 10px 12px; box-shadow: 0 12px 32px rgba(0, 0, 0, .45); }
.adash-config-scroll { max-height: min(60vh, 460px); overflow-y: auto; margin: -2px -4px 0;
    padding: 2px 4px; }
.adash-config-title { font-size: 11px; text-transform: uppercase; letter-spacing: .6px;
    color: var(--text-muted); font-weight: 600; margin: 2px 0 6px; }
.adash-config-title:not(:first-child) { margin-top: 14px; }
.adash-config-row { display: flex; align-items: center; gap: 10px; padding: 7px 2px;
    font-size: 13px; color: var(--text-primary); position: relative; }
.adash-config-row + .adash-config-row { border-top: 1px solid var(--border); }
.adash-config-name { flex: 1; min-width: 0; }
.adash-reorder { display: inline-flex; flex-direction: column; gap: 2px; flex: none; }
.adash-move { width: 22px; height: 15px; padding: 0; border: 1px solid var(--border);
    background: var(--bg-secondary); color: var(--text-secondary); border-radius: 4px;
    cursor: pointer; font-size: 8px; line-height: 1; display: flex; align-items: center;
    justify-content: center; transition: color .12s, border-color .12s; }
.adash-move:hover:not(:disabled) { color: var(--text-primary); border-color: var(--text-muted); }
.adash-move:disabled { opacity: .3; cursor: default; }
.adash-switch { position: relative; display: inline-flex; flex: none; cursor: pointer; }
.adash-config-hint { font-size: 11px; color: var(--text-muted); font-style: italic;
    padding: 8px 2px 2px; }
.adash-config-reset { width: 100%; margin-top: 10px; padding: 8px; font-size: 12px;
    background: var(--bg-secondary); color: var(--text-secondary); border: 1px solid var(--border);
    border-radius: 8px; cursor: pointer; transition: color .12s, border-color .12s; }
.adash-config-reset:hover { color: var(--text-primary); border-color: var(--text-muted); }

/* KPI tiles */
/* Sections laid out as flex children: full-width, or halves that pair up and reflow
   when hidden or reordered. Each section carries a ⠿ drag handle. */
.adash-sections { display: flex; flex-wrap: wrap; gap: 16px; align-items: flex-start; }
.adash-sec { position: relative; min-width: 0; }
.adash-sec-full { width: 100%; }
.adash-sec-half { width: calc(50% - 8px); }
.adash-sec > .adash-card { width: 100%; }
.adash-drag-handle { position: absolute; top: 12px; right: 14px; z-index: 3;
    cursor: grab; color: var(--text-muted); font-size: 15px; line-height: 1;
    letter-spacing: -2px; user-select: none; opacity: .3; transition: opacity .12s ease; }
.adash-sec:hover > .adash-drag-handle { opacity: .75; }
.adash-drag-handle:hover { opacity: 1; color: var(--text-secondary); }
.adash-drag-handle:active { cursor: grabbing; }
.adash-sec.adash-dragging { opacity: .45; outline: 2px dashed var(--accent);
    outline-offset: -2px; border-radius: 14px; }

.adash-kpis { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
.adash-kpi { background: var(--bg-card); border: 1px solid var(--border);
    border-radius: 14px; padding: 16px 18px; display: flex; flex-direction: column;
    min-height: 118px; min-width: 0; }
.adash-kpi-top { flex: 1; }
.adash-kpi-label { font-size: 11px; text-transform: uppercase; letter-spacing: .6px;
    color: var(--text-muted); font-weight: 600; }
.adash-kpi-val { font-size: 30px; font-weight: 800; color: var(--text-primary);
    line-height: 1.1; margin-top: 6px; letter-spacing: -.5px; }
.adash-kpi-sub { font-size: 12px; margin-top: 4px; }
.adash-kpi-sub.pos { color: var(--green); }
.adash-kpi-sub.neg { color: var(--red); }
.adash-kpi-sub.muted { color: var(--text-secondary); }

/* Chart containers (Chart.js responsive needs a sized, positioned parent) */
.adash-chart { position: relative; width: 100%; min-width: 0; }
.adash-chart canvas { max-width: 100%; display: block; }
.adash-chart-spark { height: 40px; margin-top: 10px; }
.adash-chart-gauge { height: 50px; margin-top: 8px; }
.adash-chart-rev { height: 84px; margin-top: 4px; }
.adash-chart-bars { height: 220px; margin-top: 6px; }

/* Cards & grids */
.adash-grid { display: grid; gap: 16px; margin-bottom: 16px; }
.adash-grid-2 { grid-template-columns: 1.15fr 1fr; }
.adash-grid-2.adash-grid-solo { grid-template-columns: 1fr; }
.adash-card { background: var(--bg-card); border: 1px solid var(--border);
    border-radius: 14px; padding: 18px; min-width: 0; }
.adash-card-title { font-size: 14px; font-weight: 700; color: var(--text-primary);
    margin-bottom: 14px; }

/* Role donut */
.adash-donut-wrap { display: flex; align-items: center; gap: 24px; flex-wrap: wrap; }
.adash-donut-canvas { position: relative; width: 168px; height: 168px; flex: 0 0 auto; }
.adash-donut-center { position: absolute; inset: 0; display: flex; flex-direction: column;
    align-items: center; justify-content: center; pointer-events: none; }
.adash-donut-num { font-size: 26px; font-weight: 800; color: var(--text-primary); line-height: 1; }
.adash-donut-lbl { font-size: 11px; text-transform: uppercase; letter-spacing: .6px;
    color: var(--text-muted); margin-top: 3px; }
.adash-legend { flex: 1; min-width: 160px; display: flex; flex-direction: column; gap: 8px; }
.adash-leg { display: flex; align-items: center; gap: 10px; font-size: 13px; }
.adash-leg-dot { width: 10px; height: 10px; border-radius: 3px; flex: 0 0 auto; }
.adash-leg-name { color: var(--text-secondary); flex: 1; }
.adash-leg-val { color: var(--text-primary); font-weight: 700; }

/* Side column: mini-stats + revenue */
.adash-side { display: flex; flex-direction: column; gap: 16px; }
.adash-ministats { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.adash-mini { background: var(--bg-secondary); border: 1px solid var(--border);
    border-radius: 10px; padding: 12px 14px; }
.adash-mini-val { font-size: 22px; font-weight: 800; color: var(--text-primary); line-height: 1; }
.adash-mini-lbl { font-size: 11px; color: var(--text-muted); margin-top: 4px; }
.adash-rev-head { display: flex; align-items: baseline; justify-content: space-between; }
.adash-rev-head .adash-card-title { margin-bottom: 0; }
.adash-rev-total { font-size: 20px; font-weight: 800; color: var(--green); }
.adash-rev-note { font-size: 11px; color: var(--text-muted); margin-top: 6px; font-style: italic; }

/* Activity feed */
.adash-activity { display: flex; flex-direction: column; }
.adash-act { display: flex; gap: 12px; padding: 10px 0; border-top: 1px solid var(--border); }
.adash-act:first-of-type { border-top: none; }
.adash-act-ico { width: 30px; height: 30px; border-radius: 9px; flex: 0 0 auto;
    display: flex; align-items: center; justify-content: center;
    background: var(--bg-secondary); color: var(--text-secondary); }
.adash-act-user { color: var(--green); }
.adash-act-ask { color: var(--accent-light); }
.adash-act-payment { color: var(--gold); }
.adash-act-match { color: var(--blue); }
.adash-act-body { flex: 1; min-width: 0; }
.adash-act-txt { font-size: 13px; color: var(--text-primary); }
.adash-act-when { font-size: 11px; color: var(--text-muted); margin-top: 1px; }

/* Per-league table */
.adash-ltable-wrap { overflow-x: auto; }
.adash-ltable { width: 100%; border-collapse: collapse; font-size: 13px; min-width: 820px; }
.adash-ltable th { text-align: right; padding: 8px 10px; font-size: 11px; font-weight: 600;
    text-transform: uppercase; letter-spacing: .4px; color: var(--text-muted);
    border-bottom: 1px solid var(--border); cursor: pointer; white-space: nowrap;
    user-select: none; }
.adash-ltable th:first-child, .adash-ltable td.lname { text-align: left; }
.adash-ltable th:hover { color: var(--text-secondary); }
.adash-ltable th.sorted { color: var(--accent-light); }
.adash-ltable td { padding: 9px 10px; border-bottom: 1px solid var(--border);
    color: var(--text-secondary); text-align: right; white-space: nowrap; }
.adash-ltable tr:last-child td { border-bottom: none; }
.adash-ltable tbody tr:hover td { background: var(--bg-hover); }
.adash-ltable td.lname { color: var(--text-primary); font-weight: 600; }
.adash-ltable td.num { font-variant-numeric: tabular-nums; }
.adash-lbadge { margin-left: 6px; font-size: 11px; opacity: .85; }

@media (max-width: 900px) {
    .adash-kpis { grid-template-columns: 1fr 1fr; }
    .adash-grid-2 { grid-template-columns: 1fr; }
    .adash-sec-half { width: 100%; }  /* halves stack full-width */
}
@media (max-width: 480px) {
    .adash-kpis { grid-template-columns: 1fr; }
    .adash-kpi-val { font-size: 26px; }
}

/* ── "Mes ligues" (static/js/app/my-leagues.js) ── */
.myl-section {
    margin: 20px 0 10px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .7px;
    text-transform: uppercase;
    color: var(--text-muted);
}
.myl-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 12px; }
.myl-card {
    padding: 16px 18px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 12px;
    min-width: 0;
}
.myl-card-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; flex-wrap: wrap; }
.myl-name { font-size: 16px; font-weight: 700; color: var(--text-primary); min-width: 0; overflow-wrap: anywhere; }
.myl-badges { display: flex; gap: 6px; flex-wrap: wrap; }
.myl-badge {
    padding: 2px 8px;
    border: 1px solid var(--border);
    border-radius: 999px;
    font-size: 11px;
    font-weight: 600;
    color: var(--text-secondary);
    white-space: nowrap;
}
.myl-badge-live { color: #22c55e; border-color: rgba(34, 197, 94, .35); }
.myl-badge-prep { color: #f59e0b; border-color: rgba(245, 158, 11, .35); }
.myl-meta { margin: 8px 0 14px; font-size: 13px; color: var(--text-secondary); }
.myl-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.myl-empty { font-size: 13px; font-style: italic; color: var(--text-muted); padding: 8px 0; }
.myl-list { display: flex; flex-direction: column; gap: 6px; }
.myl-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 10px 14px;
    border: 1px solid var(--border);
    border-radius: 10px;
}
.myl-row-name { font-size: 14px; color: var(--text-primary); min-width: 0; overflow-wrap: anywhere; }
.myl-role { margin-left: 8px; font-size: 12px; color: var(--text-muted); }
/* Section heading with an action on the right ("Tableau de bord"); the button keeps its own case. */
.myl-section-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.myl-section-head .btn { text-transform: none; letter-spacing: 0; font-size: 12px; }
.myl-icon-btn { display: inline-flex; align-items: center; gap: 6px; }

/* Forfaits editor: the "Inscription des clubs" switch above the plan grid. */
.plans-signup {
    margin-bottom: 18px;
    padding-bottom: 16px;
    border-bottom: 1px solid var(--border);
}
.plans-signup-title {
    margin-bottom: 8px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .7px;
    text-transform: uppercase;
    color: var(--text-muted);
}
.plans-signup-hint { margin-top: 6px; font-size: 12px; line-height: 1.5; color: var(--text-muted); }
/* Notifications push panel (static/js/app/push.js): subscribed devices, above the test button. */
.push-admin-stats { margin-bottom: 12px; font-size: 13px; color: var(--text-secondary); }

/* League roster without a season yet: why the added players are not regulars, and the way out. */
.roster-no-season {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px 12px;
    margin: 0 0 12px;
    font-size: 13px;
    color: var(--text-secondary);
}

/* Season wizard, last step: make the league's players the season's regulars. */
.sw-roster {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin-top: 14px;
    font-size: 13px;
    line-height: 1.4;
    color: var(--text-secondary);
    cursor: pointer;
}
.sw-roster input { margin-top: 2px; accent-color: var(--accent); }
