/* BahisNow TV — landing page.
 *
 * Palette is taken from the logo: the script "Bahis" red is the single accent,
 * everything else is a neutral dark scale. One accent colour used sparingly
 * reads as deliberate; using it everywhere would flatten the hierarchy and make
 * the live indicators stop meaning anything.
 */

:root {
  /* brand */
  --red: #e2231a;
  --red-dim: #b71c15;
  --red-glow: rgba(226, 35, 26, .22);

  /* neutrals */
  --bg: #0a0d12;
  --surface: #11161d;
  --surface-2: #171e27;
  --surface-3: #1e2732;
  --line: #232d3a;
  --line-soft: #1a222c;

  --fg: #eef3f8;
  /*
   * Near-white, not grey.
   *
   * These were #9fb0c2 and #6b7c8f - proper mid-greys, which is standard for
   * secondary text on a flat dark background. This page is not on a flat dark
   * background: it sits over a bright, busy promotional skin, and against that
   * a mid-grey label reads as switched off rather than as secondary. Hierarchy
   * now comes from size and weight, which survive a noisy backdrop; lightness
   * does not.
   */
  --fg-dim: #e8eef5;
  --fg-mute: #d3dde8;

  --gold: #f2b705;
  --ok: #3fb950;

  --r: 10px;
  --r-sm: 8px;
  --shadow: 0 8px 28px rgba(0, 0, 0, .45);
  --max: 1076px;
  /* Measured on the live page, not estimated: header 55, two CTA bars 47 each,
     provider strip 48, caption bar 58, footer 49 plus padding. The promo banners
     were 63px each and have been removed, so the player grows into that space. */
  --chrome: 356px;
}

* { box-sizing: border-box; }

html { height: 100%; }

/* One screen, so the chrome is pinned: header at the top, footer at the bottom,
   and the player/list row absorbing whatever is left. */
body {
  min-height: 100%;
  display: flex; flex-direction: column;
}

/*
 * Page skin.
 *
 * A 1920x1080 branded backdrop whose middle third is deliberately empty - the
 * artwork lives in the left and right gutters. So it is pinned (not scrolled)
 * and the content column is narrowed below, otherwise the panels would sit on
 * top of the very artwork the skin exists to show.
 */
body {
  background: var(--bg) url('/pageskin-v2.jpg') no-repeat center top;
  background-size: cover;
  background-attachment: fixed;
}

html, body {
  margin: 0;
  color: var(--fg);
  font: 15px/1.55 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
        "Helvetica Neue", Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
a { color: inherit; text-decoration: none; }
h1, h2 { margin: 0; font-weight: 700; letter-spacing: -.01em; }

/* Live pip — reused wherever "on air" needs signalling. */
.pip, .livetag i, .livecount i {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--red);
  box-shadow: 0 0 0 0 var(--red-glow);
  animation: pip 2s cubic-bezier(.4, 0, .6, 1) infinite;
  flex: 0 0 auto;
  display: inline-block;
}
@keyframes pip {
  0%   { box-shadow: 0 0 0 0 var(--red-glow); }
  70%  { box-shadow: 0 0 0 7px rgba(226, 35, 26, 0); }
  100% { box-shadow: 0 0 0 0 rgba(226, 35, 26, 0); }
}
@media (prefers-reduced-motion: reduce) { .pip, .livetag i, .livecount i { animation: none; } }

/* ------------------------------------------------------------- header --- */

.hdr {
  position: sticky; top: 0; z-index: 40;
  background: rgba(10, 13, 18, .72);
  backdrop-filter: saturate(1.4) blur(12px);
  border-bottom: 1px solid var(--line-soft);
}
.hdr-in {
  max-width: var(--max); margin: 0 auto; padding: 0 14px;
  height: 54px; display: flex; align-items: center; gap: 30px;
}

/* The logo art is dark-on-light; invert-free approach is a soft glow behind it
   so it sits on the dark chrome without a white plate. */
.logo img { height: 30px; display: block; filter: drop-shadow(0 0 10px rgba(226,35,26,.35)); }

/* Social links. Icon-only: four recognisable glyphs read faster than four
   words, and they carry aria-labels for anyone who cannot see them. */
