/* admin.css — Admin panel styles */

/* ── Match Results sub-tabs (admin.html) ──────────────────────────────────
   Mirrors the dashboard's .rem-tab-* pattern so the admin tab bar feels
   native. Tabs sit on the page bg (var(--color-bg)) and contrast against
   their surface-coloured buttons. The opened panel carries its own surface
   background. (The section header itself uses the shared .dash-section /
   .collapsible-* tab styling defined further below.)
   Keep visually in sync with css/dashboard.css :: .rem-tab-bar block. */
.rem-tab-bar {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
    margin-bottom: var(--space-sm);
}
.rem-tab-btn {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    padding: var(--space-xs) var(--space-md);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    color: var(--color-accent);
    font-family: var(--font-main);
    font-size: var(--fs-090);
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
    user-select: none;
}
.rem-tab-btn:hover {
    background: var(--color-hover);
    border-color: var(--color-accent);
}
.rem-tab-btn--open {
    background: var(--color-accent);
    color: var(--color-bg);
    border-color: var(--color-accent);
}
.rem-tab-btn--open:hover {
    background: var(--color-text);
    border-color: var(--color-text);
}
.rem-tab-arrow {
    font-size: 0.75em;
}
.rem-tab-panel {
    margin-top: var(--space-sm);
    padding: var(--space-md);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
}


/* Skip link (a11y) — duplicated from navigation.css since admin.html
   does not load navigation.css. Keep in sync if the base rules change. */
.skip-link {
    position: absolute;
    top: -100px;
    left: 0;
    background: var(--color-accent, #2563eb);
    color: #fff;
    padding: 8px 16px;
    z-index: 9999;
    text-decoration: none;
    font-weight: 600;
    border-radius: 0 0 4px 0;
    transition: top 150ms ease-out;
}
.skip-link:focus,
.skip-link:focus-visible {
    top: 0;
    outline: 2px solid #fff;
    outline-offset: -4px;
}

/* ---- Layout ---- */
.admin-layout {
    display: flex;
    min-height: 100vh;
}

.admin-sidebar {
    width: 240px;
    background: var(--header-bg);
    color: var(--header-text);
    padding: var(--space-md);
    display: flex;
    flex-direction: column;
    flex-shrink: 0;
    position: sticky;
    top: 0;
    height: 100vh;
    overflow-y: auto;
}

.admin-sidebar-logo {
    display: block;
    height: 60px;
    margin: 0 auto var(--space-sm);
    object-fit: contain;
}

.admin-sidebar h2 {
    font-size: var(--fs-110);
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    margin-bottom: var(--space-md);
    padding-bottom: var(--space-sm);
    border-bottom: 1px solid rgba(255,255,255,0.1);
    color: rgba(255,255,255,0.5);
}

/* ---- Welcome Card ---- */
.admin-welcome {
    margin-bottom: var(--space-lg);
    padding: 12px 10px 10px 12px;
    background: linear-gradient(135deg, rgba(37,99,235,0.22) 0%, rgba(255,255,255,0.04) 100%);
    border-radius: var(--radius-md);
    border: 1px solid rgba(255,255,255,0.08);
    border-top-color: rgba(255,255,255,0.13);
    position: relative;
    overflow: hidden;
    display: flex;
    align-items: center;
    gap: 10px;
    animation: welcome-in 0.4s cubic-bezier(0.22, 1, 0.36, 1) both;
}

@keyframes welcome-in {
    from { opacity: 0; transform: translateY(-6px); }
    to   { opacity: 1; transform: translateY(0); }
}

.admin-welcome::before {
    content: '';
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 3px;
    background: linear-gradient(to bottom, #60a5fa 0%, #2563eb 100%);
    border-radius: 0 2px 2px 0;
}

.admin-welcome-avatar {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--fs-105);
    font-weight: 800;
    color: #fff;
    flex-shrink: 0;
    text-transform: uppercase;
    box-shadow: 0 0 0 2px rgba(96,165,250,0.25), 0 2px 10px rgba(37,99,235,0.45);
}

.admin-welcome-body {
    min-width: 0;
    flex: 1;
}

.admin-welcome-label {
    font-size: var(--fs-062);
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: rgba(255,255,255,0.38);
    margin-bottom: 1px;
}

.admin-welcome-name {
    font-size: var(--fs-092);
    font-weight: 700;
    color: rgba(255,255,255,0.95);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    letter-spacing: 0.01em;
}

.admin-welcome-status {
    display: flex;
    align-items: center;
    gap: 5px;
    margin-top: 3px;
    font-size: var(--fs-065);
    color: rgba(52,211,153,0.85);
    letter-spacing: 0.04em;
    font-weight: 600;
    text-transform: uppercase;
}

.admin-welcome-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: #34d399;
    box-shadow: 0 0 0 2px rgba(52,211,153,0.2);
    animation: pulse-dot 2.4s ease-in-out infinite;
    flex-shrink: 0;
}

@keyframes pulse-dot {
    0%, 100% { box-shadow: 0 0 0 2px rgba(52,211,153,0.2); }
    50%       { box-shadow: 0 0 0 4px rgba(52,211,153,0.12), 0 0 8px rgba(52,211,153,0.3); }
}

.admin-sidebar nav {
    flex: 1;
}

.admin-nav-item {
    display: block;
    padding: var(--space-sm) var(--space-md);
    color: rgba(255,255,255,0.75);
    text-decoration: none;
    border-radius: var(--radius-sm);
    cursor: pointer;
    margin-bottom: var(--space-xs);
    font-size: var(--fs-095);
    transition: background 0.15s, color 0.15s;
    border: none;
    background: none;
    width: 100%;
    text-align: left;
    font-family: inherit;
}

.admin-nav-item:hover,
.admin-nav-item.active {
    background: rgba(255,255,255,0.1);
    color: #fff;
}

.admin-sidebar-footer {
    margin-top: auto;
    padding-top: var(--space-md);
    border-top: 1px solid rgba(255,255,255,0.15);
}

.admin-main {
    flex: 1;
    padding: var(--space-lg) var(--space-xl);
    background: var(--color-bg);
    overflow-y: auto;
}

.admin-main h1 {
    font-size: var(--fs-160);
    margin-bottom: var(--space-lg);
    color: var(--color-text);
}

/* ---- Login ---- */
.admin-login-wrapper {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    background: var(--color-bg);
}

.admin-login-box {
    background: var(--color-surface);
    padding: var(--space-xl);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    width: 100%;
    max-width: 400px;
}

.admin-login-box h1 {
    text-align: center;
    margin-bottom: var(--space-lg);
    font-size: var(--fs-150);
}

.admin-login-box .form-group {
    margin-bottom: var(--space-md);
}

