:root {
  --bg: #070c1a;
  --text: #eef2f9;
  --muted: #9aa6bf;
  --accent: #f59e0b;
  --accent-2: #38bdf8;
  --green: #34d399;
  --border: rgba(255, 255, 255, 0.09);
}

* { box-sizing: border-box; }

body {
  font-family: Inter, ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
  margin: 0;
  min-height: 100vh;
  background:
    radial-gradient(900px 420px at 10% -10%, rgba(56, 189, 248, 0.18), transparent 65%),
    radial-gradient(800px 400px at 90% 0%, rgba(220, 38, 38, 0.16), transparent 60%),
    var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
}

.container {
  max-width: 1180px;
  margin: 0 auto;
  padding: 36px 20px 56px;
}

.page-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 24px;
}

.page-head .title-row {
  display: flex;
  align-items: center;
  gap: 12px;
}

/* Single Moroccan flag for the whole page: the site is about the
   Atlas Lions, so the flag lives once in the header rather than on
   every card. Kept bare (no badge, no tinted panel) so it reads as a
   flag and not as a red button. */
.brand-flag {
  flex: 0 0 auto;
  display: inline-block;
  font-size: 30px;
  line-height: 1;
}

.page-head h1 {
  margin: 0;
  font-size: 34px;
  letter-spacing: -0.5px;
  background: linear-gradient(92deg, #ffffff, #ffd8a8 55%, #7dd3fc);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.head-actions { display: flex; align-items: center; gap: 12px; }
.status { color: var(--muted); font-size: 12.5px; text-align: right; }

button {
  border: 1px solid rgba(56, 189, 248, 0.45);
  background: linear-gradient(180deg, rgba(56, 189, 248, 0.22), rgba(56, 189, 248, 0.08));
  color: #eaf6ff;
  border-radius: 999px;
  padding: 10px 18px;
  cursor: pointer;
  font-weight: 600;
  font-size: 14px;
  transition: transform 0.15s ease, background 0.15s ease;
}

button:hover:not(:disabled) { background: rgba(56, 189, 248, 0.3); transform: translateY(-1px); }
button:disabled { opacity: 0.6; cursor: default; transform: none; }

.grid {
  display: grid;
  gap: 18px;
  grid-template-columns: repeat(auto-fill, minmax(290px, 1fr));
}

.card {
  background: linear-gradient(165deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0.02));
  border: 1px solid var(--border);
  border-radius: 18px;
  box-shadow: 0 18px 34px rgba(3, 7, 18, 0.45);
  padding: 18px;
}

.player-card {
  display: flex;
  flex-direction: column;
  gap: 12px;
  transition: transform 0.18s ease, border-color 0.18s ease;
}

.player-card:hover { transform: translateY(-3px); border-color: rgba(56, 189, 248, 0.4); }

.player-head { display: flex; align-items: center; gap: 14px; }
.player-info { min-width: 0; }

.player-photo-wrap { position: relative; flex: 0 0 76px; }

.player-photo {
  width: 76px;
  height: 76px;
  flex: 0 0 76px;
  object-fit: cover;
  object-position: center top;
  border-radius: 50%;
  border: 2px solid rgba(56, 189, 248, 0.35);
  background: #0f1730;
  display: block;
}

.player-photo.placeholder {
  display: grid;
  place-items: center;
  color: var(--muted);
  font-size: 11px;
  text-align: center;
}

/* The position sits inline in the position / age meta line rather
   than in a badge that would compete with the match-status pill. */
.meta-position { color: #e2e8f0; }

.player-name { margin: 0 0 4px; font-size: 19px; line-height: 1.2; }
/* Two stacked lines — club, then position and age — left-aligned on the
   same edge as the name above them. */
.player-meta {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  margin: 0 0 8px;
  color: var(--muted);
  font-size: 12.5px;
}
.meta-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 8px;
  min-width: 0;
  max-width: 100%;
}
.player-meta .meta-item + .meta-item::before {
  content: '\00b7';
  margin-right: 8px;
  color: var(--border);
}
.player-meta .meta-club { color: #e2e8f0; font-weight: 600; display: inline-flex; align-items: center; gap: 5px; }
/* The club crest sits inline beside the club name, not in a badge. */
.meta-crest { width: 16px; height: 16px; object-fit: contain; flex: 0 0 16px; }
.muted { color: var(--muted); font-size: 13px; }
.muted a { color: #7dd3fc; text-decoration: none; }
.muted a:hover { text-decoration: underline; }

.player-badges {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-bottom: 6px;
}

.badge {
  display: inline-block;
  border-radius: 999px;
  padding: 3px 10px;
  font-size: 11.5px;
  font-weight: 600;
  border: 1px solid var(--border);
  color: var(--muted);
}

/* Status and classification badges sit side by side in the same row, so
   they share one pill geometry. The vertical padding is what keeps the
   rounded border off the icon disc, so it stays comfortably larger than
   the 1px border it has to clear. */
.badge.player-status,
.badge.classification {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 11px 4px 5px;
  font-weight: 700;
  letter-spacing: 0.01em;
  line-height: 16px;
}
.status-icon {
  display: inline-grid;
  width: 16px;
  height: 16px;
  place-items: center;
  border-radius: 50%;
  color: #fff;
  font-size: 10px;
  line-height: 1;
}
/* Starter is teal, not green: green belongs to the "main guard" class
   badge, and the two pills sit side by side on a card. Teal keeps the
   "on the pitch" reading and stays in the same cool family as the
   substitute blue, which is the other half of the same match-role axis
   (the two are mutually exclusive, so they never clash). */
.badge.starter { color: #ccfbf1; border-color: rgba(45, 212, 191, 0.55); background: rgba(13, 148, 136, 0.16); }
.badge.starter .status-icon { background: #0d9488; }
.badge.substitute { color: #dbeafe; border-color: rgba(96, 165, 250, 0.5); background: rgba(37, 99, 235, 0.14); }
.badge.substitute .status-icon { background: #2563eb; }
.badge.benched { color: #e2e8f0; border-color: rgba(148, 163, 184, 0.45); background: rgba(71, 85, 105, 0.18); }
.badge.benched .status-icon { background: #64748b; }
.badge.injured { color: #fee2e2; border-color: rgba(248, 113, 113, 0.55); background: rgba(220, 38, 38, 0.14); }
.badge.injured .status-icon { background: #dc2626; }
.badge.unavailable { color: #e2e8f0; border-color: rgba(148, 163, 184, 0.45); background: rgba(71, 85, 105, 0.18); }
.badge.unavailable .status-icon { background: #64748b; }
.injury-note {
  display: inline-flex;
  margin-top: 7px;
  padding: 4px 8px;
  border-radius: 8px;
  color: #fecaca;
  background: rgba(127, 29, 29, 0.24);
  font-size: 12px;
}
.badge.classification.hidden-gem {
  color: #faf5ff;
  border-color: rgba(216, 180, 254, 0.9);
  background: linear-gradient(135deg, rgba(245, 243, 255, 0.28), rgba(168, 85, 247, 0.25), rgba(88, 28, 135, 0.22));
  box-shadow: 0 0 11px rgba(168, 85, 247, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.48);
}
.badge.classification.high-prospect {
  color: #fff7ed;
  border-color: rgba(251, 146, 60, 0.85);
  background: linear-gradient(135deg, rgba(253, 186, 116, 0.3), rgba(249, 115, 22, 0.24), rgba(154, 52, 18, 0.2));
  box-shadow: 0 0 10px rgba(249, 115, 22, 0.32), inset 0 1px 0 rgba(255, 255, 255, 0.35);
}
.badge.classification.rising-star {
  color: #fef3c7;
  border-color: rgba(250, 204, 21, 0.72);
  background: linear-gradient(135deg, rgba(250, 204, 21, 0.25), rgba(161, 98, 7, 0.18));
  box-shadow: 0 0 10px rgba(250, 204, 21, 0.18), inset 0 1px 0 rgba(255, 255, 255, 0.2);
}
.badge.classification.main-guard {
  color: #ecfdf5;
  border-color: rgba(34, 201, 115, 0.75);
  background: linear-gradient(135deg, rgba(34, 201, 115, 0.3), rgba(6, 95, 70, 0.22));
  box-shadow: 0 0 10px rgba(34, 201, 115, 0.32), inset 0 1px 0 rgba(255, 255, 255, 0.3);
}
.badge.classification.hidden-gem .status-icon { background: #a855f7; }
.badge.classification.high-prospect .status-icon { background: #f97316; }
.badge.classification.rising-star .status-icon { background: #ca8a04; }
.badge.classification.main-guard .status-icon { background: #16a34a; }

.stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }

.stat {
  background: rgba(56, 189, 248, 0.09);
  border: 1px solid rgba(56, 189, 248, 0.25);
  border-radius: 12px;
  padding: 9px 2px;
  text-align: center;
  font-size: 9px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.2px;
}

.stat b { display: block; color: #eaf6ff; font-size: 16px; letter-spacing: 0; margin-bottom: 2px; }
.stat-goals b { color: #6ee7b7; }
.stat-assists b { color: #7dd3fc; }
.stat-minutes b { color: #c7d2fe; }
.stat-rating.rating-elite b { color: #4ade80; }
.stat-rating.rating-good b { color: #a3e635; }
.stat-rating.rating-fair b { color: #fbbf24; }
.stat-rating.rating-low b { color: #f87171; }

.match { border-top: 1px solid var(--border); padding-top: 12px; }
.match-teams { display: flex; align-items: baseline; gap: 10px; font-size: 14px; font-weight: 600; }
.match-fixture { flex: 1 1 auto; min-width: 0; }
.match-score { color: var(--accent); }
/* The result is wording, not a badge: no fill and no glow, just a quiet
   divider and a tinted label so it reads as part of the match line
   instead of competing with the status pills higher up the card. */
.match-result {
  flex: 0 0 auto;
  padding-left: 10px;
  border-left: 1px solid var(--border);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--muted);
}
.match-result.win { color: #6ee7b7; }
.match-result.loss { color: #fca5a5; }
.match-result.draw { color: #cbd5e1; }
.match-meta { margin-top: 4px; }
.match-link { margin-top: 6px; }

/* One condensed filter bar for the whole dashboard, split into two clearly
   labelled sections: "Filter" (a grid of filter buttons — Leagues, Spotlight,
   Position, Age … — plus a single zone underneath that the open filter renders
   its panel into) and "Rank by" (the ordering control). Clicking another filter
   button swaps the panel in place instead of opening a second row (see
   `FILTER_TABS` in app.js). Sticky so the filters stay reachable while
   scrolling a long grid. The sections sit directly on the page background
   (no card/box behind them) so they read as part of the page rather than a
   separate panel. */
.filter-bar {
  position: sticky;
  top: 12px;
  z-index: 5;
  margin-bottom: 16px;
}

.filter-section { padding: 12px 12px 14px; }

.quick-view-section,
.rank-section {
  padding: 12px 12px 14px;
  border-top: 1px solid var(--border);
}

.filter-section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 12px;
  margin-bottom: 10px;
}

.filter-section-title {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin: 0;
  color: var(--muted);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.9px;
}

.filter-section-icon { font-size: 12px; line-height: 1; opacity: 0.85; }

.filter-section-actions { display: flex; align-items: center; gap: 8px; }

/* Two per line on a phone, more as the viewport grows. */
.filter-tabs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
  align-items: stretch;
  gap: 8px;
  min-width: 0;
}

.filter-tab {
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  min-height: 38px;
  padding: 8px 14px;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.04);
  color: var(--muted);
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.1;
  text-align: left;
  white-space: nowrap;
  transition: background 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
}

/* Specificity has to match-or-beat the global `button:hover:not(:disabled)`
   rule, otherwise its blue gradient wins over the flat tint used here. */
button.filter-tab:hover,
button.filter-tab:active,
button.filter-tab:focus {
  color: var(--text);
  border-color: var(--border);
  background: rgba(255, 255, 255, 0.08);
  box-shadow: none;
  transform: none;
}

button.filter-tab:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; }

/* The open filter is tinted like a selected chip, so it is obvious which
   button the shared panel below belongs to. */
button.filter-tab.open,
button.filter-tab.open:hover,
button.filter-tab.open:focus {
  background: rgba(56, 189, 248, 0.16);
  color: #dff3ff;
  border-color: rgba(56, 189, 248, 0.4);
  box-shadow: inset 0 0 0 1px rgba(56, 189, 248, 0.4);
}

/* Switched off while a quick view is on: still legible, plainly not tappable. */
button.filter-tab[disabled],
button.filter-tab[disabled]:hover {
  opacity: 0.45;
  cursor: default;
  background: rgba(255, 255, 255, 0.03);
  box-shadow: none;
}

.filter-tab-icon { font-size: 16px; line-height: 1; opacity: 0.9; }

.filter-tab-caret {
  /* Pinned to the trailing edge so every button's caret lines up down the
     grid, however long the label or badge is. */
  margin-left: auto;
  font-size: 10px;
  line-height: 1;
  opacity: 0.75;
  transition: transform 0.15s ease;
}

.filter-tab.open .filter-tab-caret { transform: rotate(180deg); }

/* Only shown once the visitor has actually narrowed that filter, so the
   resting bar stays quiet (no player counts on load). */
.filter-toggle-count {
  padding: 2px 7px;
  border-radius: 999px;
  background: rgba(56, 189, 248, 0.22);
  color: #dff3ff;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: normal;
}

/* Quick views are pill-shaped shortcuts in their own labelled section. While
   one is active the filter buttons are disabled because it replaces filters
   instead of stacking with them. */
.quick-views {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.quick-view {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 13px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.04);
  color: var(--muted);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
}

/* Beats the global `button:hover:not(:disabled)` gradient, like `.filter-tab`
   has to. */
button.quick-view:hover,
button.quick-view:active,
button.quick-view:focus {
  color: var(--text);
  border-color: var(--border);
  background: rgba(255, 255, 255, 0.08);
  box-shadow: none;
  transform: none;
}

button.quick-view:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; }

button.quick-view.active,
button.quick-view.active:hover,
button.quick-view.active:focus {
  background: rgba(56, 189, 248, 0.16);
  color: #dff3ff;
  border-color: rgba(56, 189, 248, 0.4);
  box-shadow: inset 0 0 0 1px rgba(56, 189, 248, 0.4);
}

.quick-view-icon { font-size: 12px; line-height: 1; opacity: 0.85; }
.quick-view[data-quick-view="injured"] .quick-view-icon {
  display: inline-grid;
  width: 16px;
  height: 16px;
  place-items: center;
  border-radius: 50%;
  background: #dc2626;
  color: #fff;
  font-size: 10px;
}
.quick-view.active .quick-view-icon { opacity: 1; color: #fbbf24; }
.quick-view[data-quick-view="injured"].active .quick-view-icon { color: #fff; }

.quick-view-count {
  font-variant-numeric: tabular-nums;
  font-size: 11px;
  font-weight: 700;
  padding: 1px 6px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.07);
  color: inherit;
}

.quick-view.active .quick-view-count { background: rgba(56, 189, 248, 0.22); }

/* Full-width under the row rather than beside it, so the buttons keep their
   line. */
.quick-view-hint { flex: 1 0 100%; margin: 2px 2px 0; font-size: 12px; }

.filter-clear-all {
  padding: 6px 12px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
}

button.filter-clear-all:hover,
button.filter-clear-all:focus {
  background: rgba(255, 255, 255, 0.08);
  color: var(--text);
  border-color: var(--border);
  box-shadow: none;
  transform: none;
}

/* The shared zone: empty and hidden until a filter is opened, then filled
   with that filter's chips (or its slider) plus one common actions line. */
.filter-panel {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 14px;
  margin-top: 12px;
  padding: 12px 4px 0;
  border-top: 1px solid var(--border);
}

.filter-panel[hidden] { display: none; }

.filter-panel-body { flex: 1 1 100%; min-width: 0; }

/* An up arrow rather than a cross: the panel folds back into its button, it
   is not dismissed, and nothing about the selection is lost. */
.filter-panel-close {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.05);
  color: var(--muted);
  font-size: 11px;
  line-height: 1;
  cursor: pointer;
}

button.filter-panel-close:hover,
button.filter-panel-close:focus {
  background: rgba(255, 255, 255, 0.1);
  color: var(--text);
  border-color: var(--border);
  box-shadow: none;
  transform: none;
}

.flag-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; flex: 1 1 auto; }

.country-filter-actions { display: flex; align-items: center; gap: 10px; margin-left: auto; }

.country-filter-count { color: var(--muted); font-size: 12px; white-space: nowrap; }

.country-filter-reset {
  padding: 6px 14px;
  font-size: 12px;
  font-weight: 600;
  border-color: var(--border);
  background: rgba(255, 255, 255, 0.05);
  color: var(--muted);
}

.country-filter-reset:hover:not(:disabled) { background: rgba(255, 255, 255, 0.09); color: var(--text); }

.flag-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px 6px 10px;
  /* Same soft-square radius as the view tabs above rather than a pill,
     so the filter rows read as one family. */
  border-radius: 9px;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.04);
  cursor: pointer;
  transition: transform 0.15s ease, opacity 0.15s ease, background 0.15s ease, border-color 0.15s ease,
    box-shadow 0.15s ease;
  color: var(--text);
  font: inherit;
}

.flag-chip:hover { transform: translateY(-1px); border-color: rgba(56, 189, 248, 0.55); }
.flag-chip:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; }

.flag-chip .flag-emoji {
  font-size: 19px;
  line-height: 1;
  transition: filter 0.15s ease, opacity 0.15s ease;
}
img.flag-emoji {
  width: 22px;
  height: 16px;
  object-fit: cover;
  border-radius: 2px;
  display: block;
}

.flag-chip .flag-label {
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.1px;
}

/* Count of players currently in that league, so the filter doubles as a
   squad summary. */
.flag-chip .flag-count {
  min-width: 20px;
  padding: 1px 6px;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.08);
  font-size: 11px;
  font-weight: 700;
  line-height: 1.5;
  text-align: center;
  color: var(--muted);
}

.flag-chip.selected {
  background: rgba(56, 189, 248, 0.16);
  border-color: rgba(56, 189, 248, 0.55);
  box-shadow: inset 0 0 0 1px rgba(56, 189, 248, 0.14);
}

.flag-chip.selected .flag-count { background: rgba(56, 189, 248, 0.28); color: #dff3ff; }

.flag-chip.deselected { opacity: 0.55; }
.flag-chip.deselected .flag-emoji { filter: grayscale(1); opacity: 0.75; }
.flag-chip.deselected .flag-label { color: var(--muted); }

/* Spotlight chips reuse the classification badge palette (see
   `.badge.classification.*`) so a chip and the badge on a card read as
   the same thing; the dot carries the colour when deselected. */
.chip-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--chip-color, rgba(148, 163, 184, 0.7));
  box-shadow: 0 0 6px var(--chip-glow, transparent);
  flex: none;
}

.flag-chip.class-chip { --chip-color: rgba(148, 163, 184, 0.75); }
.flag-chip.class-hidden-gem { --chip-color: #c084fc; --chip-glow: rgba(168, 85, 247, 0.55); }
.flag-chip.class-high-prospect { --chip-color: #fb923c; --chip-glow: rgba(249, 115, 22, 0.5); }
.flag-chip.class-rising-star { --chip-color: #facc15; --chip-glow: rgba(250, 204, 21, 0.45); }
.flag-chip.class-main-guard { --chip-color: #22c973; --chip-glow: rgba(34, 201, 115, 0.5); }

.flag-chip.class-chip.selected {
  background: color-mix(in srgb, var(--chip-color) 16%, transparent);
  border-color: color-mix(in srgb, var(--chip-color) 55%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--chip-color) 16%, transparent);
}

.flag-chip.class-chip.selected .flag-count {
  background: color-mix(in srgb, var(--chip-color) 26%, transparent);
  color: var(--text);
}

.flag-chip.deselected .chip-dot { filter: grayscale(1); box-shadow: none; opacity: 0.7; }
.flag-chip .chip-icon { font-size: 14px; line-height: 1; flex: none; }
.flag-chip.deselected .chip-icon { filter: grayscale(1); opacity: 0.75; }

/* One shared bar carries both ends of the age range: the two range inputs
   are stacked on top of the same track so only their thumbs are grabbable,
   and the highlighted section between them is drawn from the percentages
   the script writes into --age-range-start / --age-range-end. */
.age-range {
  display: grid;
  gap: 8px;
  flex: 1 1 320px;
}

.age-range-values {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  color: var(--muted);
  font-size: 12px;
}
.age-range b { color: var(--text); }

.age-range-slider { position: relative; height: 24px; }

.age-range-track,
.age-range-fill {
  position: absolute;
  top: 50%;
  height: 4px;
  border-radius: 999px;
  transform: translateY(-50%);
  pointer-events: none;
}

.age-range-track { left: 0; right: 0; background: rgba(148, 163, 184, 0.3); }

.age-range-fill {
  left: var(--age-range-start, 0%);
  right: calc(100% - var(--age-range-end, 100%));
  background: var(--accent-2);
}

.age-range-slider input {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 24px;
  margin: 0;
  background: none;
  appearance: none;
  -webkit-appearance: none;
  pointer-events: none;
}

.age-range-slider[data-age-top='min'] input[data-age-min] { z-index: 2; }
.age-range-slider[data-age-top='max'] input[data-age-max] { z-index: 2; }

.age-range-slider input:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 4px; }

.age-range-slider input::-webkit-slider-thumb {
  appearance: none;
  -webkit-appearance: none;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 2px solid var(--accent-2);
  background: var(--text);
  cursor: pointer;
  pointer-events: auto;
}

.age-range-slider input::-moz-range-thumb {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 2px solid var(--accent-2);
  background: var(--text);
  cursor: pointer;
  pointer-events: auto;
}

.age-range-slider input::-moz-range-track { background: none; }

@media (max-width: 720px) {
  .country-filter-actions { width: 100%; justify-content: space-between; margin-left: 0; }
  .age-range { flex-basis: 100%; }
}

@media (max-width: 520px) {
  .page-head h1 { font-size: 27px; }
  .brand-flag { font-size: 24px; }
  .head-actions { width: 100%; justify-content: space-between; }
  .filter-bar { position: static; }
  /* Only the league chips lose their labels here: the flag carries the
     country, while the spotlight/position chips are text-only. */
  .flag-chip[data-country] .flag-label { display: none; }
  .player-head { position: relative; }
  .player-info { flex: 1 1 auto; }
  /* The share button is pinned to the head's top right corner here, so the
     name and club line keep its width clear; the details line sits below
     the button and uses the full width. */
  .player-name { padding-right: 80px; }
  .player-head .meta-line-club { padding-right: 80px; }
  .player-head .player-head-actions { position: absolute; top: 0; right: 0; }
}

/* The ranking half of the filter bar, under its own "Rank by" title: a
   compact segmented control, since the ranking options are few and mutually
   exclusive — deliberately lighter than the filter buttons above it so the
   two sections never look like one row of look-alike controls. */
.sort-filter {
  display: flex;
  /* On very narrow viewports the toggle scrolls horizontally (see
     `.sort-toggle` overflow below) instead of wrapping to a second line. */
  flex-wrap: nowrap;
  align-items: center;
  gap: 10px;
  min-width: 0;
}

.sort-filter:empty { display: none; }

.sort-toggle {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 3px;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--border);
  /* Fallback for when the box is too narrow for label + all options:
     scroll the toggle itself rather than wrapping to a second line. */
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
}

.sort-toggle::-webkit-scrollbar { display: none; }

.sort-toggle-option {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 14px;
  border-radius: 9px;
  border: none;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.1px;
  white-space: nowrap;
  flex-shrink: 0;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
}

.sort-toggle-option:hover { color: var(--text); background: rgba(255, 255, 255, 0.05); }
.sort-toggle-option:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; }

/* Matches the selected league chip: a flat tint rather than a glossy
   gradient, so the two filter rows read as one family. */
.sort-toggle-option.active {
  background: rgba(56, 189, 248, 0.16);
  color: #dff3ff;
  box-shadow: inset 0 0 0 1px rgba(56, 189, 248, 0.4);
}

.sort-toggle-option.active:hover { background: rgba(56, 189, 248, 0.22); color: #dff3ff; }

/* Its own row, and never re-rendered while the user types: rewriting the
   input's markup on each keystroke would drop focus and the caret. No
   panel around it — the prominence comes from the field itself, which is
   tinted with the sky accent already used by the selected chips. */
.search-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 14px;
  margin-bottom: 16px;
}

.search-bar:empty { display: none; margin: 0; }

.search-field { position: relative; flex: 1 1 280px; min-width: 0; }

.search-field .search-icon {
  position: absolute;
  top: 50%;
  left: 14px;
  transform: translateY(-50%);
  font-size: 15px;
  line-height: 1;
  opacity: 0.9;
  pointer-events: none;
}

.player-search {
  width: 100%;
  padding: 13px 40px 13px 42px;
  border-radius: 12px;
  border: 1px solid rgba(56, 189, 248, 0.45);
  background: linear-gradient(165deg, rgba(56, 189, 248, 0.16), rgba(9, 16, 33, 0.85));
  color: var(--text);
  font: inherit;
  font-size: 14.5px;
  box-shadow: 0 10px 20px rgba(3, 7, 18, 0.3), inset 0 0 0 1px rgba(56, 189, 248, 0.1);
  transition: border-color 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}

.player-search::placeholder { color: #c3d3ea; }
.player-search:hover {
  border-color: rgba(56, 189, 248, 0.65);
  background: linear-gradient(165deg, rgba(56, 189, 248, 0.2), rgba(9, 16, 33, 0.85));
}
.player-search:focus {
  outline: none;
  border-color: rgba(56, 189, 248, 0.85);
  background: linear-gradient(165deg, rgba(56, 189, 248, 0.24), rgba(9, 16, 33, 0.88));
  box-shadow: 0 0 0 3px rgba(56, 189, 248, 0.22);
}

/* The native search clear affordance is inconsistent across browsers, so
   it is hidden in favour of an explicit button that matches the theme. */
.player-search::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }

.search-clear {
  position: absolute;
  top: 50%;
  right: 8px;
  transform: translateY(-50%);
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  padding: 0;
  border-radius: 50%;
  border: none;
  background: rgba(255, 255, 255, 0.09);
  color: var(--muted);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
}

.search-clear:hover:not(:disabled) { background: rgba(255, 255, 255, 0.16); color: var(--text); transform: translateY(-50%); }
.search-clear[hidden] { display: none; }

.search-summary { color: var(--muted); font-size: 12.5px; white-space: nowrap; }
.search-summary b { color: var(--text); }

/* Pagination */
.page-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin: 26px 0 8px;
}

.pagination {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 10px;
}

.pagination:empty { display: none; }

.page-list { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }

.page-btn {
  min-width: 38px;
  padding: 7px 12px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.04);
  color: var(--muted);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}

.page-btn:hover:not(:disabled):not(.active) {
  background: rgba(255, 255, 255, 0.09);
  color: var(--text);
  border-color: rgba(56, 189, 248, 0.45);
  transform: translateY(-1px);
}

.page-btn:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; }
.page-btn:disabled { opacity: 0.4; cursor: default; transform: none; }

/* Same flat tint as the selected league chip and the active sort option. */
.page-btn.active {
  background: rgba(56, 189, 248, 0.16);
  color: #dff3ff;
  border-color: rgba(56, 189, 248, 0.55);
  box-shadow: inset 0 0 0 1px rgba(56, 189, 248, 0.2);
  cursor: default;
}

.page-ellipsis { color: var(--muted); padding: 0 2px; user-select: none; }

.page-size {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  color: var(--muted);
  font-size: 12px;
}

.page-size select {
  padding: 6px 9px;
  border-radius: 9px;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.05);
  color: var(--text);
  font: inherit;
  font-size: 12.5px;
  cursor: pointer;
}

.page-size select:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 1px; }

.page-position { color: var(--muted); font-size: 12.5px; white-space: nowrap; display: none; }

@media (max-width: 520px) {
  .search-summary { width: 100%; }
  /* Page numbers wrap badly on a phone; prev/next plus the "page X of Y"
     label is enough to navigate there. */
  .page-list .page-number,
  .page-list .page-ellipsis { display: none; }
  .page-position { display: inline; }
}

/* Season aggregates land after the match card is already on screen, so
   the block is visually secondary to the match stats above it. */
.season-stats { border-top: 1px solid var(--border); padding-top: 10px; }

.season-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 7px;
  color: var(--muted);
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.7px;
}

/* One row per team the player turned out for. The crest is the only
   label, so it is given a fixed box and never shrinks away when the
   figures beside it wrap. */
.season-team-line {
  display: flex;
  align-items: center;
  gap: 8px;
}

.season-team-line + .season-team-line { margin-top: 6px; }

.season-team-line .detail-figures { margin-top: 0; }

.season-team-crest {
  width: 18px;
  height: 18px;
  flex: 0 0 18px;
  object-fit: contain;
}

.season-team-crest.placeholder {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  line-height: 1;
}

.season-pending { color: var(--muted); font-size: 12px; font-style: italic; }

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

/* The card's real action, so it keeps the sky accent used by the stats
   tiles and the selected filter chips instead of the muted ghost look
   (which read as disabled); still a quiet tint, not a solid fill. The
   highlights toggle shares this row but is deliberately excluded — it is
   a disclosure, not an action, and must not compete for the same weight. */
.card-action {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.2;
  border: 1px solid rgba(56, 189, 248, 0.45);
  border-radius: 999px;
  background: rgba(56, 189, 248, 0.16);
  color: #dff3ff;
  text-decoration: none;
  cursor: pointer;
  transition: transform 0.15s ease, background 0.15s ease;
}

.card-action:hover { background: rgba(56, 189, 248, 0.26); color: #eaf6ff; transform: translateY(-1px); }

.action-arrow { font-size: 10px; line-height: 1; }

/* Share is an icon button, not a pill: a plain round target that sits with
   the player's name at the top of the card (and of the profile hero), so it
   costs no width in the actions row and is where a reader looks for it. */
.icon-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 34px;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 1px solid rgba(148, 163, 184, 0.34);
  border-radius: 50%;
  background: rgba(148, 163, 184, 0.12);
  color: var(--muted);
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.icon-button:hover { background: rgba(148, 163, 184, 0.22); color: var(--text); }

.icon-button:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; }

/* The button sits at the head's right edge, level with the name. */
.share-button { margin-left: auto; align-self: flex-start; }

/* Confirmation after a desktop copy: the icon becomes a tick, and the green
   tint is what makes it register without a toast. */
.share-button.shared {
  border-color: rgba(52, 211, 153, 0.5);
  background: rgba(52, 211, 153, 0.2);
  color: #d7fbee;
}

.share-icon { display: block; width: 16px; height: 16px; }

/* Match highlights. The toggle sits on the actions row, pushed to its
   right edge, and the video opens below the whole row — so the card is no
   taller than it was before the feature existed, and grows only downwards
   when opened, leaving everything above it where the reader left it. */
.highlights-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
  padding: 6px 8px;
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
  background: transparent;
  border-color: transparent;
}

.highlights-toggle:hover:not(:disabled) { color: var(--text); background: rgba(148, 163, 184, 0.12); }

/* The two disclosures — match stats and highlights — are the same
   control, so they are drawn the same and sit together at the right end of
   the row; only the first of them takes the space before it. */
.highlights-toggle + .highlights-toggle { margin-left: 0; }
.card-actions [data-stats-toggle],
.last-game-disclosures .highlights-toggle { margin-left: 0; }

.highlights-external {
  display: inline-block;
  padding: 6px 8px;
  border-radius: 8px;
  color: var(--accent-2);
  font-size: 12px;
  font-weight: 600;
  text-decoration: none;
}

.highlights-external:hover { color: var(--text); background: rgba(148, 163, 184, 0.12); }

/* The arrow is the affordance the label leans on, so it gets the accent
   colour and turns to point the other way when the panel is open. */
.highlights-arrow { font-size: 10px; line-height: 1; color: var(--accent-2); }

/* The panel now also carries "searching" and "not available yet" text, so it
   needs a resting state that reads as a deliberate answer rather than an
   empty box waiting for a video. */
.highlights-status {
  margin: 0;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: rgba(148, 163, 184, 0.06);
  font-size: 13px;
}

.highlights-panel,
.stats-panel { margin-top: 10px; }

/* 16:9, so the player fills the card's width at whatever size the grid
   has given it without letterboxing or a fixed pixel height. */
.highlights-frame {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: #000;
}

/* Player profile page. Built mobile-first: one column, full width, with
   every figure block wrapping instead of scrolling sideways. It used to be
   a dialog over the dashboard; it is now a page of its own at
   `/player/<id>`, so the panel simply flows with the document. */
.player-profile {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 680px;
  margin: 0 auto;
}

/* Identity hero. No surface of its own: the portrait, the name and the
   badges sit straight on the page background, so the profile reads as a
   page rather than a card floating on one. */
.detail-hero {
  position: relative;
  padding: 0 2px 14px;
  border-bottom: 1px solid var(--border);
}

.hero-main { display: flex; align-items: center; gap: 14px; }

/* The hero portrait is deliberately identical to the update card's: same
   size, same ring, no extra glow. */
.detail-photo-wrap { flex: 0 0 76px; }

.detail-id { min-width: 0; flex: 1; }

.detail-player-name {
  margin: 0 0 6px;
  font-size: 20px;
  line-height: 1.2;
  letter-spacing: -0.2px;
}

.hero-badges { margin: 8px 0 0; }

.badge.hero-international {
  color: #ecfeff;
  border-color: rgba(56, 189, 248, 0.5);
  background: linear-gradient(135deg, rgba(56, 189, 248, 0.28), rgba(14, 116, 144, 0.24));
}

/* Everything under the hero simply follows it in the flow, with breathing
   room instead of a container. */
.player-profile > .last-game,
.player-profile > .detail-tabs { margin-top: 14px; }

.player-profile { padding-bottom: 18px; }

/* Section switcher. The tabs wrap onto a second line when the labels do
   not fit rather than living in a horizontally scrolling strip, which
   used to clip the trailing tab (and its label) out of view. */
.detail-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 12px;
}

.detail-tab {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  flex: 1 1 auto;
  padding: 7px 10px;
  font-size: 12.5px;
  line-height: 1.35;
  white-space: nowrap;
  border-color: var(--border);
  background: rgba(255, 255, 255, 0.04);
  color: var(--muted);
}

.detail-tab-icon { font-size: 12px; filter: saturate(1.2); }

.detail-tab[aria-selected='true'] {
  border-color: rgba(56, 189, 248, 0.45);
  background: linear-gradient(180deg, rgba(56, 189, 248, 0.3), rgba(56, 189, 248, 0.14));
  color: #eaf6ff;
  box-shadow: 0 4px 12px rgba(56, 189, 248, 0.16);
}

.detail-pane[hidden] { display: none; }

.detail-season-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin: 0 0 8px;
}

.detail-season-label {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--accent);
}


/* Three headline numbers first (apps / goals / assists), then every
   remaining season figure in a compact grid — ranked, never dropped. */
.detail-headline {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
}

.headline-stat {
  border-radius: 14px;
  padding: 10px 8px;
  text-align: center;
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(255, 255, 255, 0.05);
}

.headline-stat b { display: block; font-size: 26px; line-height: 1.1; font-weight: 800; }
.headline-label {
  display: block;
  margin-top: 2px;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: #dce6f6;
}
.headline-sub { display: block; margin-top: 2px; font-size: 10px; color: var(--muted); }

.headline-apps { border-color: rgba(148, 163, 184, 0.4); background: linear-gradient(180deg, rgba(148, 163, 184, 0.22), rgba(148, 163, 184, 0.06)); }
.headline-apps b { color: #e8eefb; }
.headline-goals { border-color: rgba(52, 211, 153, 0.45); background: linear-gradient(180deg, rgba(52, 211, 153, 0.24), rgba(52, 211, 153, 0.06)); }
.headline-goals b { color: #6ee7b7; }
.headline-assists { border-color: rgba(56, 189, 248, 0.45); background: linear-gradient(180deg, rgba(56, 189, 248, 0.24), rgba(56, 189, 248, 0.06)); }
.headline-assists b { color: #7dd3fc; }

.detail-stat-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 6px;
  margin-top: 8px;
}

.mini-stat {
  border-radius: 10px;
  padding: 7px 3px;
  text-align: center;
  border: 1px solid rgba(255, 255, 255, 0.08);
  background: rgba(255, 255, 255, 0.04);
  font-size: 9px;
  text-transform: uppercase;
  letter-spacing: 0.2px;
  color: var(--muted);
}

.mini-stat b { display: block; font-size: 14px; font-weight: 700; color: #eaf1ff; letter-spacing: 0; margin-bottom: 1px; }
.mini-goals b { color: #6ee7b7; }
.mini-assists b { color: #7dd3fc; }
.mini-minutes b { color: #c7d2fe; }
.mini-yellow { border-color: rgba(250, 204, 21, 0.32); background: rgba(250, 204, 21, 0.1); }
.mini-yellow b { color: #fde047; }
.mini-red { border-color: rgba(248, 113, 113, 0.35); background: rgba(248, 113, 113, 0.1); }
.mini-red b { color: #fca5a5; }
.mini-stat.rating-elite b { color: #4ade80; }
.mini-stat.rating-good b { color: #a3e635; }
.mini-stat.rating-fair b { color: #fbbf24; }
.mini-stat.rating-low b { color: #f87171; }

/* Every team a player featured for is rendered in full (club *and*
   national team). The list does not scroll on its own — the page is the
   only scroll container, so nothing nests a second scrollbar inside it. */
.detail-team-groups {
  margin-top: 12px;
}

.detail-team-card {
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-radius: 14px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.05), rgba(7, 12, 26, 0.5));
  margin-top: 8px;
  overflow: hidden;
}

.detail-team-card.national-team {
  background: linear-gradient(180deg, rgba(220, 38, 38, 0.16), rgba(16, 185, 129, 0.08), rgba(7, 12, 26, 0.5));
  border-color: rgba(245, 158, 11, 0.32);
}

.detail-team-head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px 8px;
  padding: 9px 11px;
  background: rgba(255, 255, 255, 0.03);
}

.detail-team-crest {
  width: 22px;
  height: 22px;
  flex: 0 0 22px;
  object-fit: contain;
  font-size: 13px;
  line-height: 22px;
  text-align: center;
}

.detail-team-title {
  min-width: 0;
  flex: 1;
  font-size: 13.5px;
  font-weight: 700;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.detail-team-line {
  color: var(--muted);
  font-size: 11.5px;
  font-weight: 600;
  white-space: nowrap;
}

.detail-team-line b { color: var(--text); }

.detail-rows { padding: 0 11px 10px; }

/* Small status pills shared by the competition rows (out of scope),
   the team header (national team) and the match rows (starter/sub). */
.tag {
  display: inline-block;
  border-radius: 999px;
  padding: 1px 7px;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.3px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  color: var(--muted);
}

.tag-muted { color: #cbd5f5; background: rgba(148, 163, 184, 0.16); }
.tag-national { color: #fde68a; border-color: rgba(245, 158, 11, 0.45); background: rgba(245, 158, 11, 0.16); }
.tag-starter { color: #ccfbf1; border-color: rgba(45, 212, 191, 0.45); background: rgba(45, 212, 191, 0.16); }
.tag-sub { color: #dbeafe; border-color: rgba(96, 165, 250, 0.4); background: rgba(37, 99, 235, 0.14); }
.tag-bench { color: #cbd5f5; border-color: rgba(148, 163, 184, 0.4); background: rgba(148, 163, 184, 0.14); }

/* A two-line row replaces the old six-column table: it wraps on narrow
   screens instead of forcing a 520px horizontal scroll. */
.detail-row {
  padding: 8px 0;
  border-top: 1px solid var(--border);
  font-size: 13px;
}

.detail-row-main {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 8px;
}

.detail-league-logo {
  width: 16px;
  height: 16px;
  flex: 0 0 16px;
  object-fit: contain;
  background: rgba(255, 255, 255, 0.85);
  border-radius: 4px;
  padding: 1px;
  font-size: 11px;
  line-height: 16px;
  text-align: center;
}

.detail-league-logo.placeholder { background: rgba(255, 255, 255, 0.08); }

.detail-row-title { flex: 1 1 auto; min-width: 0; font-weight: 600; }
.detail-row.excluded { opacity: 0.72; }
.detail-row.excluded .detail-row-title { color: var(--muted); font-weight: 500; }

.detail-row-sub { margin-top: 3px; color: var(--muted); font-size: 11.5px; }
.detail-row-note { margin-top: 3px; color: #fbbf24; font-size: 11px; }
.detail-row-link { margin-top: 3px; font-size: 11.5px; }
.detail-row-link a { color: #7dd3fc; text-decoration: none; }
.detail-row-link a:hover { text-decoration: underline; }

/* Match rows read as a scoreline first, then the context line. */
.detail-match-row { padding: 10px 0; }

.detail-match-head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px 8px;
}

.detail-match-teams { flex: 1 1 auto; min-width: 0; font-weight: 600; }
.detail-match-score { color: var(--accent); font-weight: 800; }

/* Each figure is its own tinted pill, so goals/assists/rating are
   findable at a glance instead of being one grey sentence. */
.detail-figures {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 6px;
  margin-top: 6px;
  font-size: 11px;
}

.figure {
  display: inline-flex;
  align-items: baseline;
  gap: 3px;
  border-radius: 999px;
  padding: 2px 8px;
  color: var(--muted);
  border: 1px solid rgba(255, 255, 255, 0.08);
  background: rgba(255, 255, 255, 0.04);
}

.figure b { color: var(--text); font-weight: 700; font-size: 12px; }
.figure-goals { border-color: rgba(52, 211, 153, 0.3); background: rgba(52, 211, 153, 0.12); }
.figure-goals b { color: #6ee7b7; }
.figure-assists { border-color: rgba(56, 189, 248, 0.3); background: rgba(56, 189, 248, 0.12); }
.figure-assists b { color: #7dd3fc; }
.figure-minutes b { color: #c7d2fe; }
.figure-rating.rating-elite { border-color: rgba(74, 222, 128, 0.45); background: rgba(74, 222, 128, 0.14); }
.figure-rating.rating-elite b { color: #4ade80; }
.figure-rating.rating-good b { color: #a3e635; }
.figure-rating.rating-fair b { color: #fbbf24; }
.figure-rating.rating-low b { color: #f87171; }

.detail-note,
.detail-empty { margin: 10px 0 0; color: var(--muted); font-size: 12.5px; }

.detail-link-row { margin-top: 12px; font-size: 12.5px; }

/* The recent list can hold a whole season of matches. It grows with its
   content and scrolls with the page rather than adding a second
   scrollbar of its own. */
.detail-match-list {
  display: block;
}

@media (min-width: 721px) {
  .detail-hero { padding: 0 2px 18px; }
  .detail-player-name { font-size: 23px; }
  .player-profile { padding-bottom: 22px; }
  .detail-stat-grid { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  .mini-stat { font-size: 9.5px; }
}

/* Top menu: the dashboard and the upcoming games are two views of the
   same page, so they are switched here rather than by navigating away.
   It sits under the header (below the single Refresh button) and is
   deliberately large, with an underline on the active view, so which
   view you are on is unmistakable. */
.view-menu {
  display: flex;
  gap: 26px;
  margin: 0 0 22px;
  border-bottom: 1px solid var(--border);
}

.view-tab {
  position: relative;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--muted);
  padding: 12px 2px 14px;
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.2px;
  display: inline-flex;
  align-items: center;
  gap: 9px;
}

.view-tab::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 3px;
  border-radius: 3px;
  background: transparent;
}

.view-tab:hover:not(:disabled) { background: transparent; color: #dbeafe; transform: none; }

.view-tab[aria-pressed="true"] { color: #ffffff; }
.view-tab[aria-pressed="true"]::after { background: linear-gradient(90deg, #38bdf8, #f59e0b); }

.view-tab-icon { font-size: 18px; line-height: 1; }

/* Match centre */
.upcoming-timezone { margin: 0 0 16px; font-size: 12px; }

.upcoming-day { margin: 0 0 18px; }

.upcoming-day:last-child { margin-bottom: 0; }

.fixture-section { margin: 0 0 30px; }

/* Each phase (live / just finished / coming up) is announced by a title
   carrying a short accent bar, so the eye finds the three groups without
   the page shouting. */
.fixture-section-title {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 12px;
  font-size: 16px;
  color: #f8fafc;
}

.fixture-section-title::before {
  content: '';
  flex: none;
  width: 4px;
  height: 17px;
  border-radius: 3px;
  background: linear-gradient(180deg, #38bdf8, #f59e0b);
}

.fixture-section-live .fixture-section-title::before {
  background: linear-gradient(180deg, #f87171, #dc2626);
}

/* Live games are marked by a thin red edge on the row rather than a full
   outline, so they stand out without breaking the flat list. */
.fixture-section-live .upcoming-fixture {
  box-shadow: inset 3px 0 0 rgba(248, 113, 113, 0.6);
}

/* The kick-off time and the score occupy the same slot, so a fixed width
   keeps every club badge on the list lined up under the one above. */
.fixture-state {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex: none;
  min-width: 64px;
}

.fixture-score {
  padding: 2px 8px;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.07);
  font-size: 14px;
  font-weight: 800;
  color: #f8fafc;
  font-variant-numeric: tabular-nums;
}

.fixture-live, .fixture-finished {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.5px;
  text-transform: uppercase;
}

.fixture-live { color: #f87171; display: inline-flex; align-items: center; gap: 4px; }
.fixture-finished { color: var(--muted); }

.fixture-live-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #f87171;
  animation: fixture-pulse 1.6s ease-in-out infinite;
}

@keyframes fixture-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.25; }
}

@media (prefers-reduced-motion: reduce) {
  .fixture-live-dot { animation: none; }
}

/* A day is a quiet label with a rule running off to the right, so the
   list is divided without adding another framed box. */
.upcoming-day-title {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 8px;
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: #bfdbfe;
}

.upcoming-day-title::after {
  content: '';
  flex: 1 1 auto;
  height: 1px;
  background: linear-gradient(90deg, rgba(148, 163, 184, 0.28), transparent);
}

/* One condensed row per fixture: the list is a single column of one-line
   summaries that expand in place, so a week of games can be scanned
   without scrolling past a full card for each one. The rows are not
   cards — they share one softly tinted panel and are told apart by a
   hairline rule, which gives the list a shape without turning it into a
   stack of boxes. */
.upcoming-fixtures {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
  align-items: start;
  padding: 4px;
  border: 1px solid var(--border);
  border-radius: 16px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0.015));
}

.upcoming-fixture {
  position: relative;
  border: 1px solid transparent;
  border-radius: 12px;
  background: transparent;
  overflow: hidden;
  transition: background-color 0.18s ease, border-color 0.18s ease, margin 0.18s ease;
}

/* The separator belongs to the row below, fades out at both ends, and
   disappears around an open row, which carries its own border instead. */
.upcoming-fixture + .upcoming-fixture::before {
  content: '';
  position: absolute;
  top: 0;
  left: 12px;
  right: 12px;
  height: 1px;
  background: linear-gradient(
    90deg,
    transparent,
    rgba(148, 163, 184, 0.22) 10%,
    rgba(148, 163, 184, 0.22) 90%,
    transparent
  );
  transition: opacity 0.18s ease;
}

.upcoming-fixture:hover { background: rgba(255, 255, 255, 0.045); }

/* An open game is lifted out of the list into a bordered block of its
   own, with room above and below, so two games opened at once never run
   into each other and each one reads as a single unit. */
.upcoming-fixture.expanded {
  margin: 8px 4px;
  border-color: rgba(56, 189, 248, 0.35);
  border-radius: 14px;
  background: linear-gradient(180deg, rgba(56, 189, 248, 0.11), rgba(56, 189, 248, 0.03));
  box-shadow: 0 12px 28px rgba(2, 6, 23, 0.45);
}

.upcoming-fixture.expanded:hover {
  background: linear-gradient(180deg, rgba(56, 189, 248, 0.13), rgba(56, 189, 248, 0.04));
}

/* An open live game keeps its red edge and takes the red accent for the
   block, so the phase is never lost when the row is opened. */
.fixture-section-live .upcoming-fixture.expanded {
  border-color: rgba(248, 113, 113, 0.4);
  background: linear-gradient(180deg, rgba(248, 113, 113, 0.1), rgba(248, 113, 113, 0.03));
  box-shadow: inset 3px 0 0 rgba(248, 113, 113, 0.6), 0 12px 28px rgba(2, 6, 23, 0.45);
}

.fixture-section-live .upcoming-fixture.expanded .upcoming-summary {
  border-bottom-color: rgba(248, 113, 113, 0.28);
}

.fixture-section-live .upcoming-fixture.expanded:hover {
  background: linear-gradient(180deg, rgba(248, 113, 113, 0.13), rgba(248, 113, 113, 0.04));
}

.upcoming-fixture.expanded::before,
.upcoming-fixture.expanded + .upcoming-fixture::before { opacity: 0; }

/* The whole summary line is the disclosure control. It keeps the plain
   row surface (no pill, no gradient) so a list of them reads as rows,
   with only the caret carrying the accent. Once open, a rule under it
   ties it to the panel it heads. */
.upcoming-summary {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 11px 12px;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--text);
  font: inherit;
  text-align: left;
}

.upcoming-fixture.expanded .upcoming-summary {
  border-bottom: 1px solid rgba(56, 189, 248, 0.22);
}

.upcoming-time {
  flex: none;
  font-size: 14px;
  font-weight: 800;
  color: #7dd3fc;
  letter-spacing: -0.2px;
  font-variant-numeric: tabular-nums;
}

/* Capped so a long competition name ("UEFA Champions League Qualifying")
   never eats the width the two clubs need. */
.upcoming-competition {
  flex: 0 1 auto;
  min-width: 0;
  max-width: 170px;
  padding: 3px 9px;
  border: 1px solid rgba(148, 163, 184, 0.16);
  border-radius: 999px;
  background: rgba(148, 163, 184, 0.1);
  font-size: 11px;
  font-weight: 600;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.upcoming-competition:empty { display: none; }

/* Kick-off time and competition sit on the collapsed summary line, so the
   expanded panel below carries only the teams and their players. */
.upcoming-summary-logo {
  width: 18px;
  height: 18px;
  flex: 0 0 18px;
  object-fit: contain;
}

.upcoming-summary-logo.placeholder { border-radius: 50%; background: rgba(255, 255, 255, 0.07); }

.upcoming-summary:hover:not(:disabled) { background: transparent; transform: none; }
.upcoming-summary:focus-visible { outline: 2px solid var(--accent-2); outline-offset: -2px; border-radius: 12px; }

.upcoming-summary-teams {
  display: flex;
  align-items: center;
  gap: 7px;
  flex: 1 1 auto;
  min-width: 0;
  font-size: 13px;
  font-weight: 700;
}

.upcoming-summary-team {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}

.upcoming-summary-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.upcoming-summary-versus {
  flex: none;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.8px;
  text-transform: uppercase;
  color: var(--muted);
}

/* How many Moroccans are in the game is not on the collapsed row: the
   clubs take that space instead, and the players are named in full once
   the row is expanded. */

/* A bare chevron rather than a filled pill: on a flat list of rows the
   circle read as one more box. */
.upcoming-arrow {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border: 0;
  background: transparent;
  color: var(--muted);
  font-size: 10px;
  line-height: 1;
  transition: transform 0.15s ease, color 0.15s ease;
}

.upcoming-fixture:hover .upcoming-arrow { color: var(--accent-2); }

.upcoming-summary[aria-expanded='true'] .upcoming-arrow {
  transform: rotate(180deg);
  color: var(--accent-2);
}

.upcoming-details { padding: 12px 14px 14px; }

.upcoming-details[hidden] { display: none; }

.upcoming-match-link {
  display: flex;
  align-items: center;
  gap: 8px;
  width: fit-content;
  margin: 12px auto 0;
  padding: 7px 11px;
  border: 1px solid rgba(96, 165, 250, 0.3);
  border-radius: 999px;
  background: rgba(37, 99, 235, 0.1);
  color: #bfdbfe;
  font-size: 11px;
  font-weight: 700;
  text-decoration: none;
  transition: border-color 0.15s ease, background 0.15s ease, color 0.15s ease;
}

.upcoming-match-link:hover {
  border-color: rgba(96, 165, 250, 0.55);
  background: rgba(37, 99, 235, 0.18);
  color: #eff6ff;
}

.upcoming-match-link-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 17px;
  height: 17px;
  border-radius: 50%;
  background: #fff;
  color: #2563eb;
  font-size: 10px;
  font-weight: 800;
}

.upcoming-match-link-arrow { color: #93c5fd; font-size: 13px; }

.upcoming-teams {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: stretch;
  gap: 10px;
}

/* Each side is its own small panel inside the open game, which makes the
   two line-ups readable as a pair instead of one run of names. */
.upcoming-team {
  min-width: 0;
  padding: 10px;
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: 12px;
  background: rgba(8, 15, 33, 0.35);
}

.upcoming-versus {
  align-self: center;
  margin: 0;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--muted);
}

.upcoming-team-head { display: flex; align-items: center; gap: 7px; min-width: 0; }

.upcoming-team-logo {
  width: 20px;
  height: 20px;
  flex: 0 0 20px;
  object-fit: contain;
}

.upcoming-team-logo.placeholder { border-radius: 50%; background: rgba(255, 255, 255, 0.07); }

.upcoming-team-name {
  font-weight: 700;
  font-size: 13px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Photos make the Moroccans in a game recognisable at a glance; several
   players at the same club wrap compactly beneath that club, each on a
   small chip so the names do not run together. */
.upcoming-players {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.upcoming-player {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  max-width: 100%;
  padding: 3px 9px 3px 3px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.05);
}

.upcoming-player-photo {
  width: 22px;
  height: 22px;
  flex: 0 0 22px;
  border-radius: 50%;
  object-fit: cover;
  background: rgba(255, 255, 255, 0.08);
}

.upcoming-player-photo.placeholder {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 9px;
  font-weight: 700;
  color: var(--muted);
}

.upcoming-player-text { display: flex; align-items: center; gap: 6px; min-width: 0; }

.upcoming-player-profile {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-left: auto;
  height: 18px;
  padding: 1px 6px;
  border: 1px solid rgba(96, 165, 250, 0.3);
  border-radius: 999px;
  background: rgba(37, 99, 235, 0.1);
  color: #bfdbfe;
  font-size: 9.5px;
  font-weight: 700;
  text-decoration: none;
  white-space: nowrap;
  transition: border-color 0.15s ease, background 0.15s ease, color 0.15s ease;
}

.upcoming-player-profile .upcoming-match-link-arrow {
  font-size: 11px;
  line-height: 1;
}

.upcoming-player-profile:hover {
  border-color: rgba(96, 165, 250, 0.55);
  background: rgba(37, 99, 235, 0.18);
  color: #eff6ff;
}

.upcoming-player-name {
  font-size: 12px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.upcoming-player-status {
  display: inline-flex;
  align-items: center;
  height: 18px;
  padding: 1px 6px;
  border: 1px solid currentColor;
  border-radius: 999px;
  font-size: 9.5px;
  font-weight: 700;
  white-space: nowrap;
}

.upcoming-player-status.starter { color: #5eead4; }
.upcoming-player-status.substitute { color: #93c5fd; }
.upcoming-player-status.bench { color: #cbd5e1; }
.upcoming-player-status.absent { color: #fca5a5; }

.upcoming-state {
  padding: 24px;
  text-align: center;
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: 14px;
}

@media (max-width: 720px) {
  .upcoming-fixtures { grid-template-columns: 1fr; }
  .upcoming-teams { grid-template-columns: 1fr; gap: 8px; }
  .upcoming-versus { justify-self: start; }
}

/* The competition name is the first thing to drop when the summary line
   runs out of room: time, clubs and the player count carry the row. */
@media (max-width: 560px) {
  .upcoming-competition { display: none; }
  .upcoming-summary { gap: 8px; padding: 10px; }
  .fixture-state { min-width: 56px; }
  .upcoming-details { padding: 10px 10px 12px; }
}

/* Keep this control with pagination so it appears only after the visitor
   reaches the end of the player list. */
.to-top {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px;
  border: 1px solid rgba(56, 189, 248, 0.45);
  background: linear-gradient(180deg, rgba(20, 30, 55, 0.96), rgba(10, 16, 32, 0.94));
  color: #dff3ff;
}

.to-top:hover:not(:disabled) { background: rgba(56, 189, 248, 0.3); }
.to-top-arrow { font-size: 12px; line-height: 1; color: var(--accent-2); }

    

/* Player profile page. The page keeps the dashboard's background (the same
   top-left gradient), so arriving here from a card reads as the same site;
   only the header is reduced to a way back. */
.profile-container { padding-top: 24px; }

.profile-head { margin-bottom: 16px; }

.back-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  font-weight: 600;
  color: #dff3ff;
  text-decoration: none;
  padding: 8px 14px;
  border: 1px solid rgba(56, 189, 248, 0.45);
  border-radius: 999px;
  background: linear-gradient(180deg, rgba(56, 189, 248, 0.22), rgba(56, 189, 248, 0.08));
}

.back-link:hover { background: rgba(56, 189, 248, 0.3); }

.back-arrow { font-size: 13px; line-height: 1; color: var(--accent-2); }

/* The latest game keeps the update card's headline figures and uses the
   profile's extra width for the remaining match stats. Its video stays
   collapsed by default. */
.last-game {
  margin: 0 0 14px;
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: linear-gradient(165deg, rgba(255, 255, 255, 0.06), rgba(255, 255, 255, 0.02));
}

.last-game-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 8px;
}

.last-game-label {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--accent);
}

.last-game .match { margin-top: 0; }

/* The one-line figure strip is the default reading of the game; it uses the
   same pills as a recent match row so both read alike. */
.last-game > .detail-figures { margin-top: 10px; }

/* Everything else the provider returns for the match is folded away, so the
   section stays roughly as tall as an update card until it is asked for. The
   two disclosures share one row and their panels can open independently. */
.last-game-disclosures {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-start;
  gap: 8px;
  margin-top: 8px;
}

.last-game .detail-stat-grid {
  grid-template-columns: repeat(auto-fit, minmax(72px, 1fr));
  margin-top: 0;
}



/* --- Favourites -----------------------------------------------------------
   The star shares the card head's top right corner with the share button, on
   every player card and on the profile hero. */
.player-head-actions {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  margin-left: auto;
}

.player-head-actions .share-button { margin-left: 0; }

.favourite-button { align-self: flex-start; }

.favourite-star { font-size: 18px; line-height: 1; }

.favourite-button.is-favourite {
  border-color: rgba(245, 158, 11, 0.55);
  background: rgba(245, 158, 11, 0.18);
  color: var(--accent);
}

/* The confirmation the star click deserves: a short line at the bottom of the
   screen, gone again on its own. */
.favourite-toast {
  position: fixed;
  left: 50%;
  bottom: 26px;
  z-index: 60;
  transform: translate(-50%, 12px);
  padding: 10px 18px;
  border: 1px solid rgba(245, 158, 11, 0.4);
  border-radius: 999px;
  background: rgba(13, 20, 38, 0.96);
  color: var(--text);
  font-size: 13.5px;
  font-weight: 600;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.18s ease, transform 0.18s ease;
}

.favourite-toast.visible { opacity: 1; transform: translate(-50%, 0); }