.social { margin-left: auto; display: flex; align-items: center; gap: 8px; }
.social a {
  width: 34px; height: 34px; border-radius: 9px;
  display: grid; place-items: center;
  color: var(--fg-dim); background: var(--surface-2);
  border: 1px solid var(--line);
  transition: color .15s, background .15s, border-color .15s, transform .1s;
}
.social a:hover { color: #fff; background: var(--red); border-color: var(--red); }
.social a:active { transform: translateY(1px); }
.social svg { width: 16px; height: 16px; display: block; }

/* ----------------------------------------------------------------- cta -- */

/* Sign-up / sign-in, in the brand red. Sits with the banners rather than in the
   header: this is the one thing the page is trying to get a viewer to do, and
   the header is already carrying the logo and the social links. */
.cta {
  max-width: var(--max); margin: 0 auto 8px; width: 100%;
  padding: 0 10px; flex: 0 0 auto;
  display: flex; justify-content: center; gap: 8px;
}
.cta:last-of-type { margin: 8px auto 0; }

.cta-btn {
  flex: 0 1 auto; min-width: 150px; text-align: center;
  padding: 9px 26px; border-radius: 7px;
  font-size: 12.5px; font-weight: 800; letter-spacing: .06em;
  border: 1px solid transparent;
  transition: background .15s, border-color .15s, transform .1s, box-shadow .15s;
}
.cta-btn.primary {
  color: #fff; background: var(--red); border-color: var(--red);
  box-shadow: 0 3px 14px rgba(226, 35, 26, .3);
}
.cta-btn.primary:hover { background: #f4291f; box-shadow: 0 4px 18px rgba(226,35,26,.45); }
.cta-btn.ghost {
  color: var(--fg); background: rgba(23, 30, 39, .92); border-color: var(--line);
}
.cta-btn.ghost:hover { border-color: var(--red-dim); background: var(--surface-3); }
.cta-btn:active { transform: translateY(1px); }

@media (max-width: 640px) {
  .cta-btn { min-width: 0; flex: 1 1 0; padding: 10px 12px; font-size: 12px; }
}

/* ------------------------------------------------------------ providers - */

/* A drifting strip of broadcaster marks above the video, inside the player
   panel. No tiles: the boxes were competing with the artwork they contained,
   and the logos read better against the panel itself. */
.provbar {
  overflow: hidden;
  padding: 5px 0 9px;
  /* Fade both ends so marks enter and leave rather than being chopped off. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
}
.provtrack {
  display: flex; align-items: center; gap: 26px;
  width: max-content;
  animation: drift 40s linear infinite;
}
/* Half, because the list is rendered twice - one full period lands the second
   copy exactly where the first began. */
@keyframes drift {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
.provbar:hover .provtrack { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) { .provtrack { animation: none; } }

/*
 * Fixed slot per logo, not width:auto.
 *
 * The track is rendered twice and animated by exactly -50% of its own width, so
 * that width has to be settled before the first wrap. With auto widths it grew
 * as each image decoded, the -50% stopped landing on the seam, and a gap opened
 * for a second or two. A fixed slot makes the width deterministic from the first
 * frame; logos of different shapes just centre inside their slot.
 */
.prov {
  flex: 0 0 108px; width: 108px; height: 34px;
  object-fit: contain; display: block;
  opacity: .92; transition: opacity .15s, transform .15s;
}
.prov:hover { opacity: 1; transform: scale(1.06); }

/* ---------------------------------------------------------------- app --- */

/* The page is one screen now: player plus channel list, no sections below. So
   it claims the viewport instead of leaving the fold half empty. */
/* Centred vertically: the player is locked to 16:9 so it cannot fill a tall
   window, and leftover height split evenly above and below reads as deliberate
   framing, where the same space all at the bottom read as a broken page. */
/* A column: the broadcaster strip sits above the player/schedule block, and the
   pair is centred vertically. As a row - which it was when the strip was added -
   the strip became a sibling column and shoved the content off centre. */
.app {
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column; justify-content: center;
}
.hero-in {
  /* Sized by its content, not stretched: stretching left the schedule panel
     taller than the fixtures in it and pushed the footer off screen. */
  flex: 0 0 auto;
  max-width: var(--max); margin: 0 auto; padding: 10px; width: 100%;
  /* Player left, schedule right.
   *
   * Underneath, a long schedule ran off the bottom of the page - with a full
   * fixture list that is unusable. Beside the player it gets its own scroll and
   * the page height stays fixed however many matches are listed.
   *
   * 1200px is the compromise with the page skin: its artwork sits in the outer
   * thirds, so this still leaves ~360px of gutter showing either side at 1920,
   * where the ~1440px the player wanted buried the banners entirely. */
  display: grid; grid-template-columns: minmax(0, 1fr) 290px; gap: 0;
  align-items: stretch;
}
/* Over a page skin the player needs its own surface: without one the title and
   buttons sit straight on the artwork and the skin's own logo reads through
   them. Same treatment as the schedule panel, so the two match. */
.player-col {
  align-self: start; min-width: 0;
  background: rgba(17, 22, 29, .93);
  backdrop-filter: blur(6px);
  border: 1px solid var(--line);
  /* Joined to the schedule: outer corners rounded, shared edge flat and drawn
     once, so the two read as a single unit rather than two floating cards. */
  border-radius: var(--r) 0 0 var(--r); border-right: 0;
  padding: 6px 6px 2px;
}

/*
 * The player is sized by the height that is left, not by the column width.
 *
 * It is locked to 16:9, so width-driven sizing overflows a short window and
 * pushes the footer off screen. Asking for the leftover height and letting
 * aspect-ratio derive the width fixes that at every viewport; max-width then
 * clamps it back on tall-but-narrow screens, and the ratio re-derives the
 * height. 420px is the fixed chrome above and below: header, caption bar, gap,
 * fixtures strip, footer and padding.
 */
.screen {
  position: relative; background: #000; border-radius: var(--r);
  overflow: hidden; box-shadow: var(--shadow);
  border: 1px solid var(--line);
  aspect-ratio: 16 / 9;
  /* min() of the two limits, stated as a width: the column it sits in, and the
     width implied by the leftover height. Expressing it this way rather than
     leaning on max-width matters - with width:auto and a set height the ratio
     wins and the box overflows its column instead of being clamped. */
  /* --chrome is everything above and below the video that is not the video:
     header, caption bar, footer, padding, the two CTA bars and the banners.
     It changes as banners drop out on shorter windows, so it is a variable the
     media queries below re-state rather than a number buried in this calc. */
  width: min(100%, calc((100vh - var(--chrome)) * 16 / 9));
  height: auto; margin: 0 auto;
}
#video { width: 100%; height: 100%; display: block; background: #000; }

.veil {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 14px;
  background: rgba(8, 11, 15, .9); color: var(--fg-dim); font-size: 14px;
}
.veil[hidden] { display: none; }
.veil p { margin: 0; }
.ring {
  width: 34px; height: 34px; border-radius: 50%;
  border: 3px solid var(--line); border-top-color: var(--red);
  animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .ring { animation-duration: 2.4s; } }

.livetag {
  position: absolute; top: 12px; left: 12px;
  display: none; align-items: center; gap: 6px;
  background: rgba(226, 35, 26, .92); color: #fff;
  font-size: 10.5px; font-weight: 800; letter-spacing: .09em;
  padding: 5px 10px; border-radius: 5px;
}
.livetag.on { display: inline-flex; }
.livetag i { background: #fff; box-shadow: none; }

.under {
  display: flex; align-items: flex-start; gap: 16px;
  padding: 9px 4px 7px; flex-wrap: wrap;
}
.under-l { min-width: 0; flex: 1 1 auto; }
.under h1 { font-size: 16px; line-height: 1.25; }
.under p { margin: 3px 0 0; color: var(--fg-mute); font-size: 12px; }
.under-r { display: flex; align-items: center; gap: 9px; flex: 0 0 auto; }

.btn {
  border: 1px solid var(--line); background: var(--surface-2); color: var(--fg);
  border-radius: var(--r-sm); padding: 6px 12px; font-size: 12.5px;
  cursor: pointer; transition: background .14s, border-color .14s;
}
.btn:hover { background: var(--surface-3); border-color: #2e3a49; }
.btn.ghost:active { transform: translateY(1px); }

/* live rail beside the player.
 *
 * The wrapper takes the grid cell and the rail fills it absolutely, so the
 * channel list never dictates the hero's height - the video does. The list
 * scrolls inside whatever height the player ends up at. */
/* A floor only, not a target: the block takes the player's height and the
   schedule scrolls inside it, so it must be free to shrink on a short window. */
.rail-wrap { position: relative; min-height: 200px; }
/* padding-right:0 - a 6px inset here left a strip of page background between
   the video and the rail, reading as a dark seam between two panels that are
   meant to meet. The screen's radius below is squared on that side to match, or
   the rounded corner would notch into the rail instead. */
.player-col { display: flex; flex-direction: column; justify-content: center; padding-right: 0; }
.rail {
  position: absolute; inset: 0;
  background: rgba(17, 22, 29, .93);
  backdrop-filter: blur(6px); border: 1px solid var(--line);
  border-radius: 0 var(--r) var(--r) 0;
  display: flex; flex-direction: column;
  min-height: 0; overflow: hidden;
}
.rail-hd {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 11px; border-bottom: 1px solid var(--line-soft);
  font-size: 11px; font-weight: 800; letter-spacing: .1em; color: var(--fg-dim);
}
.rail-n {
  margin-left: auto; font-size: 11px; font-weight: 700; color: var(--fg-mute);
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: 20px; padding: 2px 9px; letter-spacing: 0;
}
/* Fixture rows in the rail need team crests; everything else that belonged to
   the old fixture table and channel-card grid went with those sections. */
.crest {
  width: 26px; height: 26px; flex: 0 0 26px; object-fit: contain;
  background: var(--surface-3); border-radius: 5px; padding: 2px;
}

/* quality / status chips, shared by channel rows and match rows */
.q {
  font-size: 9.5px; font-weight: 800; letter-spacing: .05em;
  padding: 3px 7px; border-radius: 4px;
  background: var(--surface-3); border: 1px solid var(--line); color: var(--fg-dim);
}
.q.uhd { color: var(--gold); border-color: color-mix(in srgb, var(--gold) 40%, transparent); }
.q.sd { color: var(--fg-mute); }
.q.live { color: #fff; background: var(--red); border-color: var(--red); }
/* Kickoff time on a fixture that has not started - informational, so it stays
   quiet rather than competing with the live badge. */
.q.soon { color: var(--gold); border-color: color-mix(in srgb, var(--gold) 32%, transparent);
  font-variant-numeric: tabular-nums; letter-spacing: 0; }
/* A column beside the player. It scrolls on its own, so a hundred fixtures
   change nothing about the height of the page. */
.rail-body {
  padding: 6px; flex: 1 1 auto; min-height: 0;
  overflow-y: auto;
}

/*
 * Scrollbars in the panels.
 *
 * The previous version set only ::-webkit-scrollbar { width } and a thumb
 * colour. That is worse than styling nothing: touching any ::-webkit-scrollbar
 * part makes Chrome abandon its modern overlay scrollbar and fall back to the
 * legacy widget, which ships a light track AND stepper arrows at both ends -
 * exactly the fat white bar with arrows that showed up on the dark chat panel.
 *
 * So every part has to be accounted for: track transparent, buttons and corner
 * explicitly removed, thumb inset with a transparent border so the visible bar
 * is ~4px inside a 10px gutter. scrollbar-color covers Firefox and recent
 * Chrome, which honour it without the legacy fallback at all.
 */
.rail-body, .chat-log {
  scrollbar-width: thin;
  scrollbar-color: #303e4e transparent;
}
.rail-body::-webkit-scrollbar,
.chat-log::-webkit-scrollbar { width: 10px; height: 10px; }
.rail-body::-webkit-scrollbar-track,
.chat-log::-webkit-scrollbar-track { background: transparent; }
.rail-body::-webkit-scrollbar-thumb,
.chat-log::-webkit-scrollbar-thumb {
  background: #303e4e; border-radius: 999px;
  border: 3px solid transparent; background-clip: content-box;
}
.rail-body::-webkit-scrollbar-thumb:hover,
.chat-log::-webkit-scrollbar-thumb:hover { background: #45596e; background-clip: content-box; }
/* The steppers. Without this Chrome draws two arrow boxes on the legacy bar. */
.rail-body::-webkit-scrollbar-button,
.chat-log::-webkit-scrollbar-button { display: none; width: 0; height: 0; }
.rail-body::-webkit-scrollbar-corner,
.chat-log::-webkit-scrollbar-corner { background: transparent; }

/* The empty state should not be squeezed into one grid column. */
.rail-body .rail-empty { grid-column: 1 / -1; }

/* ------------------------------------------------------------- chat ---- */

/* Tabs in the panel header. The chat replaces the fixture list in place, so the
   player never moves and the stream is never reloaded by switching. */
.rtab {
  flex: 0 0 auto; cursor: pointer; font-family: inherit;
  padding: 4px 10px; border-radius: 20px;
  font-size: 10.5px; font-weight: 800; letter-spacing: .09em;
  color: var(--fg-mute); background: transparent; border: 1px solid transparent;
  transition: color .13s, background .13s, border-color .13s;
}
.rtab:hover { color: var(--fg-dim); background: var(--surface-2); }
.rtab.on { color: #fff; background: var(--red); border-color: var(--red); }

.chat { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }

/* Join gate: prompt, field, button - stacked and full width, so the one thing
   being asked for is unmissable. */
.chat-join {
  flex: 0 0 auto; display: grid; gap: 8px; padding: 12px 10px;
  border-top: 1px solid var(--line-soft); background: var(--surface-2);
}
.chat-join[hidden] { display: none; }
.chat-join p {
  margin: 0; font-size: 12px; color: var(--fg-dim); line-height: 1.4;
}
.chat[hidden] { display: none; }

/* Scrollbar styling is shared with .rail-body - see the block above .rail-body. */
.chat-log {
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
  padding: 8px 10px;
}
.chat-empty { color: var(--fg-mute); font-size: 12px; text-align: center; padding: 20px 8px; margin: 0; }

.cmsg { margin: 0 0 7px; }
.cmsg b {
  font-size: 11.5px; font-weight: 700; color: var(--gold);
  margin-right: 6px; word-break: break-word;
}
.cmsg .ctime {
  font-size: 9.5px; color: var(--fg-mute);
  font-variant-numeric: tabular-nums;
}
.cmsg p {
  margin: 1px 0 0; font-size: 12.5px; line-height: 1.35; color: var(--fg);
  /* Chat is user input: a single long token must wrap, not widen the panel. */
  overflow-wrap: anywhere;
}

/* Stacked, not side by side. Sharing the row with the button left the input
   about 150px wide in a 290px panel - too cramped to read what you had typed.
   Full width above the button gives the message the whole column. */
.chat-form {
  flex: 0 0 auto; display: grid; gap: 7px; padding: 9px;
  grid-template-columns: 1fr;
  border-top: 1px solid var(--line-soft); background: var(--surface-2);
}
.chat-nick, .chat-text {
  min-width: 0; padding: 10px 12px; font-family: inherit; font-size: 13.5px;
  color: var(--fg); background: var(--surface); border: 1px solid var(--line);
  border-radius: 7px; outline: none;
}
.chat-nick:focus, .chat-text:focus { border-color: var(--red-dim); }
/* opacity:1 because Firefox dims the placeholder on top of the colour, which
   left it almost invisible on this dark field. */
.chat-nick::placeholder, .chat-text::placeholder { color: var(--fg-mute); opacity: 1; }
.chat-send {
  cursor: pointer; font-family: inherit; padding: 9px 14px;
  font-size: 12px; font-weight: 800; letter-spacing: .06em;
  color: #fff; background: var(--red); border: 1px solid var(--red);
  border-radius: 7px; white-space: nowrap;
}
.chat-send:hover:not(:disabled) { background: #f4291f; }
.chat-send:disabled { opacity: .5; cursor: default; }

/* Status line under the input: who you are on the left, the rename control on
   the right. A row rather than inline text, so the button cannot collide with a
   long message and end up sitting on top of it. */
.chat-note {
  flex: 0 0 auto; margin: 0; padding: 0 10px 8px; min-height: 17px;
  display: flex; align-items: center; gap: 10px;
  font-size: 11px; color: var(--fg-mute); background: var(--surface-2);
}
.chat-note.err { color: var(--red); }
.chat-note > span {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Visible enough to find, quiet enough not to compete with Gonder: a small
   outlined chip. The first pass used a 10.5px dotted link and it simply could
   not be seen against the panel. */
.chat-rename {
  margin-left: auto; flex: 0 0 auto;
  padding: 4px 10px; cursor: pointer;
  font-family: inherit; font-size: 11px; font-weight: 700; letter-spacing: .02em;
  color: var(--fg-dim); background: var(--surface);
  border: 1px solid var(--line); border-radius: 999px;
  transition: color .14s, border-color .14s, background .14s;
}
.chat-rename:hover {
  color: #fff; background: var(--red); border-color: var(--red);
}
.chat-rename[hidden] { display: none; }


/* ------------------------------------------------------- league table --- */

/* Third panel in the rail, beside MAÇLAR and SOHBET. Same construction as the
   chat: swapped in place so the player never moves and the stream never
   reloads. */
.stand { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.stand[hidden] { display: none; }

.stand-hd {
  flex: 0 0 auto; padding: 9px 10px;
  border-bottom: 1px solid var(--line-soft); background: var(--surface-2);
}
/* The panel's picker fills its width, unlike the pill in the board filter row. */
.lgdd.wide { display: block; }
.lgdd.wide .lgdd-btn {
  width: 100%; max-width: none; justify-content: space-between;
  border-radius: 7px; padding: 9px 11px; font-size: 12.5px;
  background: var(--surface); color: var(--fg);
}
.lgdd.wide .lgdd-panel { width: 100%; left: 0; right: auto; max-height: 300px; }

.stand-body {
  /* No top padding. `position: sticky; top: 0` on the header row pins to this
     element's PADDING box, so any padding-top leaves a gap above the header
     that rows scroll up through - a sliver of the previous team stayed visible
     above the column titles, which reads as the header failing to stick. */
  flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 0 0 8px;
  scrollbar-width: thin; scrollbar-color: #303e4e transparent;
}
.stand-body::-webkit-scrollbar { width: 10px; }
.stand-body::-webkit-scrollbar-track { background: transparent; }
.stand-body::-webkit-scrollbar-thumb {
  background: #303e4e; border-radius: 999px;
  border: 3px solid transparent; background-clip: content-box;
}
.stand-body::-webkit-scrollbar-button { display: none; width: 0; height: 0; }

.stand-msg { margin: 0; padding: 24px 12px; text-align: center; color: var(--fg-mute); font-size: 12.5px; }
.stand-group {
  padding: 8px 11px 4px; font-size: 10px; font-weight: 800;
  letter-spacing: .08em; text-transform: uppercase; color: var(--fg-mute);
}

.stbl { width: 100%; border-collapse: collapse; font-size: 12px; }
.stbl th {
  position: sticky; top: 0; z-index: 1;
  padding: 6px 6px; text-align: left; font-size: 9.5px; font-weight: 800;
  letter-spacing: .07em; text-transform: uppercase; color: var(--fg-mute);
  /* Opaque, not .97. At any alpha the rows scrolling underneath show through a
     sticky header, which reads as a rendering fault - text ghosting behind the
     column titles. */
  background: #0c1016; border-bottom: 1px solid var(--line);
}
.stbl th.num, .stbl td.num { text-align: right; }
.stbl td { padding: 6px 6px; border-bottom: 1px solid var(--line-soft); vertical-align: middle; }
.stbl tbody tr:last-child td { border-bottom: 0; }
.stbl tbody tr:hover { background: rgba(30, 39, 50, .5); }

/* Rank column carries the European / relegation cut, which is the first thing
   anyone looks for in a table. */
.stbl td.rk {
  width: 26px; text-align: center; font-weight: 700;
  color: var(--fg-mute); font-variant-numeric: tabular-nums;
}
.stbl tbody tr:nth-child(-n+4) td.rk { color: #6ee7b7; }
.stbl tbody tr:nth-last-child(-n+3) td.rk { color: #ff8a9c; }

/*
 * The team cell stays a real table cell.
 *
 * `display: flex` lined the crest up with the name neatly, but it takes the
 * <td> out of the table formatting context - so the row could no longer paint a
 * continuous background across it and the hover highlight broke apart exactly
 * at this column. Inline alignment gets the same result without leaving the
 * table.
 */
.stbl td.tm { min-width: 0; }
.stbl td.tm img {
  width: 16px; height: 16px; object-fit: contain;
  display: inline-block; vertical-align: middle; margin-right: 7px;
}
.stbl td.tm span {
  display: inline-block; vertical-align: middle;
  max-width: calc(100% - 25px);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-weight: 500;
}
.stbl td.num { font-variant-numeric: tabular-nums; color: var(--fg-dim); width: 26px; }
.stbl td.pts { font-weight: 800; color: var(--fg); }
.stbl td.fm { width: 62px; }

/* Form pips: green won, grey drew, red lost. Colour alone carries it, so each
   pip also has a title for anyone who cannot separate them. */
.st-form { display: inline-flex; gap: 2px; }
.st-form .fp { width: 6px; height: 6px; border-radius: 50%; display: block; }
.st-form .fp.w { background: var(--ok); }
.st-form .fp.d { background: #55657a; }
.st-form .fp.l { background: var(--red); }

/* Three tabs in a 290px rail, so they give up their padding before the labels
   start truncating. */
.rail-hd .rtab { padding: 4px 8px; }

/* ---------------------------------------------------------- fixtures --- */

/* A fixture carried in several qualities: the row plays the default, the
   buttons under it pick a specific feed. Grouped so the options read as
   belonging to the match above them. */
.mrow { border-radius: var(--r-sm); }
.mrow .feeds {
  display: flex; flex-wrap: wrap; gap: 5px;
  padding: 0 9px 8px 36px;
}
button.feed {
  cursor: pointer; font-family: inherit;
  padding: 3px 9px; font-size: 10px; font-weight: 700; letter-spacing: .04em;
  color: var(--fg-dim); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: 20px;
  transition: color .13s, background .13s, border-color .13s;
}
button.feed:hover { color: var(--fg); background: var(--surface-3); border-color: var(--red-dim); }
button.feed.on { color: #fff; background: var(--red); border-color: var(--red); }


.ritem {
  display: flex; align-items: center; gap: 10px; padding: 9px 10px;
  border-radius: var(--r-sm); cursor: pointer; transition: background .13s;
}
.ritem:hover { background: var(--surface-2); }
.ritem.on { background: var(--surface-3); box-shadow: inset 2px 0 0 var(--red); }

/* A fixture leads with both crests, so the game is identifiable before the text
   is read. */
.ritem.match { padding: 8px; gap: 8px; }
.mt { flex: 0 0 auto; display: flex; align-items: center; gap: 5px; }
.mt .crest {
  width: 25px; height: 25px; flex-basis: 25px;
  /* No plate behind a club badge: they arrive with their own shape and colour,
     and a grey rounded square around each one just muddied them. */
  background: none; padding: 0;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .55));
}
.mt-vs { font-size: 10px; font-weight: 700; color: var(--fg-mute); }

/* Two lines: the tie on top, the competition under it. */
.ritem-t { min-width: 0; flex: 1 1 auto; }
.ritem-t b {
  display: block; font-size: 12.5px; font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ritem-t span { font-size: 11px; color: var(--fg-mute); }

.ritem .q { margin-left: auto; flex: 0 0 auto; }

/* -------------------------------------------------------- scoreboard --- */

/*
 * The live board under the player.
 *
 * It sits below the fold on purpose. The player owns the first screen - that is
 * what someone came for - and the board is what they find on the way down. The
 * removed second CTA row leaves just enough room for its header to peek above
 * the fold, which is what makes anyone scroll in the first place.
 */
.board { flex: 0 0 auto; padding: 4px 0 18px; }
.board-in {
  max-width: var(--max); margin: 0 auto; padding: 0 10px; width: 100%;
}
.board-hd {
  display: flex; align-items: center; gap: 9px; padding: 6px 4px 10px;
}
.board-hd h2 {
  display: flex; align-items: center; gap: 8px;
  font-size: 12px; font-weight: 800; letter-spacing: .11em; color: var(--fg-dim);
}
.board-when {
  margin-left: auto; font-size: 11px; color: var(--fg-mute);
  font-variant-numeric: tabular-nums;
}

/* League tabs. A horizontal scroller rather than a wrapping row: eleven leagues
   would wrap to three lines on a phone and push the matches off screen. */
.board-tabs {
  display: flex; gap: 6px; overflow-x: auto; padding: 0 4px 10px;
  scrollbar-width: none;
}
.board-tabs::-webkit-scrollbar { display: none; }
.btab {
  flex: 0 0 auto; cursor: pointer; font-family: inherit;
  padding: 7px 14px; border-radius: 20px; white-space: nowrap;
  font-size: 11.5px; font-weight: 700; letter-spacing: .03em;
  color: var(--fg-dim); background: rgba(23, 30, 39, .92);
  border: 1px solid var(--line);
  transition: color .13s, background .13s, border-color .13s;
}
.btab:hover { color: var(--fg); border-color: #2e3a49; }
.btab.on { color: #fff; background: var(--red); border-color: var(--red); }
/* The count rides inside the tab so an empty league is obvious before clicking. */
.btab u { font-style: normal; text-decoration: none; opacity: .65; margin-left: 5px; }
.btab { display: inline-flex; align-items: center; gap: 6px; }
.btab .lgb { width: 16px; height: 16px; object-fit: contain; }
/* The CANLI filter is the only chip that means "now", so it is the only red one. */
.btab.live.on { background: var(--red); border-color: var(--red); }
.btab.live:not(.on) { color: #ff8a9c; border-color: rgba(226, 35, 26, .35); }

/*
 * Two columns, filled left-to-right.
 *
 * A single column across 1076px put the score in the middle with a wide gap
 * either side and fitted six matches in the space twelve can occupy. The
 * separators are cell borders rather than grid gaps: a gap would show the page
 * skin through the panel in a grid pattern.
 */
/*
 * One chronological list, not two columns of tabs.
 *
 * Live and upcoming sit together in kickoff order with an hour heading every  time
 * the hour turns, because "what is on at nine" is the question being asked. The
 * two-column grid that used to be here split the 21:30 derby into a different
 * column from the 21:45 match beside it, which is exactly the comparison a
 * viewer is making.
 */
.board-list {
  background: rgba(17, 22, 29, .93);
  backdrop-filter: blur(6px);
  border: 1px solid var(--line); border-radius: var(--r);
  overflow: hidden;
}
.board-empty, .board-note {
  grid-column: 1 / -1;
  margin: 0; padding: 26px 14px; text-align: center;
  color: var(--fg-mute); font-size: 12.5px;
}

/* Show more, rather than paged navigation: a scoreboard repaints itself every
   20 seconds, and page numbers that shift under a live update are worse than a
   list that only ever grows. */
.board-more { display: flex; justify-content: center; padding: 10px 0 0; }
.more-btn {
  cursor: pointer; font-family: inherit;
  padding: 8px 20px; border-radius: 20px;
  font-size: 11.5px; font-weight: 700; letter-spacing: .04em;
  color: var(--fg-dim); background: rgba(23, 30, 39, .92);
  border: 1px solid var(--line);
  transition: color .13s, border-color .13s, background .13s;
}
.more-btn:hover { color: #fff; background: var(--surface-3); border-color: var(--red-dim); }

/* ---- one match, collapsed ---- */

/* Grid lines drawn by the cells themselves. nth-child works because the only
   children are matches - the empty state spans both columns and the show-more
   button lives outside the list. */
.bmatch { border-top: 1px solid var(--line-soft); }
.bmatch:nth-child(1), .bmatch:nth-child(2) { border-top: 0; }
.bmatch:nth-child(odd) { border-right: 1px solid var(--line-soft); }

/* A grid, not flex: the score column has to line up down the whole list, and
   with flex the team names shift it around by however long they happen to be. */
.bm-head {
  width: 100%; height: 100%; cursor: pointer; font-family: inherit; text-align: left;
  background: none; border: 0; color: var(--fg);
  display: grid; grid-template-columns: 46px minmax(0, 1fr) 52px minmax(0, 1fr);
  align-items: center; gap: 7px; padding: 10px 11px;
  transition: background .13s;
}
.bm-head:hover { background: rgba(30, 39, 50, .55); }

.bm-when {
  font-size: 11px; color: var(--fg-mute); font-variant-numeric: tabular-nums;
  line-height: 1.3;
}
/* An in-play match shows the minute in the accent colour where the kickoff time
   would be, so a glance down the column separates live from scheduled. */
.bm-when.live { color: var(--red); font-weight: 800; }
.bm-when small { display: block; font-size: 9.5px; letter-spacing: .04em; opacity: .8; }

/*
 * Both sides pack toward the score in the middle, not out to the panel edges.
 *
 * Left-aligning home and right-aligning away put 300px of dead space around the
 * score on a 1076px panel and made the row read as two unrelated columns. Packed
 * inward, the eye gets "name crest SCORE crest name" as one unit.
 *
 * row-reverse on the home side is what puts its crest nearest the score while
 * leaving the crest first in the markup, so the DOM order stays home-crest,
 * home-name for anything reading the row aloud.
 */
.bm-side {
  display: flex; align-items: center; gap: 8px; min-width: 0;
  flex-direction: row-reverse; justify-content: flex-start; text-align: right;
}
.bm-side.away { flex-direction: row; text-align: left; }
.bm-side b {
  font-size: 12.5px; font-weight: 600; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.bm-crest {
  width: 22px; height: 22px; flex: 0 0 22px; object-fit: contain;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .55));
}

.bm-score {
  text-align: center; font-size: 15px; font-weight: 800;
  font-variant-numeric: tabular-nums; letter-spacing: .02em;
}
.bm-score.pending { font-size: 11px; font-weight: 600; color: var(--fg-mute); letter-spacing: .1em; }

/* --------------------------------------------------------- match modal --- */

/*
 * Match detail sits in a modal, not in the row.
 *
 * Inline expansion worked while the list was one column; with two, opening a
 * match on the left pushed every row on the right downward, which is disorienting
 * on a board that also repaints itself every twenty seconds. A modal is also the
 * only way to give the statistics real width.
 *
 * The player keeps playing behind it. Nothing here touches the video element.
 */
.mdl {
  position: fixed; inset: 0; z-index: 80;
  display: flex; align-items: center; justify-content: center; padding: 22px 16px;
}
.mdl[hidden] { display: none; }
.mdl-back {
  position: absolute; inset: 0;
  background: rgba(6, 9, 13, .74);
  backdrop-filter: blur(3px);
  animation: mdl-in .16s ease;
}
.mdl-box {
  position: relative; z-index: 1;
  width: 100%; max-width: 720px; max-height: 86vh;
  display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 12px; box-shadow: 0 24px 70px rgba(0, 0, 0, .6);
  animation: mdl-rise .18s cubic-bezier(.2, .8, .3, 1);
}
@keyframes mdl-in { from { opacity: 0; } }
@keyframes mdl-rise { from { opacity: 0; transform: translateY(10px); } }
@media (prefers-reduced-motion: reduce) {
  .mdl-back, .mdl-box { animation: none; }
}

.mdl-x {
  position: absolute; top: 8px; right: 10px; z-index: 2;
  width: 30px; height: 30px; border-radius: 50%;
  cursor: pointer; font-family: inherit; font-size: 19px; line-height: 1;
  color: var(--fg-mute); background: transparent; border: 1px solid transparent;
  transition: color .13s, background .13s, border-color .13s;
}
.mdl-x:hover { color: #fff; background: var(--red); border-color: var(--red); }

/* Fixed header, scrolling body: the score should stay visible while reading
   down a long stat list. */
.mdl-hd {
  flex: 0 0 auto; padding: 16px 46px 14px 18px;
  border-bottom: 1px solid var(--line-soft);
  background: var(--surface-2); border-radius: 12px 12px 0 0;
}
.mdl-meta {
  display: flex; align-items: center; gap: 8px; margin-bottom: 12px;
  font-size: 10.5px; font-weight: 800; letter-spacing: .1em; color: var(--fg-mute);
}
.mdl-meta .q { letter-spacing: .05em; }
.mdl-teams {
  display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center; gap: 14px;
}
.mdl-team { display: flex; align-items: center; gap: 10px; min-width: 0; }
.mdl-team.h { flex-direction: row-reverse; text-align: right; }
.mdl-team img {
  width: 34px; height: 34px; flex: 0 0 34px; object-fit: contain;
  filter: drop-shadow(0 1px 3px rgba(0, 0, 0, .6));
}
.mdl-team b {
  font-size: 14px; font-weight: 600; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mdl-score {
  font-size: 26px; font-weight: 800; letter-spacing: .01em;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.mdl-score.pending {
  font-size: 13px; font-weight: 700; color: var(--fg-mute); letter-spacing: .08em;
}

.mdl-body {
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
  padding: 16px 18px 20px;
  display: grid; grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr);
  gap: 24px;
  scrollbar-width: thin; scrollbar-color: #303e4e transparent;
}
.mdl-body::-webkit-scrollbar { width: 10px; }
.mdl-body::-webkit-scrollbar-track { background: transparent; }
.mdl-body::-webkit-scrollbar-thumb {
  background: #303e4e; border-radius: 999px;
  border: 3px solid transparent; background-clip: content-box;
}
.mdl-body::-webkit-scrollbar-button { display: none; width: 0; height: 0; }
/* Set by the client when the match has no goals or cards yet - see paintModalBody. */
.mdl-body.one { grid-template-columns: 1fr; gap: 16px; }

.bm-sec h3 {
  margin: 0 0 11px; font-size: 10.5px; font-weight: 800; letter-spacing: .1em;
  color: var(--fg-mute); display: flex; align-items: center; gap: 7px;
}
.bm-loading, .bm-none {
  margin: 0; padding: 14px 0; color: var(--fg-mute); font-size: 12px;
}

/* One statistic: values either side of the label, a split bar underneath. The
   bar carries the comparison, the numbers carry the detail - a bar alone cannot
   tell you 62% from 58%, and numbers alone are not scannable. */
.st { margin-bottom: 11px; }
.st-top {
  display: flex; align-items: baseline; gap: 10px;
  font-size: 11.5px; color: var(--fg-dim); margin-bottom: 4px;
}
.st-top b { font-weight: 700; color: var(--fg); font-variant-numeric: tabular-nums; }
.st-top span { flex: 1 1 auto; text-align: center; color: var(--fg-mute); font-size: 11px; }
.st-bar {
  display: flex; height: 5px; border-radius: 3px; overflow: hidden;
  background: var(--surface-3);
}
.st-bar i { display: block; transition: width .3s ease; }
/* Home in the brand red, away in a neutral: colouring both would make the eye
   compare hues instead of lengths. */
.st-bar i.h { background: var(--red); }
.st-bar i.a { background: #46586c; }

/* ---- timeline ---- */

.tl { list-style: none; margin: 0; padding: 0; }
.tl li {
  display: grid; grid-template-columns: 34px 18px 1fr; gap: 8px;
  align-items: baseline; padding: 5px 0; font-size: 12px;
}
.tl li + li { border-top: 1px dashed var(--line-soft); }
.tl-m {
  font-size: 11px; font-weight: 700; color: var(--fg-mute);
  font-variant-numeric: tabular-nums;
}
.tl-ic { font-size: 12px; line-height: 1; }
.tl-p { min-width: 0; }
.tl-p b { font-weight: 600; }
/* The club under the player, quieter: the reader already knows the two teams
   from the row above, so this is disambiguation, not information. */
.tl-p span { display: block; font-size: 10.5px; color: var(--fg-mute); }
/* An away-team event is pushed right, so which side did what is readable
   without reading the club name at all. */
.tl li.away { text-align: right; grid-template-columns: 1fr 18px 34px; }
.tl li.away .tl-m { order: 3; }
.tl li.away .tl-ic { order: 2; }
.tl li.away .tl-p { order: 1; }

@media (max-width: 900px) {
  /* One column of matches: two would leave each team about 60px of name. */
  .board-list { grid-template-columns: 1fr; }
  .bmatch:nth-child(odd) { border-right: 0; }
  .bmatch:nth-child(2) { border-top: 1px solid var(--line-soft); }
}
@media (max-width: 640px) {
  .mdl { padding: 0; align-items: flex-end; }
  /* Full width, anchored to the bottom: a sheet is the phone idiom, and a
     centred card with 16px margins wastes the only space there is. */
  .mdl-box { max-width: none; max-height: 92vh; border-radius: 14px 14px 0 0; }
  .mdl-hd { border-radius: 14px 14px 0 0; }
  .mdl-body { grid-template-columns: 1fr; gap: 18px; }
  .mdl-score { font-size: 22px; }
  .mdl-team img { width: 28px; height: 28px; flex-basis: 28px; }
  .mdl-team b { font-size: 13px; }
  .bm-head { grid-template-columns: 42px minmax(0,1fr) 48px minmax(0,1fr); gap: 6px; padding: 10px 8px; }
  .bm-side b { font-size: 12px; }
  /* Below this the crests carry the identification and the names would be
     truncated to three letters anyway. */
  .bm-crest { width: 19px; height: 19px; flex-basis: 19px; }
}



/* ---- board filter row ---- */

/* Chips scroll horizontally, so they need a way to be scrolled. Without the
   arrows everything past the visible edge was unreachable with a mouse - a
   trackpad could swipe it, a mouse could not. The dropdown is the direct route
   for anyone who would rather not scroll at all. */
.board-filters {
  display: flex; align-items: center; gap: 6px;
  padding: 0 4px 10px;
}
.board-filters .board-tabs { flex: 1 1 auto; min-width: 0; padding: 0; }

.tscroll {
  flex: 0 0 auto; width: 26px; height: 30px; padding: 0;
  cursor: pointer; font-family: inherit; font-size: 17px; line-height: 1;
  color: var(--fg-dim); background: rgba(23, 30, 39, .92);
  border: 1px solid var(--line); border-radius: 8px;
  transition: color .13s, border-color .13s, opacity .13s;
}
.tscroll:hover { color: #fff; border-color: var(--red); }
/* Hidden rather than disabled when there is nothing to scroll to: a dead arrow
   invites a click that does nothing. */
.tscroll[hidden] { display: none; }

/*
 * League dropdown.
 *
 * Hand-built rather than a <select>, because a native dropdown draws its list
 * with the operating system's scrollbar - an unstyleable pale slab that looked
 * broken against the dark panel. Owning the panel means owning the scrollbar.
 */
.lgdd { position: relative; flex: 0 0 auto; }
.lgdd-btn {
  display: flex; align-items: center; gap: 8px;
  max-width: 210px; padding: 7px 11px; cursor: pointer;
  font-family: inherit; font-size: 11.5px; font-weight: 700;
  color: var(--fg-dim); background: rgba(23, 30, 39, .92);
  border: 1px solid var(--line); border-radius: 20px;
  transition: color .13s, border-color .13s;
}
.lgdd-btn:hover, .lgdd-btn[aria-expanded="true"] { color: #fff; border-color: var(--red); }
.lgdd-btn span {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lgdd-btn svg { width: 11px; height: 8px; flex: 0 0 11px; transition: transform .15s; }
.lgdd-btn[aria-expanded="true"] svg { transform: rotate(180deg); }

.lgdd-panel {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 30;
  width: 232px; max-height: 320px; overflow-y: auto;
  padding: 5px; border-radius: 10px;
  background: var(--surface); border: 1px solid var(--line);
  box-shadow: 0 16px 40px rgba(0, 0, 0, .55);
  scrollbar-width: thin; scrollbar-color: #303e4e transparent;
}
.lgdd-panel[hidden] { display: none; }
.lgdd-panel::-webkit-scrollbar { width: 10px; }
.lgdd-panel::-webkit-scrollbar-track { background: transparent; }
.lgdd-panel::-webkit-scrollbar-thumb {
  background: #303e4e; border-radius: 999px;
  border: 3px solid transparent; background-clip: content-box;
}
.lgdd-panel::-webkit-scrollbar-thumb:hover { background: #45596e; background-clip: content-box; }
.lgdd-panel::-webkit-scrollbar-button { display: none; width: 0; height: 0; }

.lgdd-opt {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 7px 9px; cursor: pointer; text-align: left;
  font-family: inherit; font-size: 12px; font-weight: 500;
  color: var(--fg-dim); background: none; border: 0; border-radius: 7px;
  transition: color .1s, background .1s;
}
.lgdd-opt:hover { color: #fff; background: var(--surface-3); }
.lgdd-opt.on { color: #fff; background: var(--red); font-weight: 700; }
.lgdd-opt img { width: 16px; height: 16px; flex: 0 0 16px; object-fit: contain; }
.lgdd-opt span { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lgdd-opt u { font-style: normal; text-decoration: none; opacity: .6; font-size: 10.5px; }


@media (max-width: 640px) {
  /* On a phone the row swipes naturally, so the arrows are dead weight and the
     dropdown does the work. */
  .tscroll { display: none; }
  .lgdd-btn { max-width: 150px; }
  .lgdd-panel { width: 220px; }
}

/* A league chip whose league has a match in play. The red count is the signal;
   the ring makes it findable while scrolling the row. */
.btab.haslive { border-color: rgba(226, 35, 26, .5); }
.btab u.lv {
  opacity: 1; margin-left: 6px; padding: 1px 6px;
  background: var(--red); color: #fff; border-radius: 20px;
  font-size: 9.5px; font-weight: 800;
}
.btab.on u.lv { background: rgba(0, 0, 0, .28); }

/* ---- chronological board rows ---- */


/* A match row. Grid, not flex: the score column has to line up down the whole
   list, and with flex the team names shift it by however long they happen to be. */
.mrow2 {
  width: 100%; cursor: pointer; font-family: inherit; text-align: left;
  background: none; border: 0; color: var(--fg);
  display: grid; grid-template-columns: 50px 20px minmax(0, 1fr) 62px minmax(0, 1fr);
  align-items: center; gap: 9px; padding: 9px 13px;
  border-bottom: 1px solid var(--line-soft);
  transition: background .12s;
}
.mrow2:last-child { border-bottom: 0; }
.mrow2:hover { background: rgba(30, 39, 50, .6); }
/* A running match is the one thing on the page that changes, so it gets the
   accent edge; a finished one recedes. */
.mrow2.islive { background: rgba(226, 35, 26, .06); box-shadow: inset 2px 0 0 var(--red); }
.mrow2.islive:hover { background: rgba(226, 35, 26, .1); }
.mrow2.isdone { opacity: .62; }

.m-when {
  font-size: 11.5px; color: var(--fg-dim); font-variant-numeric: tabular-nums;
  line-height: 1.25; font-weight: 600;
}
.m-when.live { color: var(--red); font-weight: 800; }
.m-when small {
  display: block; font-size: 9px; letter-spacing: .04em; opacity: .75;
  font-weight: 600; text-transform: uppercase;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.m-lg { width: 18px; height: 18px; object-fit: contain; opacity: .9; }

/* Both sides pack toward the score, so the row reads as one unit rather than
   two columns with dead space between them. */
.m-side {
  display: flex; align-items: center; gap: 8px; min-width: 0;
  flex-direction: row-reverse; justify-content: flex-start; text-align: right;
}
.m-side.away { flex-direction: row; text-align: left; }
.m-side b {
  font-size: 12.5px; font-weight: 600; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.m-score {
  text-align: center; font-size: 15px; font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.m-score.pending {
  font-size: 11px; font-weight: 600; color: var(--fg-mute); letter-spacing: .1em;
}

/* ---- pager ---- */

/* Small on purpose: this is navigation for a side panel, not the subject of the
   page. */
.pgr {
  display: flex; align-items: center; gap: 4px; flex-wrap: wrap;
  padding: 10px 2px 0;
}
.pgr-a, .pgr-n {
  min-width: 26px; height: 26px; padding: 0 7px; cursor: pointer;
  font-family: inherit; font-size: 11.5px; font-weight: 700;
  color: var(--fg-dim); background: rgba(23, 30, 39, .92);
  border: 1px solid var(--line); border-radius: 7px;
  transition: color .12s, background .12s, border-color .12s;
}
.pgr-a { font-size: 14px; line-height: 1; }
.pgr-a:hover:not(:disabled), .pgr-n:hover { color: #fff; border-color: var(--red-dim); }
.pgr-a:disabled { opacity: .35; cursor: default; }
.pgr-n.on {
  color: #fff; background: var(--red); border-color: var(--red); cursor: default;
}
.pgr-gap { color: var(--fg-mute); font-size: 11px; padding: 0 1px; }
.pgr-i { margin-left: auto; font-size: 10.5px; color: var(--fg-mute); }

@media (max-width: 640px) {
  .pgr-i { display: none; }
}

/* ---- modal tabs ---- */

/* Stats, a timeline and two starting elevens is far more than fits on a phone;
   stacked, the lineups sat under sixty lines of scroll. */
.mdl-tabs {
  grid-column: 1 / -1;
  display: flex; gap: 6px; flex-wrap: wrap;
  padding: 0 0 14px; margin: 0;
  border-bottom: 1px solid var(--line-soft);
}
.mtab {
  cursor: pointer; font-family: inherit;
  padding: 6px 13px; border-radius: 20px;
  font-size: 10.5px; font-weight: 800; letter-spacing: .08em;
  color: var(--fg-mute); background: var(--surface-2);
  border: 1px solid var(--line);
  transition: color .13s, background .13s, border-color .13s;
}
.mtab:hover { color: var(--fg); border-color: #2e3a49; }
.mtab.on { color: #fff; background: var(--red); border-color: var(--red); }
.mdl-panel { grid-column: 1 / -1; padding-top: 14px; }
.mdl-lg { width: 18px; height: 18px; object-fit: contain; flex: 0 0 18px; }

/* Half-time score and venue: the two questions the headline score cannot
   answer, kept small. */
.mdl-sub {
  margin: 11px 0 0; font-size: 11.5px; color: var(--fg-mute);
  font-variant-numeric: tabular-nums;
}

/* ---- lineups ----
   Only the formation badge and the coach line survive from the original
   two-column layout; everything else is now .lu2-* (see below). */

.lu-form {
  margin-left: auto; flex: 0 0 auto;
  font-size: 10px; font-weight: 800; letter-spacing: .06em;
  color: var(--gold); border: 1px solid color-mix(in srgb, var(--gold) 35%, transparent);
  border-radius: 20px; padding: 2px 8px;
}
.lu-coach { margin: 0 0 9px; font-size: 10.5px; color: var(--fg-mute); }

/* Timeline icons are SVG now, so the box just needs to size them. */
.tl-ic { width: 14px; height: 14px; display: block; }
.tl-ic svg { width: 14px; height: 14px; display: block; }

.bm-right { display: flex; flex-direction: column; gap: 22px; min-width: 0; }

@media (max-width: 780px) {
  .mrow2 { grid-template-columns: 44px 0 minmax(0, 1fr) 52px minmax(0, 1fr); gap: 7px; padding: 9px 9px; }
  .m-lg { display: none; }
  .lu { grid-template-columns: 1fr; gap: 16px; }
}

/* ------------------------------------------------------------- footer --- */

.ftr {
  border-top: 1px solid var(--line-soft); padding: 14px 22px;
  background: rgba(10, 13, 18, .72);
  display: flex; align-items: center; justify-content: center; gap: 12px;
  color: var(--fg-mute); font-size: 12.5px;
}
.ftr img { height: 20px; opacity: .55; }
/* The sponsorship mark reads at full strength and full size. It is the one thing
   in the footer that is not ours to dim, and at 20px the wordmark inside the
   red band was illegible. Width is left to the aspect ratio. */
.ftr .ftr-sponsor { height: 46px; width: auto; opacity: 1; }
@media (max-width: 640px) {
  .ftr { padding: 12px 16px; gap: 10px; font-size: 11.5px; }
  .ftr .ftr-sponsor { height: 36px; }
}

/* ------------------------------------------------------------ responsive - */



/* Below this the list cannot sit beside the player, so it stacks underneath and
   takes a fixed height of its own instead of borrowing the player's. */
/* Stack only when the two columns genuinely cannot sit side by side. At 1050 it
   was still stacking on ordinary laptops and adding 340px to the page. */
@media (max-width: 820px) {
  .hero-in { grid-template-columns: 1fr; }
  .rail-wrap { height: 300px; }
}
@media (max-width: 900px) {
  /* The skin's artwork sits in gutters that do not exist at this width - it
     would only show a blurred crop behind the panels. */
  body { background-image: none; }
}
@media (max-width: 640px) {
  .mt .crest { width: 22px; height: 22px; flex-basis: 22px; }
  .prov { flex-basis: 84px; width: 84px; height: 26px; }
  .provtrack { gap: 30px; }
  .hdr-in { height: 56px; padding: 0 14px; gap: 12px; }
  .logo img { height: 25px; }
  .social { gap: 6px; }
  .social a { width: 31px; height: 31px; border-radius: 8px; }
  .hero-in { padding: 14px; gap: 14px; }
  .screen { border-radius: var(--r-sm); }
  .under { padding-top: 12px; }
  .under h1 { font-size: 16.5px; }
  .under-r { width: 100%; }
  /* The logo column shrinks before the quality chip does - knowing a stream is
     4K matters more on a small screen than seeing the wordmark full size. */
  .ident { flex-basis: 108px; height: 23px; }
  .crest { width: 22px; height: 22px; flex-basis: 22px; }
}

/* ---- fixtures that will not be played ------------------------------------ */

/*
 * Postponed, cancelled, abandoned and time-unknown fixtures.
 *
 * These sit in neither the in-play nor the finished set, so they used to fall
 * through to the "upcoming" branch and advertise a kickoff time - a cancelled
 * match looked like it was about to start, and a TBD one claimed "00:00". The
 * row now prints the real status instead, and this makes it look inert rather
 * than imminent: no accent colour, struck through, so it reads as struck off
 * the card at a glance.
 */
.m-when.off {
  color: var(--fg-mute); font-weight: 700;
  text-decoration: line-through; text-decoration-thickness: 1px;
}
.m-when.off small { text-decoration: none; }
/* The modal chip keeps .q.soon for its shape, so the colour has to be undone
   here - gold on a cancelled match reads as "starting soon". */
.q.soon.off {
  color: var(--fg-mute); border-color: var(--line); background: var(--surface-3);
  letter-spacing: .05em;
}

/* ---- standings: the columns that explain the ordering -------------------- */

/*
 * O G B M Av P + form is nine columns. That fits the 372px rail on the
 * CasinoPer page and does not fit index2's 290px one - the team name is what
 * gets crushed, and a puan durumu whose team names are ellipsised to six
 * characters is worse than one missing a column.
 *
 * So the narrow page shows the minimum that still justifies the sort order -
 * played, goal difference, points - and the wider one shows the full set. The
 * markup is identical on both; only these three columns are dropped. Column
 * order is 1 rk, 2 tm, 3 O, 4 G, 5 B, 6 M, 7 Av, 8 P, 9 Form.
 */
.stbl th, .stbl td { padding: 6px 4px; }
.stbl th:first-child, .stbl td:first-child { padding-left: 9px; }
.stbl th:last-child, .stbl td:last-child { padding-right: 9px; }
.stbl td.num, .stbl th.num { width: 22px; padding-left: 2px; padding-right: 2px; }
.stbl td.rk { width: 20px; }
.stbl td.fm { width: 50px; }
.stbl .st-form .fp { width: 5px; height: 5px; }

/* Win / draw / loss, hidden where there is no room for them. */
.stbl th:nth-child(4), .stbl td:nth-child(4),
.stbl th:nth-child(5), .stbl td:nth-child(5),
.stbl th:nth-child(6), .stbl td:nth-child(6) { display: none; }

/* Goal difference is the visible tie-break, so it is never one of the columns
   that gets dropped - it is the answer to "why is this team above that one". */
.stbl td.gd { color: var(--fg-dim); font-weight: 700; }

/* ---- lineups: position groups and the bench ----------------------------- */


/* ---- a statistic the API did not report --------------------------------- */

/*
 * Distinct from a measured zero. The row keeps its label and shows an en dash
 * with no bar at all, because a bar is a comparison and there is nothing to
 * compare - drawing a 50/50 one would assert the two sides were level.
 */
.st.st-na { opacity: .55; }
.st.st-na .st-top b { color: var(--fg-mute); font-weight: 600; }

/* ---- lineups: one shared heading per position group ---------------------- */

/*
 * Two teams, one set of headings.
 *
 * These used to be two independent columns, each with its own run of position
 * headings. Because the sides field different shapes - a 3-4-3 against a
 * 4-1-4-1 - the headings drifted apart vertically: the left column's "ORTA
 * SAHA" sat three rows above the right column's, and the panel read as two
 * unrelated team sheets rather than one comparison.
 *
 * So the structure is inverted. Each position group is a full-width band with a
 * single heading, and inside it the two teams' players are paired row by row.
 * Where one side has more players in a group, the other gets an empty cell, so
 * the pairing - and every heading below it - stays level.
 */
.lu2-teams,
.lu2-coaches,
.lu2-row {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px;
}

.lu2-team { display: flex; align-items: center; gap: 8px; min-width: 0; }
.lu2-team b {
  font-size: 12.5px; font-weight: 700; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.lu2-team .lu-form { margin-left: auto; flex: 0 0 auto; }

.lu2-coaches { margin-bottom: 4px; }
.lu2-coaches .lu-coach { margin: 4px 0 0; }
/* An empty coach cell still has to occupy its half, or the row collapses and
   the two team sheets fall out of step by a line. */
.lu2-coaches .lu-coach:empty::before { content: "\00a0"; }

.lu2-grp { margin-top: 11px; }

/*
 * The heading spans both teams, so it is centred with a rule running out to
 * either side - that reads as "this band applies to both" in a way a
 * left-aligned label above two columns does not.
 */
.lu2-gt {
  display: flex; align-items: center; gap: 9px;
  margin: 0 0 5px;
  font-size: 9.5px; font-weight: 800; letter-spacing: .08em;
  text-transform: uppercase; color: var(--fg-mute);
  white-space: nowrap;
}
.lu2-gt::before,
.lu2-gt::after {
  content: ""; flex: 1 1 auto; height: 1px; background: var(--line-soft);
}

.lu2-row + .lu2-row .lu2-p { border-top: 1px dashed var(--line-soft); }

.lu2-p {
  /*
   * Centred, not left-aligned.
   *
   * Each half of the row is far wider than a shirt number plus a name, so
   * left-aligning left the two elevens hugging the outer edges of the modal
   * with a channel of dead space down the middle - they read as drifting apart
   * rather than as a comparison. Centring pulls each side in toward the divide.
   *
   * It costs the numbers their straight edge, which is why the original was
   * left-aligned. Worth it here: the number is a label on a name, not a column
   * anyone reads down.
   */
  display: flex; align-items: baseline; justify-content: center; gap: 9px;
  padding: 4px 0; font-size: 12px;
  /* Holds the row open when the cell is a pad. An empty flex item has no
     content and would otherwise collapse to nothing, letting the shorter side
     pull the next heading up and undoing the whole point of this layout. */
  min-height: 25px;
}
/* Auto width now the pair is centred - a fixed 20px box just offsets it. */
.lu2-p i {
  flex: 0 0 auto; font-style: normal; text-align: right;
  font-size: 10.5px; font-weight: 700; color: var(--fg-mute);
  font-variant-numeric: tabular-nums;
}
.lu2-p > span {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Headings sit over centred pairs, so they centre too. */
.lu2-teams .lu2-team { justify-content: center; }
.lu2-coaches .lu-coach { text-align: center; }
/* The pad itself: present for layout, invisible and unreadable. */
.lu2-p.none { border-top-color: transparent; }

/* The bench is longer than the eleven and secondary to it. */
.lu2-bench { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line-soft); }
.lu2-bench .lu2-p { padding: 3px 0; min-height: 22px; font-size: 11.5px; color: var(--fg-dim); }
.lu2-bench .lu2-gt { opacity: .85; }

@media (max-width: 560px) {
  .lu2-teams, .lu2-coaches, .lu2-row { gap: 10px; }
  .lu2-p { font-size: 11px; gap: 6px; }
  .lu2-p i { flex: 0 0 16px; }
}

/* ---- featured fixtures --------------------------------------------------- */

/*
 * A gold star and a gold edge on a featured fixture.
 *
 * index3 groups its featured matches under an ÖNE ÇIKANLAR heading, so there
 * the marker is reinforcement. index2 deliberately shows one combined list -
 * live and upcoming together, in kickoff order - so grouping would break the
 * chronology that list exists to provide. The star is how a featured fixture
 * announces itself there instead, in place.
 *
 * Gold rather than the brand accent: red on BahisNow and teal on CasinoPer both
 * already mean something else on this row (live, and the brand itself), and a
 * third meaning on the same two colours would stop any of them reading clearly.
 * The star is inline, before the title, rather than absolutely positioned in a
 * corner - the row is a tight grid and a floating glyph would collide with the
 * CANLI badge at one end or the crests at the other.
 */
/*
 * A gold wash on the row and a star on the meta line - not beside the team.
 *
 * The first attempt put the star immediately before the team name and a gold
 * bar down the row's left edge. Both were wrong. The bar competed with the
 * inset edge live rows already use, so a featured live fixture carried two
 * coloured edges meaning different things; and a glyph in front of the name
 * pushed into the busiest text in the row.
 *
 * So the row carries the signal as a wash, and the star moves to the league
 * line where there is space to spare.
 */
.ritem.featured {
  background: linear-gradient(90deg, rgba(242, 183, 5, .10), rgba(242, 183, 5, 0) 62%);
}
.ritem.featured:hover {
  background: linear-gradient(90deg, rgba(242, 183, 5, .16), rgba(242, 183, 5, .02) 62%);
}
.ritem.featured .ritem-t span::after {
  content: " ★";
  color: var(--gold);
  font-size: 9px;
  vertical-align: 1px;
}

/* ---- rail group headings ------------------------------------------------- */

/*
 * Headings that split the rail into featured and the rest. Emitted only by the
 * two-view rail (index3); index2 has no groups, so these never match there.
 */
.rgrp { padding: 10px 8px 4px; }
.rgrp:first-child { padding-top: 4px; }
.rgrp-t {
  display: flex; align-items: center; gap: 7px; margin: 0;
  font-size: 9.5px; font-weight: 800; letter-spacing: .09em;
  text-transform: uppercase; color: var(--fg-mute);
}
/* The count sits at the end of the label, not pinned to the far edge - the rail
   is narrow and a right-aligned number reads as belonging to the row below. */
.rgrp-n {
  text-decoration: none; font-size: 9.5px; font-weight: 700;
  color: var(--fg-mute); opacity: .7;
}
.rgrp-n::before { content: "("; }
.rgrp-n::after { content: ")"; }

/* ---- scrolling lists settle on whole rows -------------------------------- */

/*
 * Snap, so a scroll never rests halfway through a card.
 *
 * These lists scroll inside fixed-height panels, so the container edge cuts
 * whatever row happens to straddle it - the first and last entries end up half
 * visible and read as broken rather than as "there is more". Snapping makes the
 * scroll settle on a row boundary instead.
 *
 * `proximity`, not `mandatory`: mandatory hijacks every small scroll and fights
 * a trackpad, and on a list whose rows are taller than the viewport it can trap
 * the user between two snap points. Proximity only tidies up a scroll that
 * already ended near a boundary, which is exactly the half-row case.
 */
.rail-body,
.lsc-list,
.stand-body {
  scroll-snap-type: y proximity;
}
.rail-body > .ritem,
.rail-body > .mrow,
.lsc-list > .lsc-row {
  scroll-snap-align: start;
}
/* The standings' sticky header is the scroll port's top edge, so rows snap
   below it rather than under it. */
.stand-body .stbl tbody tr { scroll-snap-align: start; }

/* Group headings should not be snap targets - stopping with a heading pinned to
   the top and its first row cut underneath is the bug, not the fix. */
.rgrp { scroll-snap-align: none; }

/* ---- tabs read as readable, selected or not ------------------------------ */

/*
 * An unselected tab is still a label someone has to read to choose it. These
 * sat at --fg-mute, which against these panels is legible only if you are
 * looking for it - and the modal's tabs were dimmer still. Selection is already
 * carried by the pill, the underline and the accent; it does not also need the
 * unselected items pushed to the edge of visibility.
 */
.rtab, .mtab { color: var(--fg); }
.rtab:hover, .mtab:hover { color: var(--fg); }

/*
 * A tab with no data behind it stays distinguishable but stops being unreadable.
 * .45 opacity made "İLK 11" a grey smudge; at .72 it reads as available-but-
 * empty, which is the actual state, and the tooltip still explains it.
 */
.mtab.empty, body.cper .mtab.empty { opacity: .72; }
.mtab.empty:hover, body.cper .mtab.empty:hover { opacity: .9; }

/* The player and the rail meet flush, so the screen is square on the side that
   touches the rail - index3 already does this; this brings index2 in line. */
.screen { border-radius: var(--r) 0 0 var(--r); }

/* ---- the video fills its column ------------------------------------------ */

/*
 * width:100% + aspect-ratio, instead of capping the width by viewport height.
 *
 * The old rule was `min(100%, calc((100vh - var(--chrome)) * 16 / 9))`, which
 * sizes the video so the whole page fits one screen. The side effect is that on
 * any window shorter than that calculation assumes, the video comes out
 * narrower than the column holding it - 915px inside a 983px column on a
 * 706-tall window - and the panel behind it shows as a vertical strip down the
 * right-hand side, right where the rail begins. That strip is what read as a
 * black line between the player and the schedule.
 *
 * The page has a scoreboard below the fold anyway, so it was never really one
 * screen. Letting the video own its column's full width and take its height
 * from the ratio removes the strip and makes the picture bigger on every window
 * that was previously being capped.
 */
.screen {
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: 0;
}
/* Square throughout: the player meets the rail on one side and the caption bar
   below, so a radius on any of those edges notches into something flat. */
.player-col { border-radius: 0; }
/* One divider, not two. The column has no right border, so the rail's left one
   was the whole line - and with the panels sharing a background it separates
   nothing that the rail's own content does not already separate. */
.rail { border-left: 0; }

/* ---- tabs: the same white, selected or not ------------------------------- */

/*
 * No opacity dimming on an empty tab.
 *
 * Two passes at "dim but readable" (.45, then .72) both still read as grey
 * beside a full-strength neighbour, which is exactly the complaint. The tab's
 * job is to be readable; the fact that it has no data behind it is told by the
 * panel it opens and by its title attribute, neither of which needs the label
 * sacrificed to say it.
 */
.mtab.empty, body.cper .mtab.empty { opacity: 1; }
.mtab.empty:hover, body.cper .mtab.empty:hover { opacity: 1; }

/* The CANLI / YAYINLANACAKLAR / SIRALAMA bar, same reasoning as the rail tabs
   above: selection is carried by the underline and the accent, not by making
   everything else hard to read. */
.mtb { color: var(--fg); }
.mtb:hover { color: var(--fg); }

/* ---- the player sits flush, with no edge of its own ---------------------- */

/*
 * No border on .screen, and no side padding on its column.
 *
 * The remaining "line" beside the video was .screen's own 1px border. With the
 * column padding gone the video now ends exactly where the rail begins, so that
 * border had nothing to separate - it just drew a dark rule down the join.
 *
 * The column's 6px left padding went with it: it inset the video on the left
 * while the right sat flush, so the picture was 7px off-centre in its own
 * column. Flush on both sides.
 */
.screen { border: 0; }
.player-col { padding-left: 0; padding-right: 0; }

/* ---- featured rows: the star, not a wash --------------------------------- */

/*
 * The gold background is dropped. On a row that is not the one playing it read
 * as a selection highlight - two rows looking "chosen" at once, one of them
 * wrongly. The star after the league name already says featured, and it says it
 * without competing with the .on state the player actually uses.
 */
.ritem.featured,
.ritem.featured:hover { background: none; }