/* ---- Forms ---- */
.form-group {
    margin-bottom: var(--space-md);
}

.form-group label {
    display: block;
    font-weight: 600;
    margin-bottom: var(--space-xs);
    font-size: var(--fs-090);
    color: var(--color-text-secondary);
}

.form-group input,
.form-group select,
.form-group textarea {
    width: 100%;
    box-sizing: border-box;
    min-width: 0;
    padding: var(--space-sm) var(--space-md);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    font-family: inherit;
    font-size: var(--fs-095);
    color: var(--color-text);
    background: var(--color-surface);
    transition: border-color 0.15s;
}

.form-group input:focus,
.form-group select:focus,
.form-group textarea:focus {
    outline: none;
    border-color: var(--color-accent);
    box-shadow: 0 0 0 3px var(--color-accent-light);
}

/* ---- Buttons ---- */
.btn {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    padding: var(--space-sm) var(--space-md);
    border: none;
    border-radius: var(--radius-sm);
    font-family: inherit;
    font-size: var(--fs-090);
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s, opacity 0.15s, transform 0.12s, box-shadow 0.15s;
    position: relative;
    letter-spacing: 0.01em;
}

.btn:not(:disabled):hover {
    transform: translateY(-1px);
}

.btn:not(:disabled):active {
    transform: translateY(0);
}

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

.btn-primary {
    background: var(--color-accent);
    color: #fff;
    box-shadow: 0 1px 3px rgba(37,99,235,0.3);
}

.btn-primary:hover:not(:disabled) {
    background: #1d4ed8;
    box-shadow: 0 4px 12px rgba(37,99,235,0.38);
}

.btn-success {
    background: var(--color-running);
    color: #fff;
    box-shadow: 0 1px 3px rgba(4,120,87,0.3);
}

.btn-success:hover:not(:disabled) {
    background: #047857;
    box-shadow: 0 4px 12px rgba(4,120,87,0.38);
}

.btn-danger {
    background: var(--color-loss);
    color: #fff;
    box-shadow: 0 1px 3px rgba(185,28,28,0.25);
}

.btn-danger:hover:not(:disabled) {
    background: #b91c1c;
    box-shadow: 0 4px 12px rgba(185,28,28,0.35);
}

.btn-secondary {
    background: var(--color-surface);
    color: var(--color-text);
    border: 1px solid var(--color-border);
    box-shadow: 0 1px 2px rgba(0,0,0,0.05);
}

.btn-secondary:hover:not(:disabled) {
    background: var(--color-hover);
    border-color: #c0c4cd;
    box-shadow: 0 3px 8px rgba(0,0,0,0.09);
}

.btn-sm {
    padding: var(--space-xs) var(--space-sm);
    font-size: var(--fs-082);
}

.btn-block {
    display: block;
    width: 100%;
}

/* ---- Staging Badge ---- */
.staging-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--color-loss);
    color: #fff;
    font-size: var(--fs-075);
    font-weight: 700;
    min-width: 20px;
    height: 20px;
    border-radius: var(--radius-full);
    padding: 0 6px;
    margin-left: var(--space-xs);
}

.staging-badge.empty {
    display: none;
}

/* ---- Pending Changes Panel ---- */
.pending-panel {
    background: var(--color-surface);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    padding: var(--space-md);
    margin-bottom: var(--space-lg);
    border: 1px solid var(--color-border);
}

.pending-panel h3 {
    margin-bottom: var(--space-md);
    font-size: var(--fs-100);
}

.pending-list {
    list-style: none;
    margin-bottom: var(--space-md);
}

.pending-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--space-sm);
    border-bottom: 1px solid var(--color-border);
    font-size: var(--fs-090);
}

.pending-item:last-child {
    border-bottom: none;
}

.pending-item-desc {
    flex: 1;
}

.pending-item-time {
    color: var(--color-text-muted);
    font-size: var(--fs-080);
    margin: 0 var(--space-md);
}

/* ---- Cards ---- */
.admin-card {
    background: var(--color-surface);
    border-radius: var(--radius-md);
    box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 4px 16px rgba(0,0,0,0.04);
    padding: var(--space-lg);
    margin-bottom: var(--space-lg);
    border: 1px solid var(--color-border);
    transition: box-shadow 0.2s;
}

.admin-card:hover {
    box-shadow: 0 2px 6px rgba(0,0,0,0.08), 0 8px 24px rgba(0,0,0,0.06);
}

.admin-card h2 {
    font-size: var(--fs-080);
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--color-text-muted);
    margin-bottom: var(--space-md);
    padding-bottom: var(--space-sm);
    border-bottom: 1px solid var(--color-border);
}

/* ── Collapsible section tabs (Edit League view) ──────────────────────────
   IDENTICAL to the index dashboard tabs. Mirrors css/dashboard.css
   (.dash-section h2) + css/index-dashboard.css (.collapsible-header /
   .collapsible-body) because admin.html loads neither file.

   FONT SIZE: index.html is the one page that does NOT load
   typography-tokens.css, so there its `.dash-section h2 { font-size:
   var(--fs-120) }` resolves to an undefined var and the header inherits the
   body font size. admin.html DOES load the tokens, so to render these tabs at
   exactly the same size as on index.html we inherit here instead of using the
   token. Keep in sync with those two sources. */
.dash-section {
    margin-top: var(--space-xl);
}
.dash-section h2 {
    margin-bottom: var(--space-md);
    font-size: inherit; /* match index.html (see note above) — not var(--fs-120) */
    border-bottom: 2px solid var(--color-border);
    padding-bottom: var(--space-xs);
    color: var(--color-text);
}
.collapsible-header {
    cursor: pointer;
    user-select: none;
}
.collapsible-header::after {
    content: ' \25BE';
    font-size: 0.9em;
    color: var(--color-text-muted);
}
.collapsed .collapsible-header::after {
    content: ' \25B8';
}
.collapsed .collapsible-body {
    display: none;
}

/* font-small content for League Settings & Automatic Sync cards. */
.edit-card-sm,
.edit-card-sm small,
.edit-card-sm .form-group label,
.edit-card-sm .form-group input,
.edit-card-sm .form-group select,
.edit-card-sm .form-group textarea {
    font-size: var(--fs-085);
}

/* Inputs in these cards scale linearly with the viewport: --fs-085 is a
   clamp()/vw token, so em-based padding + the inherited unitless line-height
   (1.6) make the whole control grow and shrink with the font — and therefore
   with the viewport width. Covers Issue Date and every Automatic-Sync field. */
.edit-card-sm {
    --input-pad-y: 0.6em;
    --input-pad-x: 1.1em;
}
.edit-card-sm .form-group input,
.edit-card-sm .form-group select {
    padding: var(--input-pad-y) var(--input-pad-x);
}
/* date/time controls carry ~2px of constant WebKit widget chrome — trim 1px
   off each vertical padding so their box height matches the text/number inputs
   at every breakpoint. Higher specificity (attribute selector) than the rule
   above, so it wins. max-width/min-width keep the control inside its column. */
.edit-card-sm .form-group input[type="date"],
.edit-card-sm .form-group input[type="time"] {
    padding-top: calc(var(--input-pad-y) - 1px);
    padding-bottom: calc(var(--input-pad-y) - 1px);
    min-width: 0;
    max-width: 100%;
}
/* iOS Safari sizes native date/time controls to their intrinsic content width
   and ignores width:100% / min-width:0, so they overflow their column to the
   right (the reported Issue Date + BGStudio Start/End Date bug on iPhone).
   Resetting the native appearance — scoped to iOS only via the
   -webkit-touch-callout feature query — makes them honour the author box model
   and fill exactly 100% of the column. Desktop is untouched, so the themed
   ::-webkit-calendar-picker-indicator icon is preserved there. */
@supports (-webkit-touch-callout: none) {
    .edit-card-sm .form-group input[type="date"],
    .edit-card-sm .form-group input[type="time"] {
        -webkit-appearance: none;
        appearance: none;
        width: 100%;
    }
}

/* Checkboxes / radios must not inherit the full-width + padded text-input
   sizing from `.form-group input` (base) or `.edit-card-sm .form-group input`
   (responsive padding) — otherwise they stretch and shove their label aside.
   Covers the "Sync together with" league pickers in the Automatic Sync card. */
.form-group input[type="checkbox"],
.form-group input[type="radio"],
.edit-card-sm .form-group input[type="checkbox"],
.edit-card-sm .form-group input[type="radio"] {
    width: auto;
    min-width: 0;
    padding: 0;
    margin: 0;
    flex: none;
}

/* generic font-small table utility (mirrors components.css for admin.html) */
table.font-small { font-size: var(--fs-085); }

/* ── F6 — Medals & Prizes ─────────────────────────────────────────────────
   Rendered on the unified FF chrome (.ff-wrap + .admin-table.font-large,
   data-mf-table-id="F6") — see ffMedalsTableHTML in js/admin/leagueManager.js.
   The shared FF rules above own the wrapper, header, hairlines, sticky col, and
   the medal column (sticky col 1). Only the two bits below are F6-specific:
   the Count/Prize columns are held equal, and the medal-name cell content gets
   its inline-flex layout + per-medal colour. The Count/Prize <input>s inherit
   the responsive font-small sizing from .edit-card-sm .form-group input.
   (Hand-built FF chrome like F1–F4; the mountFFTable rewire is Phase 8 of
   docs/plans/table-lab-unification.md.) */
[data-mf-table-id="F6"] th:nth-child(n+2),
[data-mf-table-id="F6"] td:nth-child(n+2) {
    width: 28%;
}
.medal-cell {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    font-weight: 700;
    white-space: nowrap;
}
.medal-cell .medal-icon {
    font-size: 1.15em;
    line-height: 1;
}
.medal-cell.medal-gold   { color: var(--color-gold); }
.medal-cell.medal-silver { color: var(--color-silver); }
.medal-cell.medal-bronze { color: var(--color-bronze); }

/* ---- Admin Table ---- */
/* font-large mirrors base.css — admin.html doesn't load components.css */
table.font-large { font-size: var(--fs-093); }

.admin-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--fs-090);
    color: var(--color-text);
}

.admin-table th {
    text-align: left;
    padding: var(--space-sm) var(--space-md);
    background: var(--color-bg);
    font-weight: 700;
    color: var(--color-text-secondary);
    font-size: var(--fs-078);
    letter-spacing: 0.05em;
    text-transform: uppercase;
    border-bottom: 2px solid var(--color-border);
    white-space: nowrap;
}

.admin-table td {
    padding: var(--space-sm) var(--space-md);
    border-bottom: 1px solid var(--color-border);
    vertical-align: middle;
    color: var(--color-text);
}

.admin-table td[data-label="Actions"] {
    white-space: nowrap;
}

/* ── FF format — canonical chrome for F1/F2/F3/F4 (admin tables). ──────
   Mirrors table-lab/formats/ff/ff.css. When Phase 8 of the unification
   plan rewires admin tables to mountFFTable, the lab file becomes the
   sole source and this block is removed.

   Three cell modes (per ColDef in mountFFTable):
   • Display — read-only HTML
   • Action  — button(s) with data-* attrs, caller wires event delegation
   • Edit    — input/select/toggle + getValue (participates in getDiff)

   Caller owns: heading, "+ Add" button, Save buttons, validation msg slot,
   sub-forms (e.g. Upload Custom Flag), and event-delegation handlers.
   FF owns only the scroll wrapper + table + sticky behavior. */

.ff-wrap {
    overflow-x: auto;
    overflow-y: clip;
    border-radius: var(--radius-sm);
}

.admin-table.font-large {
    border-collapse: separate;
    border-spacing: 0;
    width: 100%;
}

.admin-table.font-large th,
.admin-table.font-large td {
    padding: 0.45em 0.5em;
    text-align: left;
    white-space: nowrap;
}

/* Sticky thead — header background --color-bg (subtle tint vs body
   --color-surface). Admin-style header chrome: uppercase + letter-spacing
   + heavier weight. */
.admin-table.font-large thead th {
    position: sticky;
    top: 0;
    z-index: 3;
    background: var(--color-bg);
    color: var(--color-text-secondary);
    font-weight: 700;
    font-size: var(--fs-078);
    letter-spacing: 0.05em;
    text-transform: uppercase;
    border-bottom: 0;
    box-shadow: inset 0 -1px 0 var(--color-border);
}

/* Row hairlines via box-shadow inset (matches SF). */
.admin-table.font-large tbody td {
    border-bottom: 0;
    box-shadow: inset 0 -1px 0 var(--color-border);
    vertical-align: middle;
}

.admin-table.font-large tbody tr:last-child td {
    box-shadow: none;
}

.admin-table.font-large tbody tr:hover td {
    background: var(--color-hover);
}

/* Sticky left column (auto-applied to first col). Top-left corner z=4
   (above sticky thead z=3 and sticky body z=2), matching MF/SF/exp. */
.admin-table.font-large th:first-child {
    position: sticky;
    left: 0;
    z-index: 4;
    background: var(--color-bg);
}
.admin-table.font-large tbody td:first-child {
    position: sticky;
    left: 0;
    z-index: 2;
    background: var(--color-surface);
}
.admin-table.font-large tbody tr:hover td:first-child {
    background: var(--color-hover);
}

/* Sticky-boundary drop-shadow on horizontal scroll — mirrors MF/SF.
   `.is-scrolled-x` is set by attachStickyShadow when scrollLeft > 0. */
.ff-wrap.is-scrolled-x .admin-table.font-large thead th:first-child {
    box-shadow:
        inset 0 -1px 0 var(--color-border),
        6px 0 8px -4px rgba(0, 0, 0, 0.18);
}
.ff-wrap.is-scrolled-x .admin-table.font-large tbody td:first-child {
    box-shadow:
        inset 0 -1px 0 var(--color-border),
        6px 0 8px -4px rgba(0, 0, 0, 0.18);
}
.ff-wrap.is-scrolled-x .admin-table.font-large tbody tr:last-child td:first-child {
    box-shadow: 6px 0 8px -4px rgba(0, 0, 0, 0.18);
}

/* Validation marker for Edit-mode cells (mountFFTable's validate() applies
   this class to invalid <td>s; caller can override via the cellInvalidClass
   arg). */
.cell-invalid {
    outline: 2px solid var(--color-loss);
    outline-offset: -2px;
}

/* ── FF button sizing — unified, em-based, viewport-fluid ──────────
   All buttons inside an FF table share the table's fluid font scaling.
   font-size is set in em — it inherits the cell's clamp-fluid font
   (var(--fs-093) for font-large). Padding, border-radius, and gap are
   all em-based so they scale proportionally with the font. Ratios
   between buttons and cells are preserved at every viewport width.
   Variant classes (.btn-primary / .btn-danger / .btn-secondary /
   .btn-tech) keep their color / weight treatment unchanged — only the
   sizing dimension is unified across the FF family.

   Density tiers (inside FF):
   • default (.btn)      = 0.88em — comfortable, used for primary actions
   • .btn-sm             = 0.85em — slightly more compact (legacy alias)
   • .btn-xs             = 0.75em — tight; used by F3 row-action buttons */
.ff-wrap .btn,
.ff-wrap .btn-sm,
.ff-wrap .btn-xs {
    font-size: 0.85em;
    padding: 0.3em 0.7em;
    border: 1px solid var(--color-border);
    border-radius: 0.25em;
    line-height: 1.2;
    gap: 0.3em;
}
.ff-wrap .btn {
    font-size: 0.88em;
    padding: 0.35em 0.8em;
}
.ff-wrap .btn-xs {
    font-size: 0.75em;
    padding: 0.25em 0.6em;
    border-radius: 0.2em;
}
.ff-wrap .btn-tech {
    font-weight: 700;
}
/* Disabled state — opacity only; size unchanged. */
.ff-wrap .btn:disabled,
.ff-wrap .btn-sm:disabled,
.ff-wrap .btn-xs:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}
/* Inter-button spacing inside F3's Actions column — also em-based. */
.ff-wrap .match-actions .btn {
    margin: 0.1em 0.15em;
}

/* Legacy hover/border rules for non-font-large admin tables (keep). */
.admin-table tbody tr:hover {
    background: var(--color-hover);
}
.admin-table tbody tr:last-child td {
    border-bottom: none;
}

/* ---- Status Toggle ---- */
.toggle-switch {
    position: relative;
    display: inline-block;
    width: 44px;
    height: 24px;
}

.toggle-switch input {
    opacity: 0;
    width: 0;
    height: 0;
}

.toggle-slider {
    position: absolute;
    inset: 0;
    background: var(--color-border);
    border-radius: var(--radius-full);
    cursor: pointer;
    transition: background 0.2s;
}

.toggle-slider::before {
    content: '';
    position: absolute;
    height: 18px;
    width: 18px;
    left: 3px;
    bottom: 3px;
    background: #fff;
    border-radius: 50%;
    transition: transform 0.2s;
}

.toggle-switch input:checked + .toggle-slider {
    background: var(--color-running);
}

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

/* ---- Messages ---- */
.admin-msg {
    padding: var(--space-sm) var(--space-md);
    border-radius: var(--radius-sm);
    margin-bottom: var(--space-md);
    font-size: var(--fs-090);
}

.admin-msg-success {
    background: var(--color-running-bg);
    color: var(--color-running);
    border: 1px solid var(--color-running);
}

.admin-msg-error {
    background: #fef2f2;
    color: var(--color-loss);
    border: 1px solid var(--color-loss);
}

.admin-msg-info {
    background: var(--color-accent-light);
    color: var(--color-accent);
    border: 1px solid var(--color-accent);
}

/* ---- Publish Progress ---- */
.publish-progress {
    margin-top: var(--space-md);
}

.publish-progress-bar {
    height: 8px;
    background: var(--color-border);
    border-radius: var(--radius-full);
    overflow: hidden;
    margin-bottom: var(--space-sm);
}

.publish-progress-fill {
    height: 100%;
    background: var(--color-accent);
    border-radius: var(--radius-full);
    transition: width 0.3s;
}

.publish-progress-text {
    font-size: var(--fs-085);
    color: var(--color-text-muted);
}

/* ---- View Site link ---- */
.admin-view-site {
    text-decoration: none;
    color: var(--color-text-muted);
    display: block;
}

.admin-view-site:hover {
    color: var(--color-accent);
}

/* ---- Match filter bar ---- */
.match-filter-bar {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    margin-bottom: var(--space-md);
}

.match-filter-bar input {
    padding: 6px 10px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    font-size: var(--fs-090);
    background: var(--color-surface);
    color: var(--color-text);
    min-width: 200px;
}

.match-filter-bar label {
    font-size: var(--fs-085);
    color: var(--color-text-secondary);
    font-weight: 600;
}

/* ---- Inline match editing ---- */
.admin-table-compact th,
.admin-table-compact td {
    padding: 4px 5px;
    font-size: var(--fs-080);
}

.inline-edit-input {
    width: 52px;
    padding: 2px 3px;
    border: 1px solid var(--color-border);
    border-radius: 3px;
    font-size: var(--fs-080);
    text-align: center;
    background: var(--color-surface);
    color: var(--color-text);
}

.inline-edit-input:focus {
    border-color: var(--color-accent);
    outline: none;
}

.inline-edit-score {
    width: 42px;
}

/* Admin table compact inputs/selects (player rows, flag uploads) */
.player-name-input,
.player-flag-select,
.player-flag-custom,
[data-field="name"],
[data-field="flag"],
#new-upload-flag-code,
#upload-flag-code {
    background: var(--color-surface);
    color: var(--color-text);
}

.btn-xs {
    padding: 2px 6px;
    font-size: var(--fs-070);
    border-radius: 3px;
    cursor: pointer;
    border: 1px solid var(--color-border);
    background: var(--color-surface);
    color: var(--color-text);
}

.btn-xs:hover {
    background: var(--color-border);
}

.btn-tech {
    font-weight: 700;
}

.btn-save-match:disabled {
    opacity: 0.35;
    cursor: not-allowed;
}
.btn-save-ready {
    background: var(--color-win, #16a34a) !important;
    color: #fff !important;
    border-color: var(--color-win, #16a34a) !important;
    animation: pulse-save 1.5s ease-in-out infinite;
}
@keyframes pulse-save {
    0%, 100% { box-shadow: 0 0 4px rgba(22, 163, 74, 0.3); }
    50% { box-shadow: 0 0 12px rgba(22, 163, 74, 0.6); }
}

.match-row-unplayed {
    opacity: 0.5;
}

.match-row-overridden {
    background: var(--color-accent-light);
}

.nowrap {
    white-space: nowrap;
}

.edit-ts {
    font-size: var(--fs-070);
    color: var(--color-text-muted);
}

/* ----------------------------------------------------------------------
   Table F — Round Editor (admin.html, ManualEntry leagues)
   2 rows per match (one per player). EDITED + ACTIONS rowspan=2.
   Sticky: leftmost (PLAYERS) column only — per TABLE-DESIGN.md iron rules.
   The scroll container is .round-editor-scroll (the wrapper). The table
   itself stays overflow:visible; backgrounds live on td (not tr) so the
   sticky column stays opaque under non-sticky cells.
   ---------------------------------------------------------------------- */
.admin-round-table {
    border-collapse: separate;
    border-spacing: 0;
    width: 100%;
    min-width: max-content;
}

.admin-round-table th,
.admin-round-table td {
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
}

.admin-round-table thead th {
    background: var(--color-bg);
}

/* Leftmost column = PLAYERS = the only sticky column.
   Static edge removed — FF chrome adds drop-shadow on horizontal scroll
   (see the .ff-wrap.is-scrolled-x rules + F3↔FF reconciliation below). */
.admin-round-table .match-player-cell {
    position: sticky;
    left: 0;
    z-index: 2;
}

.admin-round-table thead .match-player-cell {
    z-index: 3;
}

/* Each match = one <tbody class="match-block"> with two <tr>s.
   Border belongs to the *bottom* of each match-block and spans all 6 columns.
   Row-b carries it for the per-row columns; the rowspan'd EDITED/ACTIONS
   cells (physically in row-a) carry it for the right two columns.
   Suppressed for :last-child so the table doesn't end with a hanging line. */
.admin-round-table .match-block .match-row-a td {
    border-bottom: none;
}
.admin-round-table .match-block:not(:last-child) .match-row-b td {
    border-bottom: 1px solid var(--color-border);
}
.admin-round-table .match-block:not(:last-child) .match-row-a .match-edited,
.admin-round-table .match-block:not(:last-child) .match-row-a .match-actions {
    border-bottom: 1px solid var(--color-border);
}
.admin-round-table .match-block:last-child .match-row-b td {
    border-bottom: none;
}

/* Match-state colouring is on td (not tr/tbody) so sticky cells inherit
   the row background without breaking opacity. */
.match-block-unplayed td {
    background: var(--color-surface);
    color: var(--color-text-muted);
    opacity: 0.6;
}

.match-block-overridden td {
    background: var(--color-accent-light);
}

.match-block-pending td {
    background: color-mix(in srgb, var(--color-accent-light) 60%, var(--color-warning, #fef3c7) 40%);
}

/* Hover EDITED/ACTIONS (rowspan'd cells) → highlight the whole match-block. */
.admin-round-table .match-block:has(.match-edited:hover) td,
.admin-round-table .match-block:has(.match-actions:hover) td {
    background: var(--color-hover);
}

/* Hover row-a's per-row cells (PLAYER/PR/LUCK/SCORE) → only those cells.
   Don't extend the hover into the rowspan'd EDITED/ACTIONS cells, so that
   row-a and row-b feel symmetric. */
.admin-round-table .match-row-a:hover td:not(.match-edited):not(.match-actions) {
    background: var(--color-hover);
}

/* Hover row-b → all of row-b's cells (no rowspan'd cells live in row-b). */
.admin-round-table .match-row-b:hover td {
    background: var(--color-hover);
}

/* Same logic for the overridden-state tinted hover. */
.match-block-overridden:has(.match-edited:hover) td,
.match-block-overridden:has(.match-actions:hover) td,
.admin-round-table .match-block-overridden .match-row-a:hover td:not(.match-edited):not(.match-actions),
.admin-round-table .match-block-overridden .match-row-b:hover td {
    background: color-mix(in srgb, var(--color-accent-light) 70%, var(--color-hover) 30%);
}

/* All cells left-aligned per TABLE-DESIGN.md iron rule 7. */
.admin-round-table th,
.admin-round-table td {
    text-align: left;
}

.admin-round-table .match-edited {
    vertical-align: middle;
}

.admin-round-table .match-actions {
    vertical-align: middle;
    white-space: nowrap;
}

.admin-round-table .match-actions .btn {
    margin: 1px 2px;
}

/* Tight inputs so columns size to their data (the table already uses
   min-width: max-content; otherwise the default 150px <input type=number>
   dominates column width). */
.admin-round-table .inline-edit-input {
    width: 4em;
    -moz-appearance: textfield;
}
.admin-round-table .inline-edit-input.inline-edit-score,
.admin-round-table .inline-edit-input.inline-edit-score-select {
    width: 3.2em;
}
.admin-round-table .inline-edit-input.inline-edit-score-select {
    /* Score <select> needs extra room for the arrow chrome on top of digits.
       em-based so it scales with the cell font (fluid via --fs-093). */
    width: 3.8em;
    min-width: 3.8em;
}
.admin-round-table .inline-edit-input::-webkit-outer-spin-button,
.admin-round-table .inline-edit-input::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

/* Score <select> dropdown — same chrome as the number inputs it replaces.
   All sizing in em so the arrow gutter and the digit gutter scale together
   with the cell font (fluid via --fs-093). The old px values (18px right
   padding, 5px arrow inset) stayed constant while width was em — at mobile
   font sizes the px gutter ate ~half the box and clipped the digit. */
.admin-round-table select.inline-edit-score-select {
    padding: 0.15em 1.4em 0.15em 0.45em;
    border: 1px solid var(--color-border);
    border-radius: 0.2em;
    background-color: var(--color-surface);
    color: var(--color-text);
    font-size: var(--fs-080);
    font-family: inherit;
    cursor: pointer;
    accent-color: var(--color-accent);
    appearance: none;
    -webkit-appearance: none;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path fill='%232563eb' d='M0 0l5 6 5-6z'/></svg>");
    background-repeat: no-repeat;
    background-position: right 0.4em center;
    background-size: 0.6em 0.4em;
}
.admin-round-table select.inline-edit-score-select:focus {
    border-color: var(--color-accent);
    outline: none;
    box-shadow: 0 0 0 2px var(--color-accent-light);
}

/* Themed <input type="date"> — used for Issue Date (form) and EDITED column.
   accent-color tints the popup calendar in modern browsers. color-scheme is
   the only knob the browser exposes for the popup itself: 'light' renders
   the OS light calendar (white bg), 'dark' renders the OS dark calendar
   (dark-grey bg). We pick whichever is closest per theme below. */
.themed-date {
    accent-color: var(--color-accent);
    color-scheme: light;
    font-family: inherit;
    color: var(--color-text);
    background: var(--color-surface);
}
/* Note: the ~2px date/time widget-chrome height compensation lives in the
   `.edit-card-sm` block above (responsive em padding), so it is not repeated
   here. */
.themed-date::-webkit-calendar-picker-indicator {
    cursor: pointer;
    opacity: 0.85;
    filter: invert(28%) sepia(95%) saturate(2200%) hue-rotate(213deg) brightness(95%) contrast(95%);
    transition: opacity 0.15s, transform 0.15s;
}
.themed-date::-webkit-calendar-picker-indicator:hover {
    opacity: 1;
    transform: scale(1.1);
}

/* Dark themes — surface lightness < 50%, so the white popup is jarring.
   Switch the popup to the browser's dark calendar (dark-grey bg, light text)
   and drop the blue-tint filter from the icon so it stays light-on-dark. */
[data-theme="dark"] .themed-date,
[data-theme="vegas"] .themed-date,
[data-theme="casino"] .themed-date,
[data-theme="x22"] .themed-date {
    color-scheme: dark;
}
[data-theme="dark"] .themed-date::-webkit-calendar-picker-indicator,
[data-theme="vegas"] .themed-date::-webkit-calendar-picker-indicator,
[data-theme="casino"] .themed-date::-webkit-calendar-picker-indicator,
[data-theme="x22"] .themed-date::-webkit-calendar-picker-indicator {
    filter: none;
}

/* Compact themed date input inside the EDITED cell. */
.admin-round-table .match-edited-date {
    width: 8.5em;
    padding: 2px 4px;
    border: 1px solid var(--color-border);
    border-radius: 3px;
    font-size: var(--fs-078);
    line-height: 1.2;
}
.admin-round-table .match-edited-date:focus {
    border-color: var(--color-accent);
    outline: none;
    box-shadow: 0 0 0 2px var(--color-accent-light);
}

/* Flag thumbnails inside FF tables — mirror of the canonical .flag rule
   in table-lab/formats/base/base.css. em-based: height tracks cell font
   (fluid via --fs-093), so the flag scales with text at every viewport.
   image-rendering:auto is explicit — guards against any inherited
   `crisp-edges`/`pixelated` from other CSS layers (the 2026-06-03 F3
   pixelation bug was the canonical retrospective).
   admin.html doesn't load base.css/components.css, so the canonical
   rule is duplicated here as an admin-side mirror. */
.ff-wrap .flag {
    height: 1em;
    width: auto;
    margin-right: 0.3em;
    object-fit: contain;
    border-radius: 0.15em;
    vertical-align: middle;
    image-rendering: auto;
}

/* ----------------------------------------------------------------------
   F3 ↔ FF chrome reconciliation
   F3 wears the FF chrome (.ff-wrap + .admin-table.font-large) like F1/F2/F4
   but has 2 structural quirks that need surgical overrides:
     1. Hairlines come from per-match-block <tbody> border-bottom logic
        (see .match-block rules above), not from FF's universal box-shadow.
     2. Match-state coloring (.match-block-overridden/-pending/-unplayed)
        sets td backgrounds — must beat FF's first-col background rule.
   ---------------------------------------------------------------------- */

/* 1. Suppress FF's universal cell hairline — F3 owns its own per-match
      border logic above. */
.admin-table.font-large.admin-round-table tbody td {
    box-shadow: none;
}

/* 1b. Re-add drop-shadow on the sticky first col when wrapper is scrolled.
       Body cells: shadow only (F3's per-match border-bottom logic handles
       horizontal hairlines). Header cells: shadow + inset (the inset is the
       thead/body separator and must stay visible while scrolled). */
.ff-wrap.is-scrolled-x .admin-table.font-large.admin-round-table tbody td:first-child {
    box-shadow: 6px 0 8px -4px rgba(0, 0, 0, 0.18);
}
.ff-wrap.is-scrolled-x .admin-table.font-large.admin-round-table thead th:first-child {
    box-shadow:
        inset 0 -1px 0 var(--color-border),
        6px 0 8px -4px rgba(0, 0, 0, 0.18);
}

/* 2. Restore match-state backgrounds on the sticky first col. FF's default
      .admin-table.font-large tbody td:first-child sets var(--color-surface),
      which would mask the per-match tint. These selectors carry higher
      specificity (4 classes vs FF's 3) and win. */
.admin-table.font-large.admin-round-table tbody .match-block-overridden td:first-child {
    background: var(--color-accent-light);
}
.admin-table.font-large.admin-round-table tbody .match-block-pending td:first-child {
    background: color-mix(in srgb, var(--color-accent-light) 60%, var(--color-warning, #fef3c7) 40%);
}
.admin-table.font-large.admin-round-table tbody .match-block-unplayed td:first-child {
    background: var(--color-surface);
}
/* Hover propagation onto sticky first col — same specificity strategy. */
.admin-table.font-large.admin-round-table tbody .match-block:has(.match-edited:hover) td:first-child,
.admin-table.font-large.admin-round-table tbody .match-block:has(.match-actions:hover) td:first-child,
.admin-table.font-large.admin-round-table tbody .match-row-a:hover td:first-child,
.admin-table.font-large.admin-round-table tbody .match-row-b:hover td:first-child {
    background: var(--color-hover);
}
.admin-table.font-large.admin-round-table tbody .match-block-overridden:has(.match-edited:hover) td:first-child,
.admin-table.font-large.admin-round-table tbody .match-block-overridden:has(.match-actions:hover) td:first-child,
.admin-table.font-large.admin-round-table tbody .match-block-overridden .match-row-a:hover td:first-child,
.admin-table.font-large.admin-round-table tbody .match-block-overridden .match-row-b:hover td:first-child {
    background: color-mix(in srgb, var(--color-accent-light) 70%, var(--color-hover) 30%);
}

/* ---- Mobile topbar (hamburger + title + user chip) ----
   Hidden on desktop; on mobile replaces the floating standalone hamburger.
   Lives inside .admin-mobile-topbar which is fixed across the viewport top. */
.admin-mobile-topbar {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: calc(60px + env(safe-area-inset-top, 0px));
    padding: env(safe-area-inset-top, 0px) 16px 0 8px;
    background: var(--header-bg);
    color: var(--header-text, #fff);
    z-index: 110;
    align-items: center;
    gap: 4px;
    box-shadow: 0 1px 0 rgba(255,255,255,0.07), 0 4px 16px rgba(15,23,42,0.22);
}

.admin-topbar-logo {
    height: 32px;
    width: auto;
    object-fit: contain;
    flex-shrink: 0;
    border-radius: 4px;
}

.admin-topbar-title {
    flex: 1;
    font-size: var(--fs-088);
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: rgba(255,255,255,0.88);
    padding-left: 6px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.admin-topbar-user {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 5px 10px 5px 6px;
    border-radius: 22px;
    background: rgba(255,255,255,0.07);
    border: 1px solid rgba(255,255,255,0.12);
    max-width: 160px;
    flex-shrink: 0;
}

.admin-topbar-avatar {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--fs-072);
    font-weight: 800;
    color: #fff;
    flex-shrink: 0;
    text-transform: uppercase;
}

.admin-topbar-name {
    font-size: var(--fs-078);
    font-weight: 600;
    color: rgba(255,255,255,0.88);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Hamburger lives inside .admin-mobile-topbar on mobile — no fixed position needed. */
.admin-hamburger {
    display: inline-flex;
    position: static;
    width: 44px;
    height: 44px;
    padding: 0;
    border: none;
    border-radius: 10px;
    background: transparent;
    color: var(--header-text, #fff);
    cursor: pointer;
    align-items: center;
    justify-content: center;
    transition: background-color 160ms ease-out;
    flex-shrink: 0;
}
.admin-hamburger:hover  { background: rgba(255,255,255,0.09); }
.admin-hamburger:active { background: rgba(255,255,255,0.15); }

.admin-backdrop {
    display: none;
    position: fixed;
    inset: 0;
    /* Navy-tinted rather than pure black — app recedes into the sidebar's
       color world instead of just dimming. */
    background: rgba(15, 23, 42, 0.55);
    -webkit-backdrop-filter: blur(3px);
    backdrop-filter: blur(3px);
    z-index: 99;
    opacity: 0;
    transition: opacity 260ms cubic-bezier(0.32, 0.72, 0, 1);
}
.admin-backdrop.visible {
    display: block;
    opacity: 1;
}

/* Staggered nav reveal — plays once the drawer has started entering.
   Each nav item fades + slides 8px with 40ms offset. Subtle, not showy. */
@keyframes admin-nav-reveal {
    from { opacity: 0; transform: translateX(-8px); }
    to   { opacity: 1; transform: translateX(0); }
}

/* ---- Responsive: mobile drawer ---- */
@media (max-width: 767px) {
    .admin-layout {
        flex-direction: column;
    }

    .admin-mobile-topbar {
        display: flex;
    }

    .admin-sidebar {
        position: fixed;
        top: calc(60px + env(safe-area-inset-top, 0px));
        left: 0;
        width: min(284px, 82vw);
        height: calc(100vh - 60px - env(safe-area-inset-top, 0px));
        transform: translateX(-100%);
        /* iOS-style confident ease — hits, then settles. */
        transition: transform 260ms cubic-bezier(0.32, 0.72, 0, 1);
        will-change: transform;
        z-index: 100;
        /* Layered elevation: tight ambient + far soft. */
        box-shadow:
            1px 0 0 rgba(255, 255, 255, 0.04),
            6px 0 12px rgba(15, 23, 42, 0.28),
            20px 0 48px rgba(15, 23, 42, 0.22);
    }

    /* Topbar already provides branding — hide the logo and compact the heading */
    .admin-sidebar .admin-sidebar-logo {
        display: none;
    }
    .admin-sidebar h2 {
        font-size: var(--fs-085);
        margin-top: 0;
        margin-bottom: var(--space-sm);
        padding-bottom: var(--space-xs, 4px);
    }

    .admin-sidebar.open {
        transform: translateX(0);
    }

    .admin-sidebar.open .admin-nav-item {
        opacity: 0;
        animation: admin-nav-reveal 280ms cubic-bezier(0.32, 0.72, 0, 1) forwards;
    }
    .admin-sidebar.open nav .admin-nav-item:nth-child(1) { animation-delay: 120ms; }
    .admin-sidebar.open nav .admin-nav-item:nth-child(2) { animation-delay: 160ms; }
    .admin-sidebar.open nav .admin-nav-item:nth-child(3) { animation-delay: 200ms; }
    .admin-sidebar.open nav .admin-nav-item:nth-child(4) { animation-delay: 240ms; }
    .admin-sidebar.open nav .admin-nav-item:nth-child(5) { animation-delay: 280ms; }
    .admin-sidebar.open .admin-sidebar-footer .admin-nav-item:nth-child(1) { animation-delay: 320ms; }
    .admin-sidebar.open .admin-sidebar-footer .admin-nav-item:nth-child(2) { animation-delay: 360ms; }

    @media (prefers-reduced-motion: reduce) {
        .admin-sidebar,
        .admin-backdrop { transition-duration: 0ms; }
        .admin-sidebar.open .admin-nav-item { animation: none; opacity: 1; }
    }

    .admin-main {
        padding: calc(72px + env(safe-area-inset-top, 0px)) var(--space-md) var(--space-md);
        width: 100%;
    }
}

@media (min-width: 768px) {
    .admin-mobile-topbar,
    .admin-backdrop { display: none !important; }
}

/* ---- Home link + Logout button footer items ---- */
.admin-home-link {
    text-decoration: none;
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    transition: color 0.2s;
}
.admin-home-link svg {
    opacity: 0.7;
    transition: opacity 0.2s;
}
.admin-home-link:hover svg {
    opacity: 1;
}
.admin-logout-btn {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
}
.admin-logout-btn svg {
    opacity: 0.7;
    flex-shrink: 0;
    transition: opacity 0.2s;
}
.admin-logout-btn:hover svg {
    opacity: 1;
}

/* ---- Add League form: card grid ---- */
.add-league-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-md);
    margin-bottom: var(--space-md);
}
.add-league-grid .admin-card.full {
    grid-column: 1 / -1;
}
@media (max-width: 768px) {
    .add-league-grid { grid-template-columns: 1fr; }
}
.add-league-row {
    display: flex;
    gap: var(--space-md);
    flex-wrap: wrap;
}
.add-league-row .form-group {
    flex: 1;
    min-width: 100px;
}
@media (max-width: 480px) {
    .add-league-row {
        flex-direction: column;
        align-items: stretch !important;
    }
    .add-league-row .form-group {
        min-width: 0;
        width: 100%;
        text-align: left;
    }
}

/* ---- Custom file input (force English labels) ---- */
.custom-file-input {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
}
.custom-file-input input[type="file"] {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    overflow: hidden;
    pointer-events: none;
}
.custom-file-input .file-btn {
    padding: var(--space-xs) var(--space-sm);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    cursor: pointer;
    font-size: var(--fs-085);
    white-space: nowrap;
    color: var(--color-text);
}
.custom-file-input .file-btn:hover {
    background: var(--color-bg);
}
.custom-file-input .file-name {
    font-size: var(--fs-085);
    color: var(--color-text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

/* ---- Dashboard manager view ---- */
.dashboard-manager-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-md);
}
@media (max-width: 900px) {
    .dashboard-manager-grid { grid-template-columns: 1fr; }
}
.dashboard-list {
    list-style: none;
    padding: 0;
    margin: 0;
}
.dashboard-list li {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    padding: var(--space-sm);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    margin-bottom: var(--space-xs);
    background: var(--color-bg);
}
.dashboard-list li.dragging { opacity: 0.4; }
.dashboard-list li.drag-over { border-color: var(--color-accent); }
.dashboard-list .drag-handle {
    cursor: grab;
    color: var(--color-text-muted);
    user-select: none;
    font-size: var(--fs-110);
}
.dashboard-list .league-name {
    flex: 1;
}
.dashboard-save-bar {
    margin-top: var(--space-md);
    display: flex;
    gap: var(--space-sm);
}

/* ---- Player manager ---- */
.player-search-results {
    list-style: none;
    margin: 0;
    padding: 0;
    max-height: 240px;
    overflow-y: auto;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-surface);
}
.player-search-results li {
    padding: 6px 12px;
    cursor: pointer;
    border-bottom: 1px solid var(--color-border);
    font-size: var(--fs-090);
}
.player-search-results li:last-child { border-bottom: none; }
.player-search-results li:hover { background: var(--color-hover); }
.player-search-results li.muted {
    cursor: default;
    color: var(--color-text-muted);
    font-style: italic;
}
.player-meta-tag {
    display: inline-block;
    margin-left: var(--space-xs);
    padding: 1px 6px;
    background: var(--color-accent-light, #dbeafe);
    color: var(--color-accent, #2563eb);
    border-radius: var(--radius-sm);
    font-size: var(--fs-070);
    font-weight: 600;
}
.player-meta-inactive {
    background: var(--color-bg-muted, #e5e7eb);
    color: var(--color-text-muted, #6b7280);
}
.player-meta-hidden {
    background: #fee2e2;
    color: #b91c1c;
}
.player-photo-row {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    flex-wrap: wrap;
}
.player-photo-preview {
    width: 80px;
    height: 80px;
    border-radius: 50%;
    border: 2px solid var(--color-border);
    background: var(--color-bg);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    flex-shrink: 0;
}
.player-photo-preview img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}
.player-photo-preview .muted {
    color: var(--color-text-muted);
    font-size: var(--fs-075);
}
.player-preview-frame {
    width: 100%;
    height: 600px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-surface);
}

/* ---- Player autocomplete dropdown ---- */
.player-autocomplete {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    list-style: none;
    margin: 0;
    padding: 4px 0;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    box-shadow: 0 4px 12px rgba(0,0,0,0.15);
    z-index: 100;
    max-height: 200px;
    overflow-y: auto;
}
.player-autocomplete[hidden] { display: none; }
.player-autocomplete li {
    padding: 8px 12px;
    cursor: pointer;
    font-size: var(--fs-090);
}
.player-autocomplete li:hover {
    background: var(--color-hover);
}
.player-autocomplete .ac-hint {
    color: var(--color-text-muted);
    font-size: 0.82em;
    font-weight: 400;
}

/* ========================================================================
   Step 6.6b — Mobile Matrix for Admin Pages
   admin.html does NOT load components.css, so these rules are standalone.
   ======================================================================== */

/* Dual-label toggle (Step 6.6 pattern, standalone for admin-only pages) */
.th-abbr { display: none; }

@media (max-width: 640px) {
    .th-full { display: none; }
    .th-abbr { display: inline; }

    /* Admin table compression — font-large tables keep their enum size (iron rule 3) */
    .admin-table:not(.font-large) {
        font-size: var(--fs-070);
        width: 100%;
        table-layout: auto;
    }
    .admin-table:not(.font-large) thead th {
        padding: 3px 2px;
        font-size: var(--fs-065);
        white-space: nowrap;
    }
    .admin-table:not(.font-large) tbody td {
        padding: 2px 3px;
    }
    .admin-table:not(.font-large) tbody td input[type="text"],
    .admin-table:not(.font-large) tbody td input[type="number"],
    .admin-table:not(.font-large) tbody td select {
        font-size: var(--fs-070);
        padding: 1px 3px;
    }

    /* Forms: add-league grid collapses to 1-col (also set at 768px) */
    .add-league-grid { grid-template-columns: 1fr; }

    /* Edit-league form uses inline flex-wrap with min-width:80-140px;
       force each form-group to stack full-width on mobile */
    .admin-content .form-group {
        flex: 1 1 100% !important;
        min-width: 0 !important;
    }

    /* CSV editor is 10 cols — stays on horizontal scroll (min-width:max-content) */
    .admin-table-compact { min-width: max-content; }
    .table-scroll { overflow-x: auto; }
}

/* ---- League-type pill (mirrors components.css for admin page, which
   doesn't load components.css) ---- */
.league-type-pill {
    display: inline-block;
    padding: 2px 10px;
    font-size: 0.8em;
    font-weight: 600;
    border-radius: var(--radius-full);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    line-height: 1.5;
}
.league-type-pill.type-doubling {
    background: var(--lt-doubling-bg);
    color: var(--lt-doubling-text);
}
.league-type-pill.type-regular {
    background: var(--lt-regular-bg);
    color: var(--lt-regular-text);
}
.league-type-pill.type-ubc {
    background: var(--lt-ubc-bg);
    color: var(--lt-ubc-text);
}

/* ---- Status pill (mirrors components.css for admin page) ---- */
.status-pill {
    display: inline-block;
    padding: 2px 12px;
    border-radius: var(--radius-full);
    font-size: var(--fs-082);
    font-weight: 600;
    letter-spacing: 0.3px;
}
.status-running {
    background: var(--color-running-bg);
    color: var(--color-running);
}
.status-completed {
    background: var(--color-completed-bg);
    color: var(--color-completed);
}
