/*
Theme Name: UFootball v2
Theme URI: https://ufootball.com.my/
Description: Classic theme for ufootball.com.my. Predictions UI reads the engine API client-side; article bodies always come from the_content().
Author: U Football
Version: 5.24.8
Requires PHP: 8.1
Text Domain: ufootball-v2
*/

/* assets/css/site.css carries the design system (--primary, .hdr, .hero, .sec,
   .ml-*, .st-*, .ps-*, .oc-*, .tn-*). This file only adds what it lacks:
   the league sidebar, date bar, and the WP-side post templates. */

/* ── card surface ──
   Grey page, white cards. Rows live inside a card separated by hairlines rather
   than floating as individual cards, so a competition reads as one object. */

body { background: var(--bg-2) }

.uf-card {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}

.uf-card-title {
  padding: 16px 18px 10px;
  font-family: 'Archivo', sans-serif;
  font-weight: 700;
  font-size: 15px;
  color: var(--text);
}

/* ── homepage additions ── */

/* The match section rides up over the base of the hero so the cards break the
   banner edge instead of starting cleanly below it. */
#sec-matches { position: relative; z-index: 2; margin-top: -72px }

/* 30 / 70 split. fr units divide what's left AFTER the gap, so unlike percentages
   these two plus the 40px gutter can't overflow the row.
   min-width: 0 on both children is load-bearing: a grid item defaults to
   min-width: auto, which lets long content (a player name in the scorers list)
   push the track wider than its share. */
.uf-split { display: grid; grid-template-columns: 30fr 70fr; gap: 40px; align-items: start }
.uf-split > * { min-width: 0 }
.uf-split-even { grid-template-columns: 1fr 1fr }

.uf-card > .ps-tabs { padding: 0 8px }
.uf-card > .uf-head,
.uf-card > .uf-select,
.uf-card > #standings-body { padding-left: 18px; padding-right: 18px }
.uf-card > .uf-head { padding-top: 18px }
.uf-card > #standings-body { padding-bottom: 6px }

.uf-head { display: flex; align-items: center; justify-content: space-between; gap: 12px }
.uf-head .tn-header { margin-bottom: 20px }

.uf-league-list { list-style: none; margin: 0; padding: 0 0 10px }

.uf-league {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 11px 18px;
  border: 0;
  background: none;
  color: var(--text);
  font: inherit;
  font-weight: 600;
  font-size: 14px;
  text-align: left;
  cursor: pointer;
  transition: color .18s, background .18s;
}

.uf-league:hover { color: var(--primary-dark); background: var(--bg-2) }
.uf-league.on { color: var(--primary-dark); background: var(--primary-light) }

/* Name takes the slack so the badge and chevron stay pinned right, in that order. */
.uf-league-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap }

/* Badges are desaturated at rest so five competing brand palettes don't fight the
   sidebar; colour returns on hover, focus and selection. Purely decorative — the
   league name carries the meaning, so nothing is lost while they're grey. */
.uf-league-badge {
  flex: 0 0 30px;
  width: 30px;
  height: 30px;
  object-fit: contain;
  filter: grayscale(1);
  /* Greyscale alone leaves the darker marks (Bundesliga red) heavier than the
     rest; dropping opacity evens them out. */
  opacity: .5;
  transition: filter .18s, opacity .18s;
}

.uf-league:hover .uf-league-badge,
.uf-league:focus-visible .uf-league-badge,
.uf-league.on .uf-league-badge { filter: none; opacity: 1 }

@media (prefers-reduced-motion: reduce) {
  .uf-league-badge { transition: none }
}

.uf-toolbar { padding: 12px 14px; margin-bottom: 16px; display: grid; gap: 12px }

/* space-between, not center: the label's width changes with the date, which
   would slide the chevrons around under the reader's thumb. Equal 36px navs
   keep the label optically centred anyway. */
.uf-datebar { display: flex; align-items: center; justify-content: space-between; gap: 16px; font-family: 'Archivo', sans-serif }

.uf-daynav {
  width: 36px; height: 36px;
  border: 0;
  border-radius: 50%;
  background: #EBEBEB;
  color: #222;
  font-size: 24px;
  font-weight: 700;
  line-height: 1;
  padding: 0 0 3px; /* the guillemet glyph sits low; lift it to optical centre */
  cursor: pointer;
  transition: background .15s, color .15s;
}

.uf-daynav:hover { background: var(--primary); color: #fff }

/* Pill tabs, matching the reference. site.css styles .ml-tab as an underline tab
   row, which does not belong inside a toolbar card. */
.uf-toolbar .ml-tabs { border-bottom: 0; margin-bottom: 0; gap: 8px; overflow: visible; flex-wrap: wrap }

.uf-toolbar .ml-tab {
  padding: 8px 16px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--bg);
}

.uf-toolbar .ml-tab.on { border-color: var(--primary-dark); background: var(--primary-light) }

/* Date picker. The trigger reads as text, not a control, until you hover it —
   the day is the label as well as the button. */
.uf-datepick-wrap { position: relative }

.uf-datepick {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 4px 8px; border: 0; border-radius: 8px;
  background: transparent; color: inherit;
  font: inherit; font-weight: 700; cursor: pointer;
}

.uf-datepick:hover { background: var(--bg-2) }

.uf-datepick-caret {
  width: 0; height: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 5px solid var(--text-3);
}

.uf-datepick[aria-expanded="true"] .uf-datepick-caret { transform: rotate(180deg) }

.uf-cal {
  position: absolute; z-index: 30; top: calc(100% + 8px); left: 50%;
  transform: translateX(-50%);
  width: 300px; padding: 14px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: 0 12px 32px rgba(0, 0, 0, .16);
}

.uf-cal[hidden] { display: none }

.uf-cal-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px }
.uf-cal-title { font-family: 'Archivo', sans-serif; font-weight: 700; font-size: 15px }

.uf-cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px }

.uf-cal-dow {
  padding-bottom: 6px;
  color: var(--text-3);
  font-size: 11px; font-weight: 600; text-align: center;
}

.uf-cal-day {
  aspect-ratio: 1;
  border: 0; border-radius: 50%;
  background: transparent;
  color: var(--text-1);
  font: inherit; font-size: 13px; font-weight: 600;
  cursor: pointer;
}

.uf-cal-day:hover { background: var(--bg-2) }
.uf-cal-day.out { color: var(--text-3); font-weight: 400 }

/* Today is outlined, the selected day is filled — two different marks, so the
   two states stay distinguishable when they land on the same cell. */
.uf-cal-day.today { box-shadow: inset 0 0 0 1px var(--border) }
.uf-cal-day.on { background: var(--primary-dark); color: #fff }
.uf-cal-day.on:hover { background: var(--primary-dark) }

@media (max-width: 400px) { .uf-cal { width: 264px } }

.uf-group {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 13px 18px;
  border: 0;
  border-bottom: 1px solid var(--border);
  background: #f5f5f5;
  color: var(--primary-dark);
  font: inherit;
  font-size: 13px;
  font-weight: 700;
  text-align: left;
  cursor: pointer;
}

.uf-group[aria-expanded="false"] { border-bottom: 0 }
.uf-group:hover { background: #E5E7EB }

.uf-group .ml-chevron { transform: rotate(90deg); transition: transform .4s ease }
.uf-group[aria-expanded="false"] .ml-chevron { transform: none }
/* Collapse animates via the 0fr/1fr grid-row trick — display:none can't
   transition. The inner wrapper clips the rows while the track shrinks. */
.uf-group-body { display: grid; grid-template-rows: 1fr; transition: grid-template-rows .4s ease }
.uf-group[aria-expanded="false"] + .uf-group-body { grid-template-rows: 0fr }
.uf-group-body-in { overflow: hidden; min-height: 0; display: flex; flex-direction: column }

/* An empty competition is a one-line note, not a full empty state. */
.uf-group-body .uf-empty { padding: 14px 18px; font-size: 13px }

/* ── match rows inside a card ──
   site.css styles .ml-row as a standalone card (border, radius, hover scale).
   Inside a group card that reads as cards-in-cards, so it is flattened here. */
.uf-card .ml-row {
  border: 0;
  border-bottom: 1px solid var(--border);
  border-radius: 0;
  box-shadow: none;
}

.uf-card .ml-row:last-child { border-bottom: 0 }
.uf-card .ml-row:hover { transform: none; box-shadow: none; background: var(--bg-2) }

.uf-group-card { overflow: hidden }
.uf-group-card + .uf-group-card { margin-top: 16px }

@media (prefers-reduced-motion: reduce) {
  .uf-group .ml-chevron, .uf-group-body { transition: none }
  .uf-slide-l, .uf-slide-r, .uf-slide-out-l, .uf-slide-out-r { animation: none }
}

/* standings pager: new league slides in from the direction of travel */
/* cards rise in when data replaces the skeleton — load only, not re-renders */
@keyframes uf-rise { from { transform: translateY(10px); opacity: 0 } to { transform: none; opacity: 1 } }
.uf-enter > * { animation: uf-rise .35s ease backwards }
.uf-enter > :nth-child(2) { animation-delay: .07s }
.uf-enter > :nth-child(3) { animation-delay: .14s }
.uf-enter > :nth-child(4) { animation-delay: .21s }
.uf-enter > :nth-child(n+5) { animation-delay: .28s }
@media (prefers-reduced-motion: reduce) {
  .uf-enter > * { animation: none }
}

@keyframes uf-slide-r { from { transform: translateX(28px); opacity: 0 } to { transform: none; opacity: 1 } }
@keyframes uf-slide-l { from { transform: translateX(-28px); opacity: 0 } to { transform: none; opacity: 1 } }
.uf-slide-r { animation: uf-slide-r .35s ease }
.uf-slide-l { animation: uf-slide-l .35s ease }
/* out phase of the league swap — forwards holds it hidden until the new
   table is painted */
@keyframes uf-slide-out-l { to { transform: translateX(-28px); opacity: 0 } }
@keyframes uf-slide-out-r { to { transform: translateX(28px); opacity: 0 } }
.uf-slide-out-l { animation: uf-slide-out-l .18s ease forwards }
.uf-slide-out-r { animation: uf-slide-out-r .18s ease forwards }

.uf-collapse {
  border: 1px solid var(--border);
  border-radius: 8px;
  background: #fff;
  color: var(--text-3);
  padding: 6px 10px;
  cursor: pointer;
}

.uf-collapse:hover { color: var(--primary-dark); border-color: var(--primary-dark) }

.uf-filter {
  flex: 1;
  min-width: 0;
  margin-left: auto;
  padding: 7px 14px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg-2);
  font: inherit;
  font-size: 13px;
}

.uf-select {
  padding: 7px 14px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: #fff;
  color: inherit;
  font: inherit;
  font-size: 13px;
  margin: 12px 0 4px;
}

.uf-select-inline { margin: 0 0 20px; max-width: 220px }

.uf-empty { color: var(--text-3); font-size: 14px; line-height: 1.6; padding: 24px 16px; text-align: center }
.uf-empty strong { color: var(--text-2); font-weight: 600 }

/* Empty fixture list: sad U-Bao with a deflated ball, greyed by CSS so the
   asset stays full-colour and reusable. Decorative only — the one-line
   sentence carries the meaning, the image just softens it. */
.uf-empty--nofix { padding: 32px 16px }
.uf-empty--nofix::before {
  content: ''; display: block; margin: 0 auto 10px;
  width: 180px; height: 180px;
  background: url(assets/img/mascot-empty.webp) center/contain no-repeat;
  filter: grayscale(1); opacity: .55;
}

/* Loading — U-Bao instead of the loading text. A 4KB static still moved
   by CSS: frame animation (WebP/GIF/Lottie) all lost the race with the data —
   by the time the frames downloaded, the content had arrived. The still is
   cached after first paint, so he can never appear late again.
   Hidden for the first .6s so fast fetches never flash a spinner. */
/* font-size:0 hides the wording without hiding the element: the running mascot
   is the whole message on screen, and the sentence stays in the accessibility
   tree for screen readers. JS drops .uf-loading when it swaps in a real
   message, which restores the text. */
.uf-loading { font-size: 0 }
.uf-loading::before {
  content: ''; display: block; margin: 0 auto 4px;
  width: 110px; height: 110px;
  background: url(assets/img/mascot-loading-still.webp) center/contain no-repeat;
  opacity: 0;
  animation:
    uf-loading-in .4s ease .6s forwards,
    uf-loading-run .5s ease-in-out .6s infinite alternate;
}
@keyframes uf-loading-in { to { opacity: 1 } }
/* Run-bob: the stride pose + vertical bounce and a slight lean reads as running. */
@keyframes uf-loading-run {
  from { transform: translateY(0) rotate(-2deg) }
  to   { transform: translateY(-7px) rotate(2deg) }
}
@media (prefers-reduced-motion: reduce) {
  .uf-loading::before { animation: uf-loading-in .4s ease .6s forwards }
}

/* 404 — image already reads "404", so no heading. One line, one way home. */
.uf-404 {
  max-width: 440px; margin: 48px auto 80px;
  padding: 28px 24px 36px; text-align: center;
}
.uf-404 img { display: block; margin: 0 auto; width: 280px; max-width: 100%; height: auto }
.uf-404-line { margin: 4px 0 22px; color: var(--text-2); font-size: 16px }
.uf-404-home {
  display: inline-block; padding: 10px 22px; border-radius: 12px;
  background: var(--primary, #009E4F); color: #fff; font-weight: 600;
  text-decoration: none;
}
.uf-404-home:hover { filter: brightness(1.06) }

/* ── contrast corrections ──
   #009E4F is 3.50:1 on white — fine as a fill or for large display type, short of
   AA for 11-13px labels. Small green text uses the darker brand green (5.45:1).
   Same reason the CTA fill and the W/L badges are darkened: white on #009E4F is
   also 3.50:1. */

.ml-tab.on,
.ps-tab.on,
.st-pos,
.tn-sec-see,
.uf-group { color: var(--primary-dark) }

.ps-tab.on { border-bottom-color: var(--primary-dark) }

.hero-cta { background: var(--primary-dark) }
.hero-cta:hover { background: #00632F }

.ml-odds-col.is-active .ml-odds-lbl,
.ml-odds-col.is-active .ml-odds-val { color: var(--primary-dark) }

/* ── the pick, stated in words ──
   A green ring is invisible to red-green deficiency, so the word carries it. */
.uf-pick-tag {
  margin-left: 5px;
  padding: 1px 5px;
  border-radius: 4px;
  background: var(--primary-light);
  color: var(--primary-dark);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
}

/* ── live status ── */

.uf-live { display: inline-flex; align-items: center; gap: 5px; color: var(--red-dark); font-weight: 600 }

.uf-live-dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--red-dark);
  animation: uf-pulse 1.6s ease-in-out infinite;
}

@keyframes uf-pulse { 50% { opacity: .25 } }

/* A goal is the one state change worth animating — the number moved and the
   reader needs to catch it. */
.uf-scored { animation: uf-scored 1.8s ease-out }

@keyframes uf-scored {
  0%   { background: var(--primary-light); border-color: var(--primary) }
  100% { background: #fff; border-color: var(--border) }
}

@media (prefers-reduced-motion: reduce) {
  .uf-live-dot, .uf-scored { animation: none }
  .uf-scored { border-color: var(--primary) }
}

/* Last-5 form badges — the standings table in site.css has no form column. */
.uf-form {
  display: inline-grid;
  place-items: center;
  width: 17px; height: 17px;
  margin-right: 3px;
  border-radius: 50%;
  color: #fff;
  font-size: 10px;
  font-weight: 700;
}

.st-table td:last-child { white-space: nowrap }

.uf-form.f-W { background: var(--primary-dark) }
.uf-form.f-D { background: var(--text-3) }
.uf-form.f-L { background: var(--red-dark) }

.uf-center { align-self: center }

/* ── account / language popup (header) ── */

.acct { margin-left: 10px; flex-shrink: 0 }
/* > .acct-btn: outranks site.css's .nav-drop-d > summary flex rule.
   Signed out it is a 40px circle; signed in it grows into a greeting pill
   (initial + "Hi, name" + caret) and the menu drops the Log in button. */
.nav-drop-d > .acct-btn {
  height: 40px; min-width: 40px; padding: 0; margin: 0; box-sizing: border-box;
  display: flex; align-items: center; gap: 0; line-height: 1;
  border-radius: 999px;
  background: var(--primary-light);
  border: 1px solid transparent;
  color: var(--primary-dark);
  cursor: pointer;
  list-style: none;
  transition: background .18s, color .18s, box-shadow .18s, border-color .18s;
}
.acct-btn::-webkit-details-marker { display: none }
.acct-face {
  width: 38px; height: 38px; flex-shrink: 0;
  display: grid; place-items: center; border-radius: 50%;
}
.acct-face svg { width: 22px; height: 22px; display: block }
.acct-face i { display: none; font-family: 'Archivo', sans-serif; font-style: normal; font-size: 16px; font-weight: 800; letter-spacing: .02em; color: #fff }
.acct-hi, .acct-btn > .acct-caret { display: none }
.acct-btn:hover,
.nav-drop-d[open] > .acct-btn { background: var(--primary); color: #fff; box-shadow: 0 0 0 4px var(--primary-light) }
.acct-btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px }

.acct.in .acct-btn { padding-right: 14px; gap: 8px; color: var(--text) }
.acct.in .acct-face { background: var(--primary); box-shadow: 0 1px 6px rgba(0, 158, 79, .35) }
.acct.in .acct-face svg { display: none }
.acct.in .acct-face i { display: block }
.acct.in .acct-hi { display: block; max-width: 160px; font-size: 14px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
.acct.in .acct-btn > .acct-caret { display: block; margin-left: 2px }
.acct.in .acct-btn:hover,
.acct.in .nav-drop-d[open] > .acct-btn { background: var(--primary-light); color: var(--text); box-shadow: 0 0 0 4px rgba(0, 158, 79, .12) }
.acct.in .nav-drop-d[open] .acct-btn > .acct-caret { transform: rotate(180deg) }
.acct.in .acct-title { display: none }

.acct-menu { width: 300px; padding: 20px }
.acct-title { margin: 0 0 14px; font-size: 15px; font-weight: 700; color: var(--text) }

.acct-login:not([hidden]) {
  display: block; padding: 11px; border-radius: 999px;
  background: var(--primary); color: #fff;
  font-size: 14px; font-weight: 700; text-align: center; text-decoration: none;
}
.acct-login:hover { background: var(--primary-dark); color: #fff }

.acct-user:not([hidden]) { display: flex; flex-direction: column; margin: -6px 0 }
.acct-item {
  display: flex; align-items: center; gap: 14px;
  padding: 9px 0; background: none; border: 0; cursor: pointer;
  font: inherit; font-size: 15px; color: var(--text); text-decoration: none; text-align: left;
}
.acct-item svg { width: 20px; height: 20px; flex-shrink: 0; color: var(--text-2) }
.acct-item:hover { color: var(--primary) }
.acct-item:hover svg { color: var(--primary) }
.acct-out { margin-top: 6px; padding-top: 14px; border-top: 1px solid var(--border) }

.acct-caret {
  margin-left: auto; width: 0; height: 0;
  border-left: 4px solid transparent; border-right: 4px solid transparent; border-top: 5px solid currentColor;
  transition: transform .18s;
}
/* Language row — the header's segmented pair, moved in here when the account
   pill is live so the bar does not carry two pills side by side. */
.acct-lang {
  display: flex; align-items: center; justify-content: space-between;
  margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--border);
  font-size: 15px; color: var(--text);
}
.acct-lang .lang-pill { margin-left: 0 }
@media (prefers-reduced-motion: reduce) { .acct-btn, .acct-caret { transition: none } }


.uf-social { display: flex; gap: 14px; list-style: none; margin: 0; padding: 0 }
.uf-social a { color: var(--text-2); text-decoration: none }

/* ── posts (index / archive / single) ── */

.uf-post-list { display: grid; gap: 16px }

.uf-post-card {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 20px;
}

.uf-post-card h2 { font-size: 19px; margin-bottom: 6px }
.uf-post-card h2 a { color: var(--text); text-decoration: none }
.uf-post-date { color: var(--text-3); font-size: 13px }

.uf-entry { max-width: 720px; margin: 0 auto; padding: 40px 24px }
.uf-entry-title { font-family: 'Archivo', sans-serif; font-weight: 800; font-size: 30px; margin-bottom: 8px }
.uf-entry-content { margin-top: 28px; font-size: 16px; line-height: 1.75; color: var(--text-1);
  /* Editor content can hold a bare URL as link text (production's Terms page
     does); unbreakable, it pushed a 390px phone 32px sideways. Only breaks
     where a line would otherwise overflow. */
  overflow-wrap: anywhere }
/* Body links: brand color + weight instead of the browser's blue underline;
   the underline returns on hover as the affordance. */
.uf-entry-content a { color: var(--primary-dark, #007A3D); font-weight: 600; text-decoration: none }
.uf-entry-content a:hover { text-decoration: underline }

/* reading rhythm: headings get extra air above, lists breathe */
.uf-entry-content h2 { font-size: 24px; line-height: 1.25; margin-top: 36px }
.uf-entry-content h3 { font-size: 19px; line-height: 1.3; margin-top: 28px }
.uf-entry-content li + li { margin-top: 8px }

/* in-article affiliate CTA — markup ships inside post content (.ma-cta) */
.ma-cta { margin-top: 28px }
.ma-cta-inner {
  display: flex;
  align-items: center;
  gap: 28px;
  padding: 28px 32px;
  background: linear-gradient(120deg, #07452A, #0B6B3D);
  border-radius: var(--radius-lg);
  color: #fff;
}
.ma-cta-text { flex: 1; font-size: 16px; line-height: 1.6 }
.ma-cta-text strong { display: block; font-size: 19px; margin-bottom: 6px }
.uf-entry-content a.ma-cta-btn {
  flex-shrink: 0;
  padding: 14px 30px;
  background: #E9A62A;
  border-radius: 10px;
  color: #fff;
  font-size: 16px;
  font-weight: 700;
  text-decoration: none;
}
.uf-entry-content a.ma-cta-btn:hover { filter: brightness(1.08); text-decoration: none }
@media (max-width: 560px) {
  .ma-cta-inner { flex-direction: column; align-items: flex-start; gap: 16px }
}
.uf-entry-content > * + * { margin-top: 16px }
/* Article images come from the old editor with no width/height attributes and
   sources up to 1920px, so with only a border-radius here they rendered at
   natural size and blew the column open.
   width/height:auto keeps a small image small rather than stretching it, and
   the two maxima together preserve the aspect ratio. max-height matters as much
   as max-width: a square club crest constrained only by width becomes a full
   screen of logo on the way down the article. */
.uf-entry-content img {
  max-width: 100%;
  max-height: 520px;
  width: auto;
  height: auto;
  border-radius: 8px;
}

@media (max-width: 900px) {
  .uf-split, .uf-split-even { grid-template-columns: minmax(0, 1fr) }
  #sec-matches { margin-top: -32px }
}


/* ── match row: teams centred, no verdict column ── */

.uf-card .ml-row { gap: 12px }

/* The side blocks are pinned to fixed widths, otherwise the "pick" tag widens
   whichever odds column is active and pushes the flexible middle off-centre —
   the VS then lands somewhere different on every row. */
.uf-card .ml-time-block { flex: 0 0 84px; width: 84px }
.uf-card .ml-odds-block { flex: 0 0 228px; width: 228px; display: flex; gap: 6px }

/* Chevron shrinks to the glyph so the prediction block sits flush at the row's
   end instead of floating 68px short of it. */
.uf-card .ml-row > .ml-chevron { flex: 0 0 auto; text-align: right }
.uf-card .ml-odds-col { flex: 1 1 0; min-width: 0; padding: 8px 4px }
.uf-card .ml-odds-lbl { display: flex; align-items: center; justify-content: center; gap: 4px }

/* Equal side columns then park the VS pill on the row's centre line, so it lands
   in the same place regardless of how long the team names are. */
.uf-card .ml-teams-block {
  flex: 1;
  display: grid;
  /* minmax(0, 1fr), not 1fr: a plain fr track floors at min-content, so a long
     name like "Nottingham Forest" widens its own side and shoves the pill off
     the centre line. */
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: 10px;
}

.uf-card .ml-team-pair { min-width: 0 }
/* Long names wrap to two lines instead of stretching the row — site.css says
   nowrap; the clamp keeps a runaway name from making a three-line row. */
.uf-card .ml-team-pair span {
  white-space: normal;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  line-height: 1.25;
}
.uf-card .ml-team-pair:first-child { justify-content: flex-end; text-align: right }
.uf-card .ml-team-pair:last-child { justify-content: flex-start; text-align: left }

/* ── standings rail ──
   Sidebar card matching the reference: league pager on top, compact table below. */

/* Both homepage columns are sticky: sticky is inert on whichever column is
   taller (it defines the row height), so only the shorter side follows the
   scroll — sidebar on busy matchdays, match list on quiet ones. Harmless in
   the stacked mobile layout, where each grid row is its own height. */
/* 80px = 64px sticky header + 16px breathing room, so a pinned column's top
   isn't hidden under the header. */
.uf-side { display: grid; gap: 16px; align-content: start; min-width: 0; position: sticky; top: 80px }

/* ponytail: Top leagues card temporarily hidden — delete this rule to restore. */
.uf-side > .uf-card:not(.uf-standings) { display: none }

/* league badge beside the group header name */
.uf-group-name { display: inline-flex; align-items: center; gap: 9px }
.uf-group-badge { width: 22px; height: 22px; object-fit: contain }
.uf-group .ml-chevron svg { display: block; width: 12px; height: 12px }
/* triangle points down when open, flips up when collapsed (base icon points right) */
.uf-group[aria-expanded="false"] .ml-chevron { transform: rotate(-90deg) }
#sec-matches .uf-main { position: sticky; top: 80px }
.uf-side > * { min-width: 0 }

.uf-pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 12px 14px;
}

.uf-dots { display: flex; align-items: center; gap: 6px }

.uf-dot {
  width: 7px; height: 7px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--bg-3);
  cursor: pointer;
  transition: background .18s;
}

.uf-dot.on { background: var(--primary-dark) }
.uf-dot:hover { background: var(--text-3) }

#standings-head .uf-standings-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 4px 18px 14px;
}

.uf-standings-name {
  font-family: 'Archivo', sans-serif;
  font-weight: 700;
  font-size: 16px;
  color: var(--text);
}

.uf-standings-country { font-size: 13px; color: var(--text-3) }

.uf-standings-badge {
  width: 32px; height: 32px;
  object-fit: contain;
  padding: 6px;
  border: 1px solid var(--border);
  border-radius: 50%;
  box-sizing: content-box;
}

.uf-mini-table { font-size: 13px }
.uf-mini-table thead th { padding: 8px 6px; background: transparent }
/* Fixed layout takes column widths from the first row. Sizing the numeric
   columns and leaving the team column auto keeps the total at exactly 100% —
   width:100% on the team column would add to the others, not absorb them. */
.uf-mini-table thead th:nth-child(1) { width: 26px }
.uf-mini-table thead th:nth-child(2) { width: auto }
.uf-mini-table thead th:nth-child(3) { width: 34px }
.uf-mini-table thead th:nth-child(4) { width: 42px }
.uf-mini-table thead th:nth-child(5) { width: 40px }
.uf-mini-table tbody td { padding: 9px 6px; border-bottom: 0 }

/* Full table (match page): ten columns, so every one but the name is a narrow
   number. These tie with the :nth-child rules above on specificity — they have
   to stay below them to win. */
.uf-mini-table.st-table-full thead th { width: 34px }
.uf-mini-table.st-table-full thead th:nth-child(1) { width: 26px }
.uf-mini-table.st-table-full thead th:nth-child(2) { width: auto }
/* Below this the name column would be crushed instead of the table scrolling. */
.uf-mini-table.st-table-full { min-width: 520px }
.st-table-wrap:has(.st-table-full) { overflow-x: auto }
.uf-mini-table tbody tr:hover { background: var(--bg-2) }
.uf-mini-table .st-pos { width: 22px; text-align: center; color: var(--text-3) }
.uf-mini-table .st-team-cell { gap: 8px; text-align: left }
.uf-mini-table .st-name { font-weight: 500; color: var(--text) }
.uf-mini-table .st-pts { color: var(--text) }
.uf-mini-table td:first-child { padding-left: 12px }
.uf-mini-table td:last-child { padding-right: 14px }

/* Standings skeleton: the table's own shape while /api/standings loads, in place
   of a "Loading table..." sentence. Rows are the real row's height (9px padding
   around the 20px qualify bar) with the real 18px crest, so the data lands where
   the grey bars were and the card does not jump. Same shimmer as the news grid. */
.uf-st-sk { padding: 4px 14px 10px 12px }
.uf-st-sk-row { display: flex; align-items: center; gap: 8px; height: 38px }
.uf-st-sk-row i {
  display: block; flex: 0 0 auto; height: 10px; border-radius: 5px;
  background: linear-gradient(90deg, var(--bg-2) 25%, var(--border) 37%, var(--bg-2) 63%);
  background-size: 400% 100%;
  animation: np-shimmer 1.2s linear infinite;
}
.uf-st-sk-row .sk-pos { width: 12px; margin: 0 7px 0 5px }
.uf-st-sk-row .sk-crest { width: 18px; height: 18px; border-radius: 50% }
.uf-st-sk-row .sk-name { width: var(--w, 60%); max-width: 190px }
.uf-st-sk-row .sk-pts { width: 22px; margin-left: auto }
/* The sentence stays for screen readers; sighted users get the shape. */
.uf-st-sk-label {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* Qualification zones - supplementary to the position number, never the only cue. */
.st-qualify-bar { width: 3px; height: 20px; border-radius: 2px; flex-shrink: 0 }
.st-qualify-bar.ucl { background: var(--primary) }
.st-qualify-bar.uel { background: #2F6FED }
.st-qualify-bar.grey { background: transparent }

/* Segmented control: a view switcher, not navigation. Three equal segments on a
   grey track keep all three labels visible at 290px. */
.uf-seg {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2px;
  margin: 0 14px 14px;
  padding: 3px;
  background: var(--bg-2);
  border-radius: 10px;
}

.uf-seg-btn {
  padding: 7px 4px;
  border: 0;
  border-radius: 8px;
  background: none;
  color: var(--text-3);
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: background .18s, color .18s;
}

.uf-seg-btn:hover { color: var(--text) }

.uf-seg-btn.on {
  background: var(--bg);
  color: var(--primary-dark);
  box-shadow: 0 1px 3px rgba(0, 0, 0, .08);
}

@media (prefers-reduced-motion: reduce) {
  .uf-seg-btn { transition: none }
}

.uf-standings .ps-list { margin-top: 0; padding: 0 12px 12px; gap: 6px }
.uf-standings .ps-row { padding: 8px 10px; backdrop-filter: none; background: var(--bg-2); border-color: var(--border) }
.uf-standings .ps-row { min-width: 0 }
.uf-standings .ps-avatar { flex-shrink: 0 }
.uf-standings .ps-name-team { min-width: 0; flex: 1 }
.uf-standings .ps-player-name,
.uf-standings .ps-team-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: block }
.uf-standings .ps-value { flex-shrink: 0 }

/* Same reason on the table: a long club name shouldn't stretch the card. */
.uf-mini-table { table-layout: fixed; width: 100% }
.uf-mini-table .st-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
.uf-mini-table .st-team-cell { min-width: 0 }
.uf-standings .uf-empty { padding: 8px 18px 20px }

/* ── trending news ── */

/* The design system styles .tn-feat-title / .tn-sec-title, but the titles are
   links here — without this they fall back to browser-default blue underline. */
.tn-feat-title a,
.tn-sec-title a,
.tn-sec-row,
.tn-sec-row:hover { color: inherit; text-decoration: none }

.tn-feat-title a:hover { color: var(--primary-dark) }

.tn-featured, .tn-secondary {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  padding: 14px;
}

.tn-featured { gap: 0 }
.tn-feat-img { border-radius: var(--radius); overflow: hidden }
.tn-feat-img img { width: 100%; aspect-ratio: 16 / 10; object-fit: cover }
.tn-feat-content { padding: 16px 4px 8px }
.tn-feat-title { margin-bottom: 10px }
.tn-feat-excerpt { margin-bottom: 20px }
.tn-featured .hero-cta { align-self: center }

.tn-secondary { gap: 0; justify-content: flex-start }
.tn-sec-row { padding: 10px 0; align-items: flex-start; gap: 14px }
.tn-sec-thumb { flex-shrink: 0; width: 150px; border-radius: 10px; overflow: hidden }
.tn-sec-thumb img { width: 100%; aspect-ratio: 16 / 11; object-fit: cover; display: block }
.tn-sec-body { display: flex; flex-direction: column; gap: 4px }
.tn-secondary .hero-cta { align-self: center; margin-top: 14px }

@media (max-width: 560px) {
  .tn-sec-thumb { width: 108px }
}

/* ── trending news v2 — featured story + "Latest News" card grid.
   The .tn- rules above serve the old layout, kept commented out in
   front-page.php for restore. ── */

/* The whole news section as one big card, same surface as the rest of the site. */
.tn2-wrap {
  padding: 24px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}
.tn2-featured {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  gap: 32px;
  align-items: center;
  margin-bottom: 36px;
}
.tn2-feat-img { display: block; border-radius: var(--radius); overflow: hidden }
/* height:auto beats the width/height attrs WP prints, letting aspect-ratio rule */
.tn2-feat-img img { display: block; width: 100%; height: auto; aspect-ratio: 16 / 10; object-fit: cover }

.tn2-meta { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; color: var(--text-3); font-size: 13px }
.tn2-dot { font-size: 10px }

.tn2-feat-title { margin: 10px 0 12px; font-size: clamp(24px, 2.6vw, 34px); line-height: 1.15 }
.tn2-feat-title a, .tn2-card-title a { color: var(--text-1); text-decoration: none }
.tn2-feat-title a:hover, .tn2-card-title a:hover { color: var(--primary-dark) }

.tn2-excerpt { margin: 0 0 14px; color: var(--text-2); font-size: 15px; line-height: 1.6 }
.tn2-card-excerpt {
  font-size: 13px;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden;
}

.tn2-foot { display: flex; align-items: center; gap: 6px; color: var(--text-3); font-size: 13px }
.tn2-cat { color: var(--primary-dark); font-weight: 700; text-decoration: none }
.tn2-cat:hover { text-decoration: underline }

.tn2-latest-head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 18px }
.tn2-latest-head .tn-header { margin-bottom: 0 }
.tn2-seeall { color: var(--primary-dark); font-weight: 700; font-size: 14px; text-decoration: none }
.tn2-seeall:hover { text-decoration: underline }

.tn2-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 24px }
.tn2-card { display: flex; flex-direction: column }
/* Ratio + placeholder live on the wrapper, so a post with no featured image
   still holds the same box and the card text stays aligned across the row. */
.tn2-card-img { display: block; aspect-ratio: 4 / 3; background: var(--bg-2); border-radius: var(--radius); overflow: hidden; margin-bottom: 12px }
.tn2-card-img img { display: block; width: 100%; height: 100%; object-fit: cover }
.tn2-card-title { margin: 6px 0 8px; font-size: 17px; line-height: 1.3 }
.tn2-card .tn2-excerpt { margin-bottom: 10px }
.tn2-card .tn2-foot { margin-top: auto }

@media (max-width: 900px) {
  .tn2-featured { grid-template-columns: 1fr; gap: 16px }
  .tn2-grid { grid-template-columns: repeat(2, minmax(0, 1fr)) }
}
@media (max-width: 520px) {
  .tn2-grid { grid-template-columns: minmax(0, 1fr) }
}

/* ── news page (/news/) — trending banner, league tabs, card grid ── */

.np-banner {
  position: relative;
  display: block;
  overflow: hidden;
  aspect-ratio: 21 / 9;
  background: var(--text-1, #111);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  color: #fff;
  text-decoration: none;
  margin-bottom: 24px;
}
.np-banner > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover }
/* Frosted-glass strip across the banner's bottom. The solid rgba is the
   fallback; @supports lightens it once backdrop-filter carries the legibility. */
.np-banner-body {
  position: absolute;
  inset: auto 0 0 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 20px 28px 18px;
  background: rgba(10, 14, 18, .78);
  border-top: 1px solid rgba(255, 255, 255, .18);
}
@supports (backdrop-filter: blur(1px)) {
  /* Darkness comes from brightness() on the backdrop, not a heavy overlay —
     that keeps the translucency that reads as glass. The white top gradient
     is the gloss highlight. */
  .np-banner-body {
    background: linear-gradient(180deg, rgba(255, 255, 255, .09), rgba(255, 255, 255, 0) 45%), rgba(10, 14, 18, .35);
    backdrop-filter: blur(20px) saturate(.85) brightness(.5);
    -webkit-backdrop-filter: blur(20px) saturate(.85) brightness(.5);
  }
}
.np-banner-title { font-family: var(--font-display, inherit); font-size: clamp(20px, 2.6vw, 32px); font-weight: 800; line-height: 1.2; text-shadow: 0 1px 3px rgba(0, 0, 0, .8) }
.np-banner-sub {
  color: rgba(255, 255, 255, .85);
  font-size: 15px;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
}
.np-banner-meta { display: flex; align-items: center; gap: 8px; margin-top: 4px; font-size: 13px; color: rgba(255, 255, 255, .85) }
.np-banner-meta .avatar { border-radius: 50%; }
.np-pills { display: flex; gap: 8px; margin-left: auto }
.np-pill { padding: 4px 12px; border: 1px solid rgba(255, 255, 255, .7); border-radius: 999px; background: rgba(0, 0, 0, .3); font-size: 12px; font-weight: 600 }

.np-toolbar { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-bottom: 22px }
.np-tab {
  padding: 8px 16px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--bg);
  color: var(--text-2);
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
}
.np-tab:hover { border-color: var(--primary-dark); color: var(--primary-dark) }
.np-tab.on { background: var(--primary); border-color: var(--primary); color: #fff }
.np-search { margin-left: auto }
.np-search input {
  padding: 8px 16px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--bg);
  font: inherit;
  font-size: 14px;
  min-width: 200px;
}

/* main + sidebar split */
.np-split { display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: 24px; align-items: start }
/* Same 80px rail offset as .uf-side / .sp-stick — clears the sticky header.
   The stack is ~865px, so it fits a laptop viewport; no bottom-edge trick. */
.np-side { position: sticky; top: 80px }
.np-grid { grid-template-columns: repeat(2, minmax(0, 1fr)) }

/* article cards get card chrome on this page */
.np-main .tn2-card {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.np-main .tn2-card-img { border-radius: 0; margin-bottom: 0 }
.tn2-card-body { display: flex; flex-direction: column; flex: 1; gap: 8px; padding: 14px 16px 16px }
.tn2-card-body .tn2-card-title, .tn2-card-body .tn2-excerpt { margin: 0 }

/* featured story card */
.np-featured {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  overflow: hidden;
  margin-bottom: 24px;
}
.np-feat-img { position: relative; display: block; aspect-ratio: 16 / 7; background: var(--bg-2) }
.np-feat-img img { display: block; width: 100%; height: 100%; object-fit: cover }
.np-feat-badge {
  position: absolute;
  top: 14px;
  left: 14px;
  padding: 5px 14px;
  border-radius: 999px;
  background: var(--primary);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
}
.np-feat-body { display: flex; flex-direction: column; gap: 8px; padding: 16px 20px 20px }
.np-feat-title { font-size: 22px; line-height: 1.25; margin: 0 }
.np-feat-title a { color: var(--text-1); text-decoration: none }
.np-feat-title a:hover { color: var(--primary-dark) }
.np-feat-body .tn2-excerpt { margin: 0 }

/* sidebar widgets */
.np-widget {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  padding: 16px;
}
.np-widget + .np-widget { margin-top: 20px }
.np-widget-title { font-size: 16px; font-weight: 800; margin-bottom: 12px }

.np-trow { display: flex; gap: 10px; padding: 7px 0; color: inherit; text-decoration: none }
.np-trow-thumb { flex: 0 0 84px; aspect-ratio: 16 / 10; border-radius: var(--radius); overflow: hidden; background: var(--bg-2) }
.np-trow-thumb img { display: block; width: 100%; height: 100%; object-fit: cover }
.np-trow-body { display: flex; flex-direction: column; gap: 4px; min-width: 0 }
.np-trow-title {
  font-size: 13px; font-weight: 700; line-height: 1.35;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
}
.np-trow:hover .np-trow-title { color: var(--primary-dark) }
.np-trow-read { font-size: 12px; color: var(--text-3) }

/* today's top match — green card, engine-fed */
.np-topmatch { background: linear-gradient(160deg, #0B5E34, var(--primary)); border: 0; color: #fff }
.np-topmatch .np-widget-title { color: #fff }
.np-topmatch .uf-empty { color: rgba(255, 255, 255, .8) }
.tm-sub { font-size: 13px; color: rgba(255, 255, 255, .8); margin-bottom: 12px }
.tm-teams { display: flex; align-items: center; gap: 8px }
.tm-team { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 6px; font-size: 13px; font-weight: 600; text-align: center; min-width: 0 }
.tm-team img { width: 44px; height: 44px; object-fit: contain }
.tm-vs { font-weight: 800; font-size: 14px }
.tm-btn {
  display: block;
  margin-top: 14px;
  padding: 10px;
  border: 1px solid rgba(255, 255, 255, .4);
  border-radius: 999px;
  background: rgba(255, 255, 255, .14);
  color: #fff;
  font-size: 14px;
  font-weight: 700;
  text-align: center;
  text-decoration: none;
}
.tm-btn:hover { background: rgba(255, 255, 255, .24) }

/* newsletter */
.np-sub-text { font-size: 13px; color: var(--text-2); margin-bottom: 12px }
.np-sub input[type="email"] {
  width: 100%;
  padding: 10px 16px;
  border: 1px solid var(--border);
  border-radius: 999px;
  font: inherit;
  font-size: 14px;
  margin-bottom: 10px;
}
.np-sub button {
  width: 100%;
  padding: 10px;
  border: 0;
  border-radius: 999px;
  background: var(--primary);
  color: #fff;
  font: inherit;
  font-size: 14px;
  font-weight: 700;
  cursor: pointer;
}
.np-sub button:hover { background: var(--primary-dark, #007A3D) }
.np-sub-note { font-size: 12px; color: var(--text-3); text-align: center; margin-top: 10px }
.np-sub-ok { font-size: 14px; font-weight: 600; color: var(--primary-dark, #007A3D) }

/* skeleton cards shown while the ajax filter loads */
.np-sk { display: flex; flex-direction: column; gap: 10px }
.np-sk-img, .np-sk-line {
  background: linear-gradient(90deg, var(--bg-2) 25%, var(--border) 37%, var(--bg-2) 63%);
  background-size: 400% 100%;
  animation: np-shimmer 1.2s linear infinite;
}
.np-sk-img { aspect-ratio: 4 / 3; border-radius: var(--radius) }
.np-sk-line { height: 14px; border-radius: 6px }
.np-sk-line.w40 { width: 40% }
.np-sk-line.w80 { width: 80% }
@keyframes np-shimmer {
  from { background-position: 100% 0 }
  to   { background-position: 0 0 }
}
@media (prefers-reduced-motion: reduce) {
  .np-sk-img, .np-sk-line, .uf-st-sk-row i { animation: none }
}

.np-pager { display: flex; justify-content: center; gap: 6px; margin-top: 28px }
.np-pager .page-numbers {
  padding: 8px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg);
  color: var(--text-2);
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
}
.np-pager .page-numbers.current { background: var(--primary); border-color: var(--primary); color: #fff }
.np-pager .page-numbers:hover:not(.current) { border-color: var(--primary-dark); color: var(--primary-dark) }

@media (max-width: 900px) {
  .np-banner { aspect-ratio: 16 / 10 }
  .np-pills { display: none }
  .np-split { grid-template-columns: minmax(0, 1fr) }
  .np-side { position: static }
  .np-search { margin-left: 0; width: 100% }
  .np-search input { width: 100% }
}
@media (max-width: 520px) {
  .np-grid { grid-template-columns: minmax(0, 1fr) }
}

/* ── page texture ──
   Brand texture behind the whole page. A fixed ::before layer instead of
   background-attachment: fixed, which repaints badly on mobile Safari. */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -1;
  background: var(--bg-2) url(assets/img/page-texture.webp) center / cover no-repeat;
  pointer-events: none;
}

/* ── footer — brand + stats band, link columns, copyright ── */

.ft { background: #fff; border-top: 1px solid var(--border) }
.ft-top { background-color: #fff; background-size: cover; background-position: center; border-bottom: 1px solid var(--border) }
.ft-top-inner {
  max-width: 1200px;
  margin: 0 auto;
  padding: 44px 24px;
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  gap: 40px;
  align-items: center;
}
.ft-brand img { display: block; width: 240px; height: auto }
.ft-desc { margin-top: 14px; max-width: 360px; color: var(--text-2); font-size: 15px; line-height: 1.6 }
.ft-accent { display: block; width: 48px; height: 3px; margin-top: 16px; border-radius: 2px; background: var(--gold, #CFA761) }
.ft-stats { display: grid; grid-template-columns: repeat(3, 1fr); text-align: center }
.ft-stats .stat-col + .stat-col { border-left: 1px solid var(--border) }

.ft-cols {
  max-width: 1200px;
  margin: 0 auto;
  padding: 40px 24px 36px;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 32px;
}
.ft-col-title { font-size: 14px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase }
.ft-col-title::after { content: ''; display: block; width: 32px; height: 3px; margin-top: 8px; border-radius: 2px; background: var(--gold, #CFA761) }
.ft-col ul { list-style: none; margin: 16px 0 0; padding: 0; display: grid; gap: 12px; justify-items: start }
.ft-col a { color: var(--text-2); font-size: 14px; text-decoration: none }
.ft-col a:hover { color: var(--primary-dark) }
/* Rounded chip per network rather than a bare glyph: the squircle gives the
   three rows one silhouette, and the surface is what carries the hover state —
   colouring a hairline glyph green reads as a rendering fault, filling a tile
   reads as a button. --radius on a 36px box is the same 1:3 curve the cards use. */
.ft-soc { display: inline-flex; align-items: center; gap: 10px }
.ft-soc-ic {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  flex-shrink: 0;
  border-radius: var(--radius);
  background: var(--bg-2);
  color: var(--text-2);
  transition: background .18s, color .18s, transform .18s;
}
.ft-soc svg { width: 19px; height: 19px }
.ft-soc:hover .ft-soc-ic,
.ft-soc:focus-visible .ft-soc-ic {
  background: var(--primary);
  color: #fff;
  transform: translateY(-1px);
}
@media (prefers-reduced-motion: reduce) {
  .ft-soc-ic { transition: none }
  .ft-soc:hover .ft-soc-ic { transform: none }
}

.ft .copyright-bar { border-top: 1px solid var(--border) }

@media (max-width: 900px) {
  .ft-top-inner { grid-template-columns: minmax(0, 1fr); gap: 28px }
  .ft-cols { grid-template-columns: repeat(2, minmax(0, 1fr)) }
  .ft-brand img { width: 132px } /* matches the header logo's visual weight */
}
@media (max-width: 520px) {
  .ft-cols { grid-template-columns: minmax(0, 1fr) }
}

/* ── match rows on mobile: three stacked rows — time / teams / prediction ── */
@media (max-width: 640px) {
  .uf-card .ml-row { flex-wrap: wrap; gap: 10px }
  .uf-card .ml-time-block { flex: 1 1 100%; width: auto; display: flex; align-items: baseline; gap: 8px }
  .uf-card .ml-teams-block { flex: 1 1 100% }
  .uf-card .ml-odds-block { flex: 1 1 100%; width: 100% }
  .uf-card .ml-row > .ml-chevron { display: none }
}

/* ── mobile bottom nav ── */

.bn { display: none }

@media (max-width: 900px) {
  .bn {
    position: fixed;
    inset: auto 0 0 0;
    z-index: 90;
    display: grid;
    /* 3 or 4 items depending on UFOOTBALL_AI_LIVE — let the children
       decide the column count rather than hardcoding it. */
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    background: var(--bg);
    border-top: 1px solid var(--border);
    padding-bottom: env(safe-area-inset-bottom);
    box-shadow: 0 -4px 16px rgba(0, 0, 0, .06);
  }
  .bn-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 3px;
    padding: 9px 0 7px;
    color: var(--text-3);
    font-size: 11px;
    font-weight: 600;
    text-decoration: none;
  }
  .bn-item svg { width: 22px; height: 22px }
  .bn-item.on { color: var(--primary-dark, #007A3D) }
  body { padding-bottom: calc(58px + env(safe-area-inset-bottom)) }

  /* homepage view switch — gated on .uf-bn (set by JS) so no-JS still stacks both */
  body.uf-bn:not(.uf-view-leagues) #sec-matches .uf-side { display: none }
  body.uf-bn.uf-view-leagues #sec-matches .uf-main { display: none }
  /* the News tab covers it — the homepage news section is redundant on mobile */
  body.uf-bn #sec-news { display: none }

  /* toolbar: date row, tab row, then the filter full-width on its own row */
  .ml-tabs { flex-wrap: wrap }
  .ml-tabs .uf-filter { flex: 1 1 100%; order: 9 }

  /* footer columns as accordions — titles only until tapped */
  .ft-col-title { cursor: pointer; position: relative }
  .ft-col-title::before {
    content: '';
    position: absolute;
    right: 0;
    top: 4px;
    width: 8px;
    height: 8px;
    border-right: 2px solid var(--text-3);
    border-bottom: 2px solid var(--text-3);
    transform: rotate(45deg);
    transition: transform .18s;
  }
  .ft-col.open .ft-col-title::before { transform: rotate(225deg) }
  .ft-col ul { display: none }
  .ft-col.open ul { display: grid }
  .ft-cols { gap: 20px }
}
@media (prefers-reduced-motion: reduce) {
  .ft-col-title::before { transition: none }
}

/* ── static pages — green hero band + centered content card ── */

.pg-hero { background: linear-gradient(135deg, #07452A, #0B6B3D); color: #fff }
.pg-hero-inner { max-width: 1140px; margin: 0 auto; padding: 40px 20px 36px }
.pg-hero .sp-crumb span:last-child { color: rgba(255, 255, 255, .9) }
.pg-title { font-size: clamp(26px, 3vw, 36px); line-height: 1.15 }

.pg-entry {
  max-width: 900px;
  margin: 0 auto;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  padding: 12px 36px 32px;
}
/* Legacy builder-era pages carry full-size images; cap them so a logo export
   can't fill the viewport. */
.pg-entry img { max-width: 100%; height: auto; max-height: 420px; object-fit: contain }
.pg-entry .uf-entry-content { margin-top: 16px }

/* ── single post — hero, author sidebar, widgets, related ── */

/* The hero band is far wider than a 16:9 featured image, so cover crops top and
   bottom. Anchoring at 25% from the top keeps faces (upper third of most sports
   shots) in frame; the horizontal gradient darkens only the text side. */
.sp-hero {
  position: relative;
  background: #10151a 50% 25% / cover no-repeat;
  background-image: linear-gradient(90deg, rgba(8, 12, 16, .88) 0%, rgba(8, 12, 16, .68) 45%, rgba(8, 12, 16, .28) 100%), var(--sp-bg, none);
  color: #fff;
}
.sp-hero { display: flex; align-items: center; min-height: clamp(340px, 38vw, 480px) }
.sp-hero-inner { width: 100%; max-width: 1140px; margin: 0 auto; padding: 48px 20px }
.sp-crumb { display: flex; gap: 8px; font-size: 13px; color: rgba(255, 255, 255, .7); margin-bottom: 16px }
.sp-crumb a { color: inherit; text-decoration: none }
.sp-crumb a:hover { color: #fff }
.sp-cat-pill {
  display: inline-block;
  padding: 5px 14px;
  border-radius: 999px;
  background: var(--primary);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  text-decoration: none;
  margin-bottom: 14px;
}
.sp-title { max-width: 720px; font-size: clamp(26px, 3.4vw, 40px); line-height: 1.15; margin-bottom: 14px }
.sp-excerpt { max-width: 620px; color: rgba(255, 255, 255, .85); font-size: 15px; line-height: 1.6; margin-bottom: 16px }
.sp-meta { display: flex; align-items: center; gap: 8px; font-size: 13px; color: rgba(255, 255, 255, .85) }
.sp-meta .avatar { border-radius: 50% }

.sp-grid { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 24px; align-items: start }
/* margin-top: 0 overrides the shared 28px rule above — that gap belongs to
   static pages (title → text); here the grid already spaces the card. */
.sp-main .uf-entry-content { margin-top: 0; background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius-lg); box-shadow: var(--shadow); padding: 20px 32px 28px }

/* Sidebar widgets follow the scroll so the rail isn't blank beside a long
   article. The aside stretches to the row; the inner wrapper does the sticking. */
.sp-right { align-self: stretch }
.sp-stick { position: sticky; top: 80px }

.sp-author { display: flex; gap: 12px }
.sp-author .avatar { border-radius: 50%; flex-shrink: 0 }
.sp-author-name { font-weight: 800; margin-bottom: 4px }
.sp-author-bio { font-size: 13px; color: var(--text-2); line-height: 1.5 }

/* numbered rank badge on popular thumbnails */
.sp-num { position: relative }
.sp-num::before {
  content: attr(data-n);
  position: absolute;
  top: 4px;
  left: 4px;
  z-index: 1;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--primary);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* tags left, share right, one row */
.sp-foot { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px 24px; margin-top: 18px }
.sp-tags, .sp-share { display: flex; align-items: center; flex-wrap: wrap; gap: 8px }
.sp-tags-label { font-size: 13px; font-weight: 700; color: var(--text-2) }
.sp-tag {
  padding: 6px 14px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--bg);
  color: var(--text-2);
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
}
.sp-tag:hover { border-color: var(--primary-dark); color: var(--primary-dark) }

/* ── match-analysis posts (Analysis category) ──
   Markup ships inside post content (.match-analysis). Each section renders as
   its own card, so the article's outer card unwraps for these posts. */
.sp-main .uf-entry-content:has(> .match-analysis) { background: none; border: 0; box-shadow: none; padding: 0 }

.match-analysis > * + * { margin-top: 24px }
/* wpautop wraps the section comments in the post body as stray zero-height <p>s.
   The first one makes .ps-card a "+ *", so its 24px margin lands at the top of
   the column and drops the article below the sidebar. Kill it there only. */
.match-analysis > p:first-child + * { margin-top: 0 }

/* prediction summary — dark green hero card */
.ps-card {
  background: linear-gradient(135deg, #07452A, #0B6B3D);
  border-radius: var(--radius-lg);
  padding: 26px 28px;
  color: #fff;
}
.ps-top-label { font-size: 12px; font-weight: 700; letter-spacing: .18em; text-transform: uppercase; color: #CFA761; margin-bottom: 18px }
/* VS on the true centre line; flags sit at the card's outer edges in ringed
   circles, names read inward in caps. */
.ps-teams { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 20px }
.ps-team { display: flex; align-items: center; gap: 16px; min-width: 0 }
.ps-team-away { flex-direction: row-reverse; justify-content: flex-start; text-align: right }
.ps-card .ps-team-logo {
  width: 64px !important;
  height: 64px !important;
  border-radius: 50%;
  object-fit: cover !important;
  box-shadow: 0 0 0 3px rgba(255, 255, 255, .18);
}
/* scoped — site.css owns bare .ps-team-name for the homepage scorers card */
.ps-card .ps-team-name { font-size: 22px; font-weight: 800; color: #fff; text-transform: uppercase; letter-spacing: .02em }
.ps-team-venue { font-size: 12px; color: rgba(255, 255, 255, .65) }
.ps-vs { font-size: 13px; font-weight: 700; letter-spacing: .1em; color: rgba(255, 255, 255, .55) }
.ps-badge {
  display: inline-block;
  margin: 16px 0 4px;
  padding: 6px 14px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .06em;
  background: rgba(255, 255, 255, .16);
}
/* one color per engine tier; the label text carries the meaning, color reinforces */
.ps-badge--blue { background: #2563EB }   /* HIGH CONFIDENCE */
.ps-badge--cyan { background: #0E7490 }   /* LIKELY WIN */
.ps-badge--purple { background: #7C3AED } /* TIGHT MATCH */
.ps-badge--red { background: #DC2626 }    /* UPSET ALERT */
.ps-outcomes { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; margin-top: 16px }
.ps-outcome {
  position: relative;
  padding: 18px 14px 16px;
  text-align: center;
  background: rgba(255, 255, 255, .07);
  border: 1px solid rgba(255, 255, 255, .16);
  border-radius: var(--radius);
}
.ps-outcome.ps-active { border: 2px solid #E9A62A; background: rgba(255, 255, 255, .1) }
.ps-star { position: absolute; top: 8px; left: 12px; color: #E9A62A }
.ps-outcome-name { font-size: 13px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em }
.ps-prob-label { margin-top: 10px; font-size: 10px; font-weight: 600; letter-spacing: .14em; text-transform: uppercase; color: rgba(255, 255, 255, .6) }
.ps-prob-pct { font-family: Archivo, sans-serif; font-size: 30px; font-weight: 800; line-height: 1.2 }
.ps-prob-bar-track { height: 4px; margin: 10px 0 12px; border-radius: 999px; background: rgba(255, 255, 255, .2); overflow: hidden }
.ps-prob-bar-fill { height: 100%; border-radius: 999px; background: rgba(255, 255, 255, .75) }
.ps-active .ps-prob-bar-fill { background: #E9A62A }
.ps-odds { font-size: 13px; font-weight: 700 }
.ps-return { margin-top: 4px; font-size: 11px; color: rgba(255, 255, 255, .6) }
.ps-analysis {
  display: flex;
  align-items: center;
  gap: 20px;
  margin-top: 18px;
  padding: 16px 20px;
  background: rgba(0, 0, 0, .28);
  border-radius: var(--radius);
}
.ps-analysis-body { flex: 1 }
.ps-analysis-title { font-size: 13px; font-weight: 800; text-transform: uppercase; letter-spacing: .08em }
.ps-analysis-text { margin: 6px 0 0; font-size: 14px; color: rgba(255, 255, 255, .85); line-height: 1.6 }
.uf-entry-content a.ps-bet-btn {
  flex-shrink: 0;
  padding: 12px 26px;
  background: #FDF9EE;
  border-radius: 10px;
  color: #07452A;
  font-size: 15px;
  font-weight: 700;
  text-decoration: none;
}
.uf-entry-content a.ps-bet-btn:hover { filter: brightness(.96); text-decoration: none }
.ps-footer { margin-top: 16px; text-align: center; font-size: 11px; letter-spacing: .08em; color: rgba(255, 255, 255, .5) }

/* section cards */
.match-analysis section {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  padding: 22px 26px;
}
/* flag + title on one row, green rule underneath */
.match-analysis section h2 {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 14px;
  padding-bottom: 10px;
  border-bottom: 2px solid var(--primary);
  font-size: 20px;
}
.match-analysis section > p { font-size: 15px }

/* team form stats — bordered table, right column tinted light green */
.ma-stats-list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin: 14px 0 0;
  padding: 0;
  list-style: none;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  /* right half tinted edge-to-edge, so an odd row's empty right cell stays green */
  background: linear-gradient(90deg, #fff 50%, #E6F1EB 50%);
}
.ma-stats-list li { display: flex; align-items: center; gap: 10px; padding: 12px 16px; font-size: 14px }
.ma-stats-list li:nth-child(n+3) { border-top: 1px solid var(--border) }
.ma-stats-list li::before { content: ''; flex-shrink: 0; width: 6px; height: 6px; border-radius: 50%; background: var(--primary) }

/* stat tiles — news.js rebuilds the list items; these override the table look.
   12-col grid gives the 4-then-3 rhythm from the reference. */
.ma-stats-list.ma-tiles {
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: 14px;
  border: 0;
  border-radius: 0;
  overflow: visible;
  background: none;
}
.ma-tiles li {
  grid-column: span 3;
  gap: 12px;
  padding: 14px 16px 12px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-bottom: 3px solid var(--primary);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.ma-tiles li:nth-child(n+3) { border-top: 1px solid var(--border) }
.ma-tiles li::before { display: none }
.ma-tile-ic {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 10px;
  background: #E6F1EB;
  color: var(--primary-dark, #007A3D);
}
.ma-tile-ic svg { width: 24px; height: 24px }
.ma-tile-body { display: flex; flex-direction: column; min-width: 0 }
.ma-tile-label { font-size: 12px; font-weight: 600; color: var(--text-2) }
.ma-tile-num { font-family: Archivo, sans-serif; font-size: 22px; font-weight: 800; line-height: 1.2 }
.ma-tile-unit { font-size: 12px; color: var(--text-3) }

@media (max-width: 900px) {
  .ma-tiles li { grid-column: span 6 }
}
@media (max-width: 460px) {
  .ma-tiles li { grid-column: span 12 }
}

/* W/D/L badges — letter + color, never color alone */
.ma-pill-W, .ma-pill-D, .ma-pill-L,
.ma-badge-W, .ma-badge-D, .ma-badge-L {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: 12px;
  font-weight: 700;
}
.ma-pill-W, .ma-badge-W { background: var(--primary) }
.ma-pill-D, .ma-badge-D { background: #E9A62A }
.ma-pill-L, .ma-badge-L { background: #DC2626 }
.ma-pill-W, .ma-pill-D, .ma-pill-L { padding: 5px 14px; border-radius: 999px }
.ma-badge-W, .ma-badge-D, .ma-badge-L { width: 26px; height: 26px; border-radius: 50% }
.ma-form-badges { display: inline-flex; flex-wrap: wrap; gap: 6px; vertical-align: middle }
.ma-results-block, .ma-venue-form { display: flex; align-items: center; gap: 14px; margin-top: 16px; padding: 12px 16px; background: #F4FAF7; border: 1px solid var(--border); border-radius: var(--radius) }
.ma-results-label, .ma-venue-label, .ma-form-label { font-size: 11px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--text-3) }

/* head-to-head */
/* the form cards duplicate each team's Form and Insights section — hidden until the post generator stops emitting them */
.ma-h2h-cards { display: none }
.ma-h2h-card { border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden }
.ma-h2h-card-header { display: flex; align-items: center; gap: 8px; padding: 10px 14px; background: var(--primary-dark, #007A3D); color: #fff; font-size: 14px; font-weight: 700; line-height: 1 }
/* flex gap owns the spacing; the inline margin/vertical-align nudge the flag off-centre */
.ma-h2h-card-header img { display: block; margin: 0 !important; vertical-align: unset !important }
/* wpautop inserts a <br> between flag and name (separate lines in the stored
   markup); as a flex item it wrecks the vertical centring */
.ma-h2h-card-header br, .match-analysis section h2 br { display: none }
.ma-form-row { display: flex; align-items: center; gap: 12px; padding: 12px 14px }
.ma-h2h-results-header { margin-top: 16px; padding: 10px 14px; background: #07452A; border-radius: var(--radius) var(--radius) 0 0; color: #fff; font-size: 14px; font-weight: 700 }
.ma-h2h-table { width: 100%; margin: 0; border-collapse: collapse; font-size: 13px }
.ma-h2h-table th { padding: 10px 14px; background: var(--bg-2); font-size: 11px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--text-3); text-align: left }
.ma-h2h-table td { padding: 10px 14px; border-bottom: 1px solid var(--border) }
/* site.css sets body img { display: block }, which stacks the flag above the name */
.ma-h2h-team img { display: inline-block }
.ma-h2h-table .ma-score { display: inline-block; min-width: 44px; padding: 3px 10px; background: #E6F1EB; border-radius: 999px; font-family: Archivo, sans-serif; font-weight: 700; text-align: center }

/* our prediction — the verdict card, echoing the prediction hero */
.ma-tip-box {
  margin-top: 16px;
  padding: 20px 24px;
  background: linear-gradient(135deg, #07452A, #0B6B3D);
  border-radius: var(--radius);
  color: #fff;
}
.ma-tip-star { display: none } /* raw asterisk glyph from the stored markup */
.ma-tip-body strong { display: block; margin-bottom: 8px; font-size: 16px; color: #F5CE6E }
.ma-tip-body p { margin: 0; font-size: 14px; line-height: 1.65; color: rgba(255, 255, 255, .88) }

/* match details — three fact tiles */
.ma-match-details ul { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; margin: 14px 0 0; padding: 0; list-style: none }
.ma-match-details li { padding: 12px 16px; background: var(--bg-2); border-radius: var(--radius); font-size: 15px }
.ma-match-details li strong { display: block; margin-bottom: 4px; font-size: 11px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--text-3) }

@media (max-width: 640px) {
  .ps-outcomes { grid-template-columns: minmax(0, 1fr) }
  .ps-analysis { flex-direction: column; align-items: flex-start; gap: 14px }
  .ma-stats-list { grid-template-columns: minmax(0, 1fr) }
  .ma-h2h-cards { grid-template-columns: minmax(0, 1fr) }
  .ma-match-details ul { grid-template-columns: minmax(0, 1fr) }
  .ps-teams { grid-template-columns: minmax(0, 1fr); justify-items: start }
  .ps-team-away { flex-direction: row; justify-content: flex-start; text-align: left }
  .ps-vs { text-align: center }
}

/* circular brand share buttons */
.sp-soc {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  color: #fff;
}
.sp-soc svg { width: 18px; height: 18px; fill: currentColor }
.sp-soc:hover { filter: brightness(1.12) }
.sp-soc-fb { background: #4267B2 }
.sp-soc-x { background: #000 }
.sp-soc-tg { background: #29A9EA }
.sp-soc-wa { background: #25D366 }

.sp-related { margin-top: 36px }

@media (max-width: 800px) {
  .sp-grid { grid-template-columns: minmax(0, 1fr) }
}

/* ── hero banner ──
   The shipped banner is a 5.3:1 strip, not the 1.6:1 photo site.css was built
   for. Its rules (background-size:auto + scale(1.12), a 560px floor) would crop
   the strip down to the empty middle of the pitch and lose the players at both
   ends, so the sizing is redefined here. */

.hero {
  min-height: clamp(230px, 21vw, 440px);
  padding-bottom: 0;
}

.hero::before {
  background-size: cover;
  background-position: center;
  transform: none;
}

/* The banner's centre is dark green; site.css sets the title to #000000, which
   is unreadable on it. White clears AA comfortably, and the shadow keeps it
   legible if a lighter image is swapped in via the Customizer. */
.hero-title,
.hero-sub {
  color: #fff;
  text-shadow: 0 2px 12px rgba(0, 0, 0, .55);
}

.hero-title { margin-bottom: 14px }
.hero-sub { margin-bottom: 0 }

@media (max-width: 700px) {
  /* Narrow viewports crop a wide strip hard, so let it sit shorter still. */
  .hero { min-height: 190px }
  .hero-title { font-size: 24px }
}

/* Rows became links to the match page; site.css styles .ml-row as a div, so the
   default anchor colour and underline have to be cleared. */
a.ml-row { text-decoration: none; color: inherit }
a.ml-row:hover .ml-chevron { color: var(--primary-dark) }

/* ══ match page (/match/{id}/) ══════════════════════════════════
   Shell renders server-side, data fills in from assets/js/match.js. */

/* Stadium plate under a green tint: floodlights top-left and top-right, blurred
   crowd, and a deliberately dark centre the score sits in. */
.mp-hero {
  position: relative;
  overflow: hidden;
  background:
    /* Three layers, first painted on top:
       1. the brand green, now translucent — it tints the photo instead of
          replacing it, so the hero stays green-branded but keeps the stadium;
       2. the photo. 50% 34%, not centre: it is 3:1 but the hero band is far
          wider than tall, so `cover` keeps only a slice, and dead centre lands
          on the empty stands rather than the floodlights;
       3. the same green at full opacity, as the colour underneath — it shows on
          ultra-wide viewports where `cover` runs out, and stands in on a 404. */
    linear-gradient(135deg, rgba(10, 31, 20, .82) 0%, rgba(15, 46, 28, .68) 55%, rgba(7, 26, 16, .86) 100%),
    url(assets/img/match-hero.webp) 50% 34% / cover no-repeat,
    linear-gradient(135deg, #0a1f14 0%, #0f2e1c 55%, #071a10 100%);
  color: #fff;
}

/* Vignette pinned to the middle, so the scoreline keeps its dark pocket while
   the tinted floodlights stay bright at the corners. */
.mp-hero::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(ellipse 60% 90% at 50% 50%, rgba(4, 20, 12, .55) 0%, rgba(4, 20, 12, 0) 70%);
}

/* Content clears the vignette. */
.mp-hero > * { position: relative; z-index: 1 }

.mp-hero-inner {
  max-width: 1180px;
  margin: 0 auto;
  padding: 26px 20px 30px;
  text-align: center;
}

.mp-comp {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 5px 14px; margin-bottom: 22px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .12);
  font-size: 12px; font-weight: 600;
}

.mp-comp-badge { width: 20px; height: 20px; object-fit: contain }

.mp-score {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: 20px;
}

.mp-team { display: flex; align-items: center; gap: 14px; min-width: 0 }
.mp-team-home { justify-content: flex-end }
.mp-team-away { justify-content: flex-start }
.mp-team img { width: 48px; height: 48px; object-fit: contain }

.mp-team-name {
  font-family: 'Archivo', sans-serif;
  font-size: 22px; font-weight: 700;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.mp-figure {
  font-family: 'Archivo', sans-serif;
  font-size: 34px; font-weight: 800;
  letter-spacing: .02em;
  white-space: nowrap;
}

.mp-status { margin-top: 12px; font-size: 12px; color: rgba(255, 255, 255, .72) }
.mp-status .uf-live { color: #fff }
.mp-hero-empty, .mp-loading { grid-column: 1 / -1; color: rgba(255, 255, 255, .8) }
.mp-hero-empty strong { color: #fff }

/* The band reserves the scoreline's height while it is empty, so the whole page
   below it does not jump down the moment the teams arrive. 48px crest + the
   22px name line, which is what .mp-score resolves to once filled. */
.mp-score[aria-busy="true"] { min-height: 48px }
.mp-score:not([aria-busy="true"]) { animation: uf-rise .4s ease }
.mp-comp:empty { visibility: hidden }
@media (prefers-reduced-motion: reduce) {
  .mp-score:not([aria-busy="true"]) { animation: none }
}

/* ── loading state, match page ──
   Left column: one mascot, no cards. Right column: skeletons in the real row
   geometry. The two differ because the rail's contents are known up front and
   the main column's are not — see the notes in match.php. */
.mp-main.is-loading > .mp-block { display: none }
.mp-main:not(.is-loading) > .mp-main-load { display: none }
.mp-main-load { padding: 40px 0 }

/* Only the values shimmer. The rows around them are the real .mp-info-row and
   .mp-prob-row markup drawn by paintShell(), so the card reserves its true
   height with no measured pixel value to keep in sync — add a row to either
   card and the reservation follows automatically. */
.mp-sk-chip {
  display: inline-block;
  border-radius: 6px;
  background: linear-gradient(90deg, var(--bg-2) 25%, var(--border) 37%, var(--bg-2) 63%);
  background-size: 400% 100%;
  animation: np-shimmer 1.2s linear infinite;
}
.mp-sk-chip.is-val   { width: 92px; height: 15px; vertical-align: -2px }
.mp-sk-chip.is-sub   { width: 60px; height: 10px }
.mp-sk-chip.is-team  { width: 76px; height: 13px }
.mp-sk-chip.is-pct   { width: 30px; height: 13px }
.mp-sk-chip.is-num   { width: 18px; height: 12px }
/* Matches the date/kick-off line on an upcoming card, which sets that card's
   height — 15px here left the strip 3px short of the fixtures. */
.mp-sk-chip.is-when  { width: 150px; height: 18px }
.mp-sk-chip.is-crest { width: 18px; height: 18px; border-radius: 50% }
/* The upcoming card's crests render at 52px. */
.mp-sk-chip.is-badge { width: 52px; height: 52px; border-radius: 50% }

/* A skeleton upcoming card is the real .mp-up-card with chips inside, so it
   holds the exact height of the fixtures that replace it. Not a link, so the
   pointer and hover lift are taken back off. */
.mp-up-card.is-loading { cursor: default; pointer-events: none }
.mp-up-card.is-loading:hover { transform: none; box-shadow: var(--shadow) }
.mp-up-card.is-loading .mp-up-vs { opacity: .35 }

/* Stands in for U-Bao's banner. Height matches .mp-mascot as rendered, so the
   card does not grow when the pick lands. */
.mp-sk-mascot {
  height: 102px;
  margin-bottom: 9px;
  border-radius: var(--radius);
  background: linear-gradient(90deg, var(--bg-2) 25%, var(--border) 37%, var(--bg-2) 63%);
  background-size: 400% 100%;
  animation: np-shimmer 1.2s linear infinite;
}

/* The bar track is already drawn by .mp-prob-bar; while loading it simply has no
   fill inside, which reads as an empty track rather than a broken one. */
@media (prefers-reduced-motion: reduce) {
  .mp-sk-chip, .mp-sk-mascot { animation: none }
}

.mp-body { padding-top: 22px }
/* The homepage split is 30/70 with the rail first; here the main column leads,
   so the ratio is redeclared rather than reusing the sidebar proportions. */
.mp-split { margin-top: 16px; grid-template-columns: 70fr 30fr }
.mp-main, .mp-side { display: grid; gap: 16px; align-content: start; min-width: 0 }
/* sticky rides below the 64px fixed header; only engages while the side
   column is shorter than the main one (row height = taller column) */
.mp-split .mp-side { position: sticky; top: 80px }
.mp-main > *, .mp-side > * { min-width: 0 }
.mp-block > div { padding: 0 18px 18px }
.mp-inline-empty { padding: 0 }

/* Match page runs one notch larger than the homepage lists: OneFootball's match
   view sets section titles at 20px and row text at 16px, and beside it our 15/13
   read as fine print. Scoped to .mp-block so the homepage keeps its density. */
.mp-block > .uf-card-title { font-size: 18px }
.mp-block .uf-mini-table { font-size: 14px }

/* who will win */
.mp-prob { display: grid; gap: 10px }
.mp-prob-row { display: grid; grid-template-columns: 1fr 88px 40px; align-items: center; gap: 10px; font-size: 15px }
.mp-prob-label { display: flex; align-items: center; gap: 6px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
.mp-prob-bar { height: 6px; border-radius: 999px; background: var(--bg-2); overflow: hidden }
.mp-prob-bar > span { display: block; height: 100%; background: var(--border) }
.mp-prob-row.is-pick .mp-prob-bar > span { background: var(--primary-dark) }
.mp-prob-row.is-pick .mp-prob-val { color: var(--primary-dark); font-weight: 700 }
.mp-prob-val { text-align: right; font-weight: 600; font-variant-numeric: tabular-nums }

.mp-badge {
  display: inline-block; margin: 14px 0 0;
  padding: 4px 10px; border-radius: 6px;
  background: var(--primary-light); color: var(--primary-dark);
  font-size: 12px; font-weight: 700; text-transform: uppercase;
}

.mp-note { margin: 12px 0 0; color: var(--text-3); font-size: 12px; line-height: 1.5 }

/* U-Bao's Pick — the prediction card doubles as the mascot's one on-page
   appearance. The mascot sits in normal flow at the top of the card body, not
   as an absolute sticker: an overlay doesn't add height, so it ended up lying
   across the probability rows and clipping the percentages. */
.mp-pick-card { border-color: var(--primary-light) }

/* The banner carries the tint, not the whole card — a gradient behind the bars
   and the note washed out the one number that matters.
   The band is sized by its TEXT, not by the mascot: the 34px top margin is the
   room U-Bao's head grows into, and the matching -34px on the image keeps that
   head out of the flex line's height. Shrinking the green while the figure
   stays full-size is what makes him stand in front of the band rather than
   inside it. Nothing leaves the card, so no risk to the title or the bars. */
.mp-mascot {
  display: flex; align-items: flex-end; gap: 10px;
  margin: 34px 0 16px;
  padding: 0 12px;
  border-radius: 12px;
  background: linear-gradient(160deg, var(--primary-light) 0%, rgba(0, 158, 79, .06) 100%);
}

/* Bottom-aligned and flush to the band's lower edge, so he stands ON it. The
   shadow is cast down-left onto the green — that contact shadow is most of the
   3D read; without it he looks pasted on. */
.mp-mascot-img {
  display: block;
  flex: 0 0 104px; width: 104px; height: auto;
  margin: -34px 0 -1px;
  filter: drop-shadow(0 6px 9px rgba(0, 0, 0, .2));
}

.mp-mascot-say {
  flex: 1; min-width: 0;
  padding: 12px 0 14px;
  font-size: 13px; line-height: 1.4;
}

.mp-mascot-say span { display: block }

.mp-mascot-label {
  color: var(--text-3);
  font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
}

/* The team is the verdict, so it's the hero. Its probability sits one row down
   in the bars — printing it here too just doubled the same number. */
.mp-mascot-team {
  margin-top: 1px;
  font-family: 'Archivo', sans-serif;
  font-size: 22px; font-weight: 800; line-height: 1.15;
  color: var(--primary-dark);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.mp-mascot-badge {
  display: inline-block; margin-top: 6px;
  padding: 3px 8px; border-radius: 6px;
  background: #fff; color: var(--primary-dark);
  font-size: 11px; font-weight: 700; letter-spacing: .02em; text-transform: uppercase;
}

.mp-pick-cta {
  display: inline-block; margin-top: 14px;
  color: var(--primary-dark);
  font-size: 13px; font-weight: 700; text-decoration: none;
}

.mp-pick-cta:hover { text-decoration: underline }
.mp-pick-cta::after { content: ' \203A' }

/* Narrow sidebar (tablet) squeezes the banner before the page goes one-column;
   drop the mascot a size rather than let the percentage wrap. */
/* Narrow sidebar: smaller figure means less head above the band, so the top
   margin and the negative margin shrink together — they have to stay equal or
   the head starts eating into the card title. */
@media (max-width: 1080px) and (min-width: 901px) {
  .mp-mascot { margin-top: 26px }
  .mp-mascot-img { flex-basis: 84px; width: 84px; margin-top: -26px }
  .mp-mascot-team { font-size: 19px }
}

/* form guide + head to head — result cards.
   Five per row on desktop; the pill sits on the card's top edge so the outcome
   reads before the scoreline does. Border colour repeats the pill, never
   carries the meaning alone. */
.mp-form-grid { display: grid; gap: 26px }
.mp-form-head {
  display: flex; align-items: center; gap: 8px; margin: 0 0 16px;
  font-family: 'Archivo', sans-serif; font-size: 15px; font-weight: 700;
}
.mp-form-head img { width: 22px; height: 22px; object-fit: contain }
.mp-form-badges { display: flex; gap: 6px }

.mp-rcards {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 10px;
}

.mp-rcard-wrap { min-width: 0 }

.mp-rcard {
  position: relative;
  padding: 18px 6px 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg);
  text-align: center;
}

.mp-rcard.is-win  { border-color: rgba(0, 122, 61, .45) }
.mp-rcard.is-loss { border-color: rgba(211, 33, 24, .45) }

.mp-rpill {
  position: absolute; top: 0; left: 50%;
  transform: translate(-50%, -50%);
  padding: 3px 12px; border-radius: 999px;
  color: #fff; font-size: 10px; font-weight: 700; letter-spacing: .04em;
  background: var(--text-3);
}
.mp-rcard.is-win  .mp-rpill { background: var(--primary-dark) }
.mp-rcard.is-loss .mp-rpill { background: var(--red-dark) }

.mp-rscore {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  font-family: 'Archivo', sans-serif;
  font-size: 17px; font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.mp-rscore span { color: var(--text-3); font-weight: 600 }

.mp-rcrests { display: flex; align-items: center; justify-content: center; gap: 14px; margin-top: 9px }
.mp-rcrests img { width: 28px; height: 28px; object-fit: contain }

.mp-rdate { margin-top: 7px; color: var(--text-3); font-size: 12px; text-align: center }

/* head to head — Wins / Draws / Wins circles between the two crests, then one
   row per meeting: date + competition on top, home side left, score centred.
   Circle colour never stands alone: each carries its number, a label below,
   and the crest beside it says whose count it is. */
.mp-h2h-tally {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(16px, 4vw, 44px);
  padding: 6px 0 20px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 4px;
}
.mp-h2h-cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-2);
}
.mp-h2h-num {
  width: 52px;
  height: 52px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Archivo', sans-serif;
  font-size: 20px;
  font-weight: 800;
}
.mp-h2h-num.is-home { background: var(--primary-dark, #007A3D); color: #fff }
.mp-h2h-num.is-draw { background: var(--bg); border: 1px solid var(--border); color: var(--text) }
.mp-h2h-num.is-away { background: var(--gold, #CFA761); color: #fff }
/* labels sit under the circles; the crests centre on the circle row, not the column */
.mp-h2h-tally .mp-h2h-tlogo { margin-bottom: 26px }
.mp-h2h-tlogo img { width: 40px; height: 40px; object-fit: contain }

.mp-h2h-row { padding: 12px 2px; border-bottom: 1px solid var(--border) }
.mp-h2h-row:last-child { border-bottom: 0; padding-bottom: 2px }
.mp-h2h-top {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 8px;
  font-size: 12px;
  color: var(--text-3);
}
.mp-h2h-league { display: inline-flex; align-items: center; gap: 5px }
.mp-h2h-league img { width: 16px; height: 16px; object-fit: contain }
.mp-h2h-mid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: 12px;
  font-size: 14px;
}
.mp-h2h-team { display: inline-flex; align-items: center; gap: 8px; min-width: 0 }
.mp-h2h-team.is-home { justify-content: flex-end }
.mp-h2h-team img { width: 22px; height: 22px; object-fit: contain; flex: none }
.mp-h2h-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
.mp-h2h-score { min-width: 44px; text-align: center; font-weight: 700; font-variant-numeric: tabular-nums }

/* match events — centre spine, home left, away right */

/* Ubao on the pitch behind the timeline. The art is deliberately pale on the
   left where the card text lands, and the event cards are opaque white, so the
   only thing needing protection is the card title — hence the veil, heavier on
   the left than the right so the mascot still reads. */
#mp-events-block {
  background-image:
    linear-gradient(90deg, rgba(255, 255, 255, .88) 0%, rgba(255, 255, 255, .72) 45%, rgba(255, 255, 255, .34) 100%),
    linear-gradient(180deg, #fff 0%, rgba(255, 255, 255, 0) 45%),
    url('assets/img/events-bg.webp');
  /* the art is pinned to a fixed height at bottom-right so expanding the
     timeline never rescales U-Bao; the 180deg fade sits over the art strip's
     top edge so the cut-off melts into the card instead of drawing a line */
  background-size: cover, 100% 480px, auto 480px;
  background-position: center, center bottom, right bottom;
  background-repeat: no-repeat;
}

.mp-ev-timeline { position: relative; display: grid; gap: 10px; padding: 4px 0 }

/* The spine is drawn behind the rows so it doesn't shift them. */
.mp-ev-timeline::before {
  content: ''; position: absolute; top: 0; bottom: 0; left: 50%;
  border-left: 1px dashed var(--border);
}

.mp-ev-row {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 46px minmax(0, 1fr);
  align-items: center;
}

/* Cards hug the spine instead of filling their half — on a wide rail a
   full-width card puts its text miles from the minute it belongs to. */
.mp-ev-card { width: 100%; max-width: 330px }

/* grid-row: 1 on both is load-bearing. The card is first in the DOM, and on an
   away row it is placed in column 3; sparse auto-placement will not then step
   back to column 2 for the minute, so it starts a second row and the minute
   drifts below its own card. */
.mp-ev-card, .mp-ev-min { grid-row: 1 }
.mp-ev-home .mp-ev-card { grid-column: 1; justify-self: end; flex-direction: row-reverse; text-align: right }
.mp-ev-away .mp-ev-card { grid-column: 3; justify-self: start }
.mp-ev-min { grid-column: 2 }

.mp-ev-card {
  display: flex; align-items: center; gap: 11px;
  padding: 11px 14px;
  border: 1px solid var(--border); border-radius: 10px;
  background: var(--bg);
  box-shadow: var(--shadow);
  min-width: 0;
}

/* Opaque so it breaks the dashed spine rather than being crossed out by it. */
.mp-ev-min {
  position: relative;
  padding: 5px 0;
  background: var(--bg);
  text-align: center;
  font-size: 12px; font-weight: 700;
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
}
.mp-ev-text { display: grid; min-width: 0 }
.mp-ev-name { font-size: 15px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
.mp-ev-sub { color: var(--text-3); font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap }

/* Icons are inline SVG; the span is just a non-shrinking slot for them. */
.mp-ev-icon { flex: 0 0 18px; width: 18px; height: 18px; display: block }
.mp-ev-svg { display: block; width: 18px; height: 18px }

.mp-ev-more {
  display: block; margin: 18px auto 0;
  padding: 9px 20px;
  border: 1px solid var(--primary-dark); border-radius: 999px;
  background: var(--primary-dark);
  color: #fff;
  font: inherit; font-size: 15px; font-weight: 600;
  cursor: pointer;
}
.mp-ev-more:hover { background: var(--primary); border-color: var(--primary) }

/* line-ups
   The pitch is one grid of two halves; each half lays its position groups out
   as columns, so 4-4-2 and 3-5-2 both space themselves without per-formation
   rules. Away half renders its groups reversed — both sides attack the centre. */
.mp-lu-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 12px; font-size: 15px }
.mp-lu-team { display: flex; align-items: center; gap: 8px; min-width: 0 }
.mp-lu-team-away { flex-direction: row-reverse }
.mp-lu-team img { width: 22px; height: 22px; object-fit: contain }
.mp-lu-form { color: var(--text-3); font-weight: 600; font-variant-numeric: tabular-nums }

.mp-pitch {
  position: relative;
  display: grid; grid-template-columns: 1fr 1fr;
  min-height: 430px;
  padding: 16px 10px;
  border-radius: var(--radius-lg);
  overflow: hidden;
  /* Pitch art in assets/img/pitch.webp (18 KB): generated, then recoloured
     pixel-wise to the brand hue (150deg) with the mown-stripe contrast preserved.
     Stretched to 100% 100%
     rather than cover: cover would crop the penalty boxes off the ends, and the
     halfway line has to stay on the container's centre because the two team
     halves butt up against it. */
  background: #0a6537 url(assets/img/pitch.webp) center / 100% 100% no-repeat;
}

/* Light wash only. The turf was recoloured to brand green (see the note on
   .mp-pitch), and white on its lightest stripe already measures ~5.6:1 — the
   heavier scrim the darker art needed would now just mute the brand colour. */
.mp-pitch::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: rgba(4, 40, 22, .12);
}

.mp-lu-half { position: relative; z-index: 1; display: grid; grid-auto-flow: column; grid-auto-columns: 1fr }
.mp-lu-line { display: flex; flex-direction: column; justify-content: space-around; align-items: center; gap: 10px; min-width: 0 }

/* grid col 1 is the team's left flank. Home attacks right, so col 1 is the top
   of the screen; the away side attacks left, where its left flank is the
   bottom — hence the reversed stacking, not a cosmetic choice. */
.mp-lu-half:last-child .mp-lu-line { flex-direction: column-reverse }

.mp-lu-p { position: relative; display: grid; justify-items: center; gap: 5px; width: 100%; min-width: 0 }

.mp-lu-avatar {
  display: grid; place-items: center;
  width: var(--lu-size, 38px); height: var(--lu-size, 38px);
  flex: 0 0 var(--lu-size, 38px);
  border-radius: 50%;
  overflow: hidden;
  background: #fff;
  color: var(--primary-dark);
  font-family: 'Archivo', sans-serif; font-size: 13px; font-weight: 800;
  box-shadow: 0 2px 6px rgba(0, 0, 0, .25);
}

/* Headshots arrive on a light background, so they sit on the white circle
   without a ring; object-fit keeps a non-square crop from stretching a face. */
.mp-lu-avatar img { width: 100%; height: 100%; object-fit: cover; display: block }

.mp-lu-name {
  max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: #fff; font-size: 12px; font-weight: 600; text-align: center;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .4);
}

.mp-lu-marks { position: absolute; top: -5px; left: calc(50% + 10px); display: flex; gap: 2px }
.mp-lu-mark { display: grid; place-items: center; width: 17px; height: 17px; border-radius: 50%; background: #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, .3) }
.mp-lu-mark .mp-ev-svg { width: 12px; height: 12px }

.mp-lu-coach { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 2px 0; font-size: 14px; font-weight: 600 }
.mp-lu-coach-label { color: var(--text-3); font-weight: 600; font-size: 12px; text-transform: uppercase; letter-spacing: .04em }

.mp-lu-subs { display: grid; grid-template-columns: 1fr 1fr; gap: 0 28px; margin-top: 20px }
.mp-lu-subs-title { margin: 0 0 6px; font-family: 'Archivo', sans-serif; font-size: 13px; font-weight: 700; color: var(--text-3); text-transform: uppercase; letter-spacing: .04em }
.mp-lu-sub-list { list-style: none; margin: 0; padding: 0 }
.mp-lu-sub { display: flex; align-items: center; gap: 8px; padding: 8px 0; border-bottom: 1px solid var(--border); font-size: 14px }
.mp-lu-sub:last-child { border-bottom: 0 }
.mp-lu-sub .mp-lu-avatar { box-shadow: none; background: var(--bg-2); font-size: 11px }
.mp-lu-sub-num { flex: 0 0 auto; min-width: 16px; color: var(--text-3); font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums }
.mp-lu-sub-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
.mp-lu-sub-pos { margin-left: auto; flex: 0 0 auto; color: var(--text-3); font-size: 12px }
.mp-lu-sub-marks { display: flex; align-items: center; gap: 4px; flex: 0 0 auto }
.mp-lu-sub-marks .mp-lu-marks { position: static; display: flex }
.mp-lu-sub-marks .mp-lu-mark { background: transparent; box-shadow: none }
.mp-lu-min { color: var(--primary-dark); font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums }

/* Narrow: the pitch turns vertical, home defending the top edge. */
@media (max-width: 700px) {
  .mp-pitch { grid-template-columns: 1fr; min-height: 0; gap: 18px }
  .mp-lu-half { grid-auto-flow: row }
  .mp-lu-half:first-child { border-right: 0; border-bottom: 2px solid rgba(255, 255, 255, .3); padding-bottom: 14px }
  .mp-lu-line { flex-direction: row; justify-content: space-around; gap: 6px }
  .mp-lu-p { width: auto; max-width: 76px }
  .mp-pitch::after { width: 84px; height: 84px; margin: -42px 0 0 -42px }
  .mp-lu-subs { grid-template-columns: 1fr; gap: 18px }
}

/* match info */
.mp-info-row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding: 9px 0; border-bottom: 1px solid var(--border); font-size: 15px }
.mp-info-row:last-child { border-bottom: 0 }
.mp-info-k { color: var(--text-3); flex: 0 0 auto }
.mp-info-ico { width: 15px; height: 15px; margin-right: 7px; vertical-align: -2.5px; color: var(--primary) }
.mp-info-v { font-weight: 600; text-align: right }
.mp-info-sub { display: block; color: var(--text-3); font-weight: 400; font-size: 12px }
.mp-info-missing { color: var(--text-3); font-weight: 400; font-style: italic }

/* match statistics — opposed bars meeting on a centre line */
.mp-ms-legend { display: flex; justify-content: space-between; margin-bottom: 14px; color: var(--text-3); font-size: 12px; font-weight: 600 }
.mp-ms + .mp-ms { margin-top: 16px }

.mp-ms-label {
  margin-bottom: 4px;
  color: var(--text-3);
  font-size: 12px; font-weight: 600; letter-spacing: .04em;
  text-align: center; text-transform: uppercase;
}

.mp-ms-vals {
  display: flex; justify-content: space-between;
  font-size: 15px; font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* Two halves with a 4px gap, so the centre line stays visible even when both
   sides are full. Each fill is anchored to its inner edge and grows outward. */
.mp-ms-bar { display: flex; gap: 4px; margin-top: 5px }
.mp-ms-half { flex: 1; height: 6px; border-radius: 999px; background: var(--bg-2); display: flex }
.mp-ms-l { justify-content: flex-end }
.mp-ms-r { justify-content: flex-start }
.mp-ms-half i { display: block; height: 100%; border-radius: 999px; background: var(--text) }
.mp-ms-r i { background: var(--text-2) }

/* league table — highlight the two sides in this match */
.uf-mini-table tbody tr.mp-table-on:hover { background: var(--primary-light) }
.mp-table-on .st-name { font-weight: 700; color: var(--primary-dark) }
.mp-table-gap td { padding: 6px 0; text-align: center; color: var(--text-3); letter-spacing: 3px; background: var(--bg-2) }

/* related news */
/* Full-bleed image card: the thumbnail fills the card and the title sits on a
   black bottom gradient, so the headline stays legible on any photo. */
/* upcoming matches — three fixture cards for this competition */
.mp-upnext { margin-top: 28px }
.mp-up-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px }
.mp-up-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  padding: 20px 18px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  color: inherit;
  text-decoration: none;
  transition: transform .15s ease, box-shadow .15s ease;
}
.mp-up-card:hover { transform: translateY(-2px); box-shadow: 0 8px 22px rgba(17, 17, 17, .1) }
.mp-up-league {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-2);
}
.mp-up-league img { width: 20px; height: 20px; object-fit: contain }
.mp-up-teams {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: 10px;
  width: 100%;
}
.mp-up-team {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  font-weight: 700;
  text-align: center;
}
.mp-up-team img { width: 52px; height: 52px; object-fit: contain }
.mp-up-vs { font-family: 'Archivo', sans-serif; font-size: 18px; font-weight: 800; color: var(--text) }
.mp-up-when {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 14px;
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-2);
  white-space: nowrap;
}
.mp-up-sep { color: var(--border) }
.mp-up-btn {
  width: 100%;
  padding: 10px;
  border: 1px solid var(--primary);
  border-radius: 10px;
  text-align: center;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--primary);
  transition: background .15s, color .15s;
}
.mp-up-card:hover .mp-up-btn { background: var(--primary); color: #fff }
@media (max-width: 900px) {
  .mp-up-grid { grid-template-columns: minmax(0, 1fr) }
}

.mp-news { margin-top: 28px }
.mp-news-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 20px }
.mp-news-card {
  position: relative;
  display: block;
  overflow: hidden;
  aspect-ratio: 4 / 5;
  background: var(--text-1, #111); /* dark fallback when a post has no thumbnail */
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  text-decoration: none;
  color: #fff;
  transition: box-shadow .18s, transform .18s;
}

.mp-news-card:hover {
  box-shadow: 0 8px 20px rgba(0, 0, 0, .25);
  transform: translateY(-2px);
}

.mp-news-img,
.mp-news-img img { position: absolute; inset: 0; width: 100%; height: 100%; }
.mp-news-img img { display: block; object-fit: cover }
.mp-news-card:hover .mp-news-img img { transform: scale(1.04) }
.mp-news-img img { transition: transform .3s }

.mp-news-body {
  position: absolute;
  inset: auto 0 0 0;
  display: flex;
  flex-direction: column;
  padding: 56px 14px 12px;
  background: linear-gradient(to top, rgba(0, 0, 0, .92) 0%, rgba(0, 0, 0, .72) 45%, rgba(0, 0, 0, 0) 100%);
}
.mp-news-card .tn-sec-title { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden; color: #fff; font-size: 16px; font-weight: 700; line-height: 1.35; text-shadow: 0 1px 3px rgba(0, 0, 0, .8) }

/* outlined category pill, top-left over the image */
.mp-news-tag {
  position: absolute;
  top: 12px;
  left: 12px;
  padding: 4px 12px;
  border: 1px solid rgba(255, 255, 255, .8);
  border-radius: 999px;
  background: rgba(0, 0, 0, .3);
  color: #fff;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.4;
}

@media (prefers-reduced-motion: reduce) {
  .mp-news-card, .mp-news-img img { transition: none }
  .mp-news-card:hover { transform: none }
  .mp-news-card:hover .mp-news-img img { transform: none }
}

@media (max-width: 900px) {
  .mp-split { grid-template-columns: minmax(0, 1fr) }
  .mp-news-grid { grid-template-columns: repeat(2, minmax(0, 1fr)) }
}

@media (max-width: 520px) {
  .mp-news-grid { grid-template-columns: minmax(0, 1fr) }
}

@media (max-width: 560px) {
  /* Cover on a narrow, tall card crops to the mascot's midriff and reads as a
     smudge — drop to the flat white card instead. */
  #mp-events-block { background-image: none }
  .mp-rcards { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px }
  .mp-ev-row { grid-template-columns: minmax(0, 1fr) 38px minmax(0, 1fr) }
}

@media (max-width: 640px) {
  .mp-team img { width: 34px; height: 34px }
  .mp-team-name { font-size: 15px }
  .mp-figure { font-size: 26px }
  .mp-score { gap: 10px }
  .mp-rscore { font-size: 15px }
  .mp-rcrests img { width: 22px; height: 22px }
}

/* ── about page — hero, mission/vision, timeline, partners, ambassadors ──
   Hardcoded template (page-about-us.php); the stored builder content is a flat
   run of <p> tags no stylesheet can lay out. */

.ab-hero { position: relative; display: flex; align-items: flex-end; min-height: clamp(360px, 40vw, 520px); overflow: hidden; background: #07452A }
.ab-hero-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover }
/* Scrim is brand green rather than neutral black — the office shot is cool-lit
   and goes grey under a black wash. */
.ab-hero::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    linear-gradient(90deg, rgba(5, 42, 26, .94) 0%, rgba(5, 42, 26, .82) 46%, rgba(5, 42, 26, .34) 100%),
    linear-gradient(0deg, rgba(5, 42, 26, .7), rgba(5, 42, 26, 0) 55%);
}
.ab-hero-inner { position: relative; z-index: 1; width: 100%; max-width: 1200px; margin: 0 auto; padding: 44px 24px 48px; color: #fff }
.ab-eyebrow { font-size: 12px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--gold) }
.ab-title { font-family: 'Archivo', sans-serif; font-weight: 900; font-size: clamp(30px, 4.4vw, 52px); line-height: 1.08; margin: 10px 0 14px }
.ab-lede { max-width: 620px; font-size: clamp(15px, 1.4vw, 18px); line-height: 1.6; color: rgba(255, 255, 255, .9) }

.ab-sec { padding-top: 40px; padding-bottom: 8px }
.ab-sub { font-family: 'Archivo', sans-serif; font-size: 18px; font-weight: 800; margin: 32px 0 16px }
.ab-sub::after { content: ''; display: block; width: 32px; height: 3px; margin-top: 8px; border-radius: 2px; background: var(--gold) }

.ab-who { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); gap: 32px; align-items: start }
/* top: 80px matches the other sticky rails (.uf-side, .sp-stick) — clears the
   sticky header. Dropped below 900px, where the column stacks. */
.ab-who-copy { position: sticky; top: 80px; font-size: 17px; line-height: 1.75; color: var(--text-2) }
.ab-who-copy p + p { margin-top: 16px }
.ab-mv { display: grid; gap: 16px }
.ab-mv-card {
  background: var(--bg);
  border: 1px solid var(--border);
  border-left: 3px solid var(--primary);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  padding: 20px 24px 22px;
}
.ab-mv-card img { width: 40px; height: 40px }
.ab-mv-card h3 { font-family: 'Archivo', sans-serif; font-size: 17px; font-weight: 800; letter-spacing: .04em; text-transform: uppercase; margin: 12px 0 8px }
.ab-mv-card p { font-size: 15px; line-height: 1.65; color: var(--text-2) }

.ab-tl { list-style: none; display: grid; gap: 36px; margin: 0; padding: 0 }
.ab-tl-item { position: relative; padding-left: 34px }
.ab-tl-item::before { content: ''; position: absolute; left: 7px; top: 12px; bottom: -40px; width: 2px; background: var(--border-2) }
.ab-tl-item:last-child::before { display: none }
.ab-tl-item::after { content: ''; position: absolute; left: 0; top: 4px; width: 16px; height: 16px; border-radius: 50%; background: var(--primary); box-shadow: 0 0 0 4px var(--primary-light) }
.ab-tl-date { font-family: 'Archivo', sans-serif; font-size: 15px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; margin-bottom: 14px }
/* Fixed 3-up, not auto-fit: a milestone with one clip keeps the same card width
   as the three-up rows instead of stretching across the section. */
.ab-tl-media { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 18px }

.ab-media { background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius-lg); box-shadow: var(--shadow); padding: 10px 10px 14px }
.ab-frame { position: relative; aspect-ratio: 16 / 9; border-radius: var(--radius); overflow: hidden; background: #0b0f14 }
.ab-frame iframe, .ab-frame img { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; object-fit: cover }
.ab-media figcaption { padding: 12px 6px 0; font-size: 14px; line-height: 1.5; color: var(--text-2) }

.ab-brands { display: flex; flex-wrap: wrap; gap: 16px }
.ab-brand { width: 200px; padding: 16px; background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius-lg); box-shadow: var(--shadow) }
.ab-brand img { width: 100%; height: auto; object-fit: contain }

.ab-baes { list-style: none; display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 14px; margin: 0; padding: 0 }
/* Cutout PNGs on transparent backgrounds — the green tile is what makes them
   read as portraits instead of floating heads. */
.ab-bae {
  position: relative;
  display: block;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: linear-gradient(165deg, #0B6B3D, #009E4F 55%, #05341F);
  text-decoration: none;
  transition: transform .18s ease, box-shadow .18s ease;
}
.ab-bae:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); text-decoration: none }
/* height:auto beats the width/height attrs, letting aspect-ratio rule */
.ab-bae img { width: 100%; height: auto; aspect-ratio: 1; object-fit: cover }
.ab-bae-tag {
  position: absolute;
  inset: auto 0 0;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 18px 10px 8px;
  background: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, .68));
  color: #fff;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ab-bae-tag svg { flex-shrink: 0; width: 14px; height: 14px; fill: currentColor }

.ab-cta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 28px;
  margin: 24px 0 8px;
  padding: 30px 34px;
  background: linear-gradient(120deg, #07452A, #0B6B3D);
  border-radius: var(--radius-lg);
  color: #fff;
}
.ab-cta h2 { font-family: 'Archivo', sans-serif; font-size: clamp(20px, 2.4vw, 26px); font-weight: 900; letter-spacing: .02em }
.ab-cta p { margin-top: 8px; font-size: 15px; line-height: 1.6; color: rgba(255, 255, 255, .88) }
.ab-cta-btn { flex-shrink: 0; padding: 14px 28px; background: #E9A62A; border-radius: 10px; color: #fff; font-size: 15px; font-weight: 700; text-decoration: none }
.ab-cta-btn:hover { filter: brightness(1.08) }

@media (max-width: 900px) {
  .ab-who { grid-template-columns: minmax(0, 1fr) }
  .ab-who-copy { position: static }
  .ab-tl-media { grid-template-columns: repeat(2, minmax(0, 1fr)) }
  .ab-cta { flex-direction: column; align-items: flex-start }
}
@media (max-width: 600px) {
  /* 3-up, not auto-fill: two columns turn 32 portraits into 16 rows of scroll. */
  .ab-baes { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px }
  .ab-bae-tag { padding: 14px 7px 6px; font-size: 11px; gap: 4px }
  .ab-tl-media { grid-template-columns: minmax(0, 1fr) }
  .ab-hero-inner { padding: 32px 20px 36px }
  .ab-sec { padding-top: 28px }
}
@media (prefers-reduced-motion: reduce) {
  .ab-bae { transition: none }
  .ab-bae:hover { transform: none }
}

/* ── category archive ──
   Reuses the news page's rail, cards and pills; only the identity header, the
   hero split and the list rows are new. Classes are ct-* so nothing here can
   change how /news/ renders. */
/* .sp-crumb is written for the dark post hero; on this light page it needs the
   text colours inverted. */
.ct-crumb { color: var(--text-3); margin-bottom: 4px; padding: 4px 4px 0; flex-wrap: wrap }
.ct-crumb a { color: var(--text-2) }
.ct-crumb a:hover { color: var(--primary-dark) }
.ct-crumb span:last-child { color: var(--text) }

.ct-head {
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 8px 4px 22px;
}
.ct-logo { width: 72px; height: 72px; object-fit: contain; flex-shrink: 0 }
.ct-title {
  font-family: 'Archivo', sans-serif;
  font-size: clamp(26px, 3.2vw, 36px);
  line-height: 1.1;
  margin: 0 0 6px;
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 10px;
}
/* The English name sits beside a Chinese one; on the en archive it is absent. */
.ct-title-alt { font-size: 15px; font-weight: 500; color: var(--text-3) }
.ct-desc { max-width: 640px; color: var(--text-2); font-size: 14px; line-height: 1.6; margin: 0 }

.ct-pills { margin-bottom: 18px }

/* Lead card left, four stacked rows right, both columns the same height:
   `stretch` squares the row off and 4x1fr splits the right column evenly, so
   the lead grows or shrinks to whatever the four rows come to. Row count is set
   by the hero query in category.php - keep the two in step. */
.ct-hero { display: grid; grid-template-columns: 1.35fr 1fr; gap: 16px; margin-bottom: 28px; align-items: stretch }
.ct-hero-side { display: grid; gap: 12px; grid-template-rows: repeat(4, 1fr) }

.ct-lead { position: relative; border-radius: var(--radius-lg); overflow: hidden; height: 100% }
.ct-lead-img { display: block; position: relative; text-decoration: none; height: 100% }
/* min-height covers the case where the four rows are shorter than the image
   wants to be - a category with only one or two posts. */
.ct-lead-img img { display: block; width: 100%; height: 100%; min-height: 320px; object-fit: cover }
/* Scrim rather than a flat tint: the title sits on photography, and a gradient
   keeps the top of the image readable while still passing contrast at the base. */
.ct-lead-body {
  position: absolute;
  inset: auto 0 0 0;
  padding: 56px 22px 20px;
  background: linear-gradient(to top, rgba(0, 0, 0, .88) 30%, rgba(0, 0, 0, 0));
  color: #fff;
  display: block;
}
.ct-lead-title { display: block; font-family: 'Archivo', sans-serif; font-weight: 700; font-size: 20px; line-height: 1.3 }
.ct-lead-excerpt { display: block; margin-top: 8px; font-size: 13px; line-height: 1.55; color: rgba(255, 255, 255, .82) }
.ct-lead .np-feat-badge { position: absolute; top: 14px; left: 14px; z-index: 1 }

.ct-srow {
  display: grid;
  grid-template-columns: 104px 1fr;
  gap: 12px;
  align-items: center;
  padding: 10px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  text-decoration: none;
}
.ct-srow:hover { border-color: var(--primary) }
.ct-srow-thumb { align-self: stretch; display: block }
.ct-srow-thumb img { display: block; width: 100%; height: 100%; min-height: 66px; object-fit: cover; border-radius: 8px }
.ct-srow-title { display: block; font-weight: 600; font-size: 14px; line-height: 1.4; color: var(--text) }

/* Hard cap on excerpt height. The PHP trim keeps whole articles off the wire;
   this is what guarantees the shape of the row, and it holds whatever the
   editor pastes in either language. */
.tn2-excerpt,
.ct-lead-excerpt,
.np-banner-sub {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.tn2-excerpt      { -webkit-line-clamp: 4; line-clamp: 4 }
/* Over the lead photo there is room for two before the scrim runs out. */
.ct-lead-excerpt  { -webkit-line-clamp: 2; line-clamp: 2 }
.np-banner-sub    { -webkit-line-clamp: 2; line-clamp: 2 }

.ct-section-title { font-family: 'Archivo', sans-serif; font-size: 20px; margin: 0 0 16px }

.ct-row { display: grid; grid-template-columns: 180px 1fr; gap: 16px; padding: 16px 0; border-bottom: 1px solid var(--border) }
.ct-row:first-of-type { padding-top: 0 }
.ct-row:last-of-type { border-bottom: 0 }
.ct-row-img img { display: block; width: 100%; height: 112px; object-fit: cover; border-radius: 10px }
.ct-row-title { font-size: 16px; line-height: 1.35; margin: 0 0 6px }
.ct-row-title a { color: var(--text); text-decoration: none }
.ct-row-title a:hover { color: var(--primary-dark) }
.ct-row .tn2-excerpt { margin: 0 0 8px; font-size: 13px }

@media (max-width: 860px) {
  .ct-hero { grid-template-columns: minmax(0, 1fr) }
  .ct-hero-side { grid-template-rows: auto }
  .ct-lead-img img { min-height: 220px }
  .ct-head { gap: 14px; padding-bottom: 16px }
  .ct-logo { width: 52px; height: 52px }
  .ct-row { grid-template-columns: 116px 1fr; gap: 12px }
  .ct-row-img img { height: 78px }
}

/* Upcoming Matches, empty or failed: the strip keeps the height its skeleton
   reserved and centres the message in it, so the page cannot drop 255px after
   the reader has already seen three cards' worth of space. */
.mp-up-empty {
  grid-column: 1 / -1;
  align-self: center;
}

/* ── AI Prediction page (page-ai-prediction.php) ──
   The model switcher and the tab strip are radio inputs; panels swap on
   :checked, so the page ships no JS. .ai-vh hides the radios visually but keeps
   them in the tab order — display:none would drop them out of it. */

.ai-vh {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* 优设标题黑, self-hosted because a CJK display face has no Google Fonts entry.
   9-glyph subset — the zh banner headline and nothing else. Editing that
   headline means regenerating the file and bumping the ?v= below; see
   assets/fonts/README.md. */
@font-face {
  font-family: 'YouSheBiaoTiHei';
  src: url('assets/fonts/ysbth-banner.woff2?v=2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* ── hero ── */
/* Fixed band height so the banner reads the same in both languages.
   The cost is a copy budget. At 1280px the en column (the longer of the two)
   fills 476 of the 496px content box — 46px spare. Lengthen the lede or the
   headline past that and the text spills out of the band onto the grey section
   below, because nothing clips it any more. Re-measure if you edit that copy. */
.ai-hero {
  position: relative;
  height: 560px;
  overflow: visible;
  background: #EEF4E4;  /* the art is the video poster now, see .ai-hero-video */
}

/* No wash over the art. There used to be a gradient here for text legibility,
   and it bleached the network to mint (68% opaque across the middle). The image
   is already pale on the left where the copy sits (#E7F2CC); the reference
   design uses it at full strength. */


.ai-hero-inner {
  position: relative;
  z-index: 1;
  height: 100%;
  max-width: 1200px;
  margin: 0 auto;
  padding: 28px 24px 36px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 250px;
  align-items: center;
  gap: 24px;
}

/* .sp-crumb is written for the dark post hero; this hero is light, so the same
   inversion the category header needs applies here. */
.ai-hero .sp-crumb { color: var(--text-3); margin-bottom: 14px }
.ai-hero .sp-crumb a { color: var(--text-2) }
.ai-hero .sp-crumb a:hover { color: var(--primary-dark) }
.ai-hero .sp-crumb span:last-child { color: var(--text) }

/* zh gets the display face; the en headline stays on the shell's Archivo.
   :lang(zh) matches the <html lang="zh-CN"> Polylang writes. */
.ai-title:lang(zh) {
  font-family: 'YouSheBiaoTiHei', 'Archivo', sans-serif;
  font-weight: 400;
}

/* The display face's glyphs fill only .72em of the em box (ink 711 to -9 of
   1000 units), so line-height buys far less here than it looks: at 1.02 the two
   rows still sat ~20px apart. .9 leaves ~.18em between them, about 12px at 68px,
   which is the same visual gap the Archivo headline gets at .96, with no risk
   of the rows touching. */
/* Sizes are the reference art's, scaled to our 1152px content width: the second
   line's ink is 96px tall on a 1265px-wide mock, the first 59px (1.63x), so the
   second line lands at 121px and the first at .6 of it. That second line,
   预见赛果 plus a half-width "!", is 4.002em wide — 484px at 121 — which is why
   the copy column is 1.15fr (504px): the reference's text column is simply wider
   than ours was. Below ~1315px the column narrows with the viewport, and the vw
   term has to keep 4.002em inside it. The tight end is 1025px on a desktop with
   a classic ~15px scrollbar: media queries count the scrollbar, layout does not,
   so the three-column grid runs with 15px less column than the viewport implies
   (measured 392px). The limit there is 9.51vw; 9.2vw leaves ~14px of slack, and
   more at every wider size. 9.6vw wrapped the line at exactly that width.
   No letter-spacing — the reference sets the glyphs tight. */
.ai-title:lang(zh) {
  font-size: clamp(40px, 9.2vw, 121px);
  line-height: .9;
  letter-spacing: 0;
}

.ai-title-a,
.ai-title-b { display: block }

/* The ball-and-streaks mark beside 超越数据, from the reference lockup. Sized in
   em of this line so it scales with the headline at every width. Measured off
   home-title.png against line 1: 1.19em tall with its bottom on the glyphs' ink
   bottom, 2.27em wide (the file's own 381:200), and its left edge .53em back
   into 据 so the top streak's tip meets the character as it does in the art.
   Line 1 plus the mark is 3.25x the big line's size, under line 2's 4.00x, so
   it can never be what makes a line wrap. A pseudo-element: decorative, silent
   to screen readers, and it adds no height to the fixed band. */
.ai-title-a:lang(zh) {
  font-size: .6em;
  position: relative;
  width: max-content;
}

/* En gets the same mark at the same pixel size as zh (zh line 1 is 72.6px
   with a 2.27em mark = ~165px; en line 1 is 48px, so 3.43em), tucked into the
   line end the way zh's is. Phones get a smaller one: at full size it would
   run past the gutter after "Beyond the data." */
.ai-title-a:not(:lang(zh)) { position: relative; width: max-content }
.ai-title-a:not(:lang(zh))::after {
  content: "";
  position: absolute;
  left: calc(100% - .45em);
  top: -.6em;
  width: 3.43em;
  height: 1.8em;
  background: url('assets/img/ai/icon-ball.webp') no-repeat center / contain;
}
@media (max-width: 620px) {
  .ai-title-a:not(:lang(zh))::after { width: 2.7em; height: 1.42em; top: -.45em }
}
/* At 360px and under, "Beyond the data." alone fills the line (287 of 288px
   at 320), so there is no room for the mark; it is decoration, so it goes. */
@media (max-width: 360px) {
  .ai-title-a:not(:lang(zh))::after { content: none }
}

.ai-title-a:lang(zh)::after {
  content: "";
  position: absolute;
  left: calc(100% - .53em);
  top: -.4em;
  width: 2.27em;
  height: 1.19em;
  background: url('assets/img/ai/icon-ball.webp') no-repeat center / contain;
}

/* Capped at 48 and not 54: the copy column narrowed when the mascot column grew,
   and at 54 "Beyond the data." wraps, which turns the two-line headline into
   three and pushes the lede out of the fixed band.
   Line-height .96 is about the floor for Archivo 900: its descender plus the
   next line's ascender come to ~.92em, so any tighter and the "y" in "Beyond"
   meets the "h" below it. Top margin is small now the eyebrow pill is gone —
   it follows the breadcrumb directly. */
.ai-title {
  font-family: 'Archivo', sans-serif;
  font-weight: 900;
  font-size: clamp(32px, 4.4vw, 48px);
  line-height: .96;
  color: #024413;            /* measured from the reference art */
  margin: 4px 0 18px;
}

.ai-lede {
  max-width: 46ch;
  font-size: 15px;
  line-height: 1.75;
  color: var(--text-2);
}

.ai-lede + .ai-lede { margin-top: 14px }

.ai-stat {
  background: var(--bg);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  padding: 12px 16px;
  text-align: center;
}

.ai-stat-value {
  display: block;
  font-family: 'Archivo', sans-serif;
  font-weight: 800;
  font-size: 26px;
  line-height: 1.1;
  color: var(--primary-dark);
}

.ai-stat-label {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  color: var(--text-3);
}

/* The shared .hero-cta pill, widened to fill the stat column, with the label
   and arrow kept together in the middle rather than pushed to opposite ends. */
.ai-hero-cta {
  justify-content: center;
  padding: 14px 20px;
}

.ai-stat-note {
  text-align: center;
  font-size: 12px;
  color: var(--text-2);
}

/* Below 1024px the copy takes the full width and the band has to grow with it,
   so the fixed height comes off. */
@media (max-width: 1024px) {
  .ai-hero { height: auto }
  .ai-hero-inner { height: auto; grid-template-columns: minmax(0, 1fr) 220px }
  .ai-hero-copy { grid-column: 1 / -1 }
  /* The copy goes full width here, so the column stops being the limit it is
     on desktop and the headline can size off the viewport. The second line is
     4.002em, so 20vw makes it ~80% of the screen on a phone and still leaves
     slack inside the 16px gutters (390px: line 312, column 358). The 121px cap
     only binds above ~605px, where the column is wide enough for it. */
  .ai-title:lang(zh) { font-size: min(20vw, 121px) }
}

@media (max-width: 620px) {
  .ai-hero-inner {
    grid-template-columns: minmax(0, 1fr);
    padding: 20px 16px 28px;
  }
}

/* ── section headings ── */
.ai-sec { padding-top: 40px; padding-bottom: 40px }

.ai-kicker {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-3);
  margin-bottom: 8px;
}

.ai-h2 {
  font-family: 'Archivo', sans-serif;
  font-weight: 900;
  font-size: clamp(24px, 4vw, 38px);
  line-height: 1.15;
  color: var(--text);
}

.ai-sub {
  margin-top: 10px;
  font-size: 15px;
  font-weight: 600;
  color: var(--primary-dark);
}

/* ── model switcher ── */
.ai-models {
  margin-top: 28px;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
}

@media (max-width: 900px) { .ai-models { grid-template-columns: repeat(2, minmax(0, 1fr)) } }
@media (max-width: 520px) { .ai-models { grid-template-columns: minmax(0, 1fr) } }

.ai-model {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--ai-tint);
  color: inherit;
  text-decoration: none;
  transition: transform .18s ease, border-color .18s ease, box-shadow .18s ease;
}
/* The card links to the dashboard: lift, accent the border and slide the
   eyebrow arrow on hover, and give keyboard focus the same cue. */
.ai-model:hover,
.ai-model:focus-visible {
  transform: translateY(-3px);
  border-color: var(--ai-accent);
  box-shadow: 0 10px 28px rgba(0, 0, 0, .35);
}
.ai-model:focus-visible { outline: 2px solid var(--ai-accent); outline-offset: 3px }
.ai-model-eyebrow span { display: inline-block; transition: transform .18s ease }
.ai-model:hover .ai-model-eyebrow span,
.ai-model:focus-visible .ai-model-eyebrow span { transform: translateX(4px) }
@media (prefers-reduced-motion: reduce) {
  .ai-model, .ai-model-eyebrow span { transition: none }
  .ai-model:hover, .ai-model:focus-visible,
  .ai-model:hover .ai-model-eyebrow span, .ai-model:focus-visible .ai-model-eyebrow span { transform: none }
}

.ai-model-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 6px;
}

.ai-model-top img {
  width: 56px;
  height: 56px;
  object-fit: contain;
}

.ai-model-eyebrow {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .12em;
  color: var(--ai-accent);
  text-align: right;
}

.ai-model-name {
  font-family: 'Archivo', sans-serif;
  font-weight: 800;
  font-size: 18px;
  color: var(--text);
}

.ai-model-meta {
  font-size: 12px;
  font-weight: 700;
  color: var(--ai-accent);
}

.ai-model-desc {
  margin-top: 4px;
  font-size: 13px;
  line-height: 1.6;
  color: var(--text-2);
}


.ai-radio:focus-visible ~ .ai-tabs .ai-tab {
  outline: 2px solid var(--primary-dark);
  outline-offset: 2px;
}

/* ── testimonials: filterable carousel over the stadium ──
   Centred header, four filter pills, a scroll-snap rail of cards with the one
   nearest the centre lit, dots, and a trust row. The rail is native overflow
   scrolling; ai-landing.js only moves it, lights the centre card, keeps the
   dots honest and hides cards the active filter rejects. Sits full-bleed so
   the stadium backdrop runs edge to edge. */
.ai-voices {
  position: relative;
  background: #07110D var(--ai-voices-bg) center / cover no-repeat;
}
.ai-voices::before {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(7, 17, 13, .92) 0%, rgba(7, 17, 13, .78) 50%, rgba(7, 17, 13, .94) 100%);
}
.ai-voices-in { position: relative; text-align: center; padding-top: 48px; padding-bottom: 40px }
.ai-voices .ai-kicker { letter-spacing: .18em; text-transform: uppercase; font-size: 12px }
.ai-h2-accent { color: var(--primary-on-dark, var(--primary)) }
.ai-voices .ai-sub { color: var(--text-2); font-weight: 500 }

/* filter pills */
.ai-voice-filters {
  display: inline-flex; flex-wrap: wrap; justify-content: center; gap: 4px;
  margin-top: 22px; padding: 5px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .05);
  border: 1px solid rgba(255, 255, 255, .1);
}
.ai-voice-filter {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 9px 16px; border: 1px solid transparent; border-radius: 999px;
  background: none; color: var(--text-2);
  font: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
}
.ai-voice-filter svg { width: 16px; height: 16px }
.ai-voice-filter:hover { color: #fff }
.ai-voice-filter.is-on { background: rgba(0, 158, 79, .16); border-color: rgba(63, 203, 122, .45); color: #fff }
.ai-voice-count {
  min-width: 20px; padding: 1px 6px; border-radius: 999px;
  background: rgba(255, 255, 255, .1); font-size: 11px; font-weight: 700; color: var(--text-2);
}
.ai-voice-filter.is-on .ai-voice-count { background: var(--primary); color: #fff }

/* rail */
.ai-voice-rail { position: relative; margin: 28px -24px 0; padding: 0 24px }
.ai-voice-track {
  list-style: none; margin: 0; padding: 12px 0 8px;
  display: flex; gap: 16px;
  overflow-x: auto; scroll-snap-type: x mandatory; scroll-behavior: smooth;
  scrollbar-width: none;
  scroll-padding: 0 24px;
}
.ai-voice-track::-webkit-scrollbar { display: none }
.ai-voice-track { cursor: grab }
.ai-voice-track.is-dragging { cursor: grabbing; scroll-snap-type: none; scroll-behavior: auto; user-select: none }
.ai-voice-track:focus-visible { outline: 2px solid var(--primary-on-dark); outline-offset: 4px }

.ai-voice {
  flex: 0 0 min(300px, 84vw);
  scroll-snap-align: center;
  display: flex; flex-direction: column; gap: 12px;
  padding: 20px 22px;
  text-align: left;
  background: rgba(10, 22, 18, .78);
  border: 1px solid rgba(255, 255, 255, .1);
  border-radius: var(--radius-lg);
  box-shadow: 0 10px 30px rgba(0, 0, 0, .35);
  transition: border-color .25s, box-shadow .25s, transform .25s;
}
.ai-voice.is-hidden { display: none }
.ai-voice.is-active {
  border-color: rgba(63, 203, 122, .6);
  box-shadow: 0 0 0 1px rgba(63, 203, 122, .25), 0 0 28px rgba(0, 158, 79, .28), 0 14px 34px rgba(0, 0, 0, .45);
  transform: translateY(-4px);
}
@media (prefers-reduced-motion: reduce) {
  .ai-voice { transition: none }
  .ai-voice.is-active { transform: none }
  .ai-voice-track { scroll-behavior: auto }
}

.ai-voice-quote {
  position: relative; margin: 0; padding-left: 22px; flex: 1;
  font-size: 14px; line-height: 1.65; color: var(--text-2);
}
.ai-voice.is-active .ai-voice-quote { color: var(--text) }
.ai-voice-quote::before {
  content: "\201C";
  position: absolute; left: 0; top: -6px;
  font-family: 'Archivo', sans-serif; font-weight: 900; font-size: 36px; line-height: 1;
  color: var(--primary-on-dark);
}
.ai-voice-stars { display: flex; gap: 2px; margin: 0; color: var(--primary-on-dark) }
.ai-voice-stars svg { width: 13px; height: 13px }

.ai-voice-by { display: flex; align-items: center; gap: 10px; font-size: 13px; line-height: 1.35 }
.ai-voice-by strong { display: block; color: var(--text); font-weight: 700 }
.ai-voice-role { display: block; color: var(--text-3) }
.ai-voice-avatar {
  flex-shrink: 0; width: 38px; height: 38px; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(0, 158, 79, .18); border: 1px solid rgba(63, 203, 122, .4);
  color: var(--primary-on-dark);
  font-family: 'Archivo', sans-serif; font-weight: 800; font-size: 15px;
  overflow: hidden;
}
.ai-voice-avatar img { width: 100%; height: 100%; object-fit: cover }
/* the reviewer's real 90-day record from the feed, under the byline */
.ai-voice-rec { margin: 10px 0 0; font-size: 12px; font-weight: 700; color: var(--primary-on-dark) }
.ai-voice-stars svg.is-off { color: rgba(255, 255, 255, .18) }
/* loading / error / empty card spans the rail instead of sitting in one slot */
.ai-voice-wait { flex-basis: 100%; display: grid; place-items: center; min-height: 160px }

.ai-voice-tags { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 }
.ai-voice-tags span {
  padding: 4px 10px; border-radius: 999px;
  background: rgba(255, 255, 255, .06); border: 1px solid rgba(255, 255, 255, .1);
  font-size: 11px; font-weight: 600; color: var(--text-2);
}

.ai-voice-arrow {
  position: absolute; top: 50%; z-index: 2;
  width: 40px; height: 40px; margin-top: -20px;
  border-radius: 50%; border: 1px solid rgba(255, 255, 255, .2);
  background: rgba(10, 22, 18, .85); color: #fff;
  font-size: 26px; line-height: 1; cursor: pointer;
}
.ai-voice-arrow[data-dir="-1"] { left: 2px }
.ai-voice-arrow[data-dir="1"]  { right: 2px }
.ai-voice-arrow:hover { border-color: var(--primary-on-dark); color: var(--primary-on-dark) }
.ai-voice-arrow:disabled { opacity: .3; cursor: default }

.ai-voice-dots { display: flex; justify-content: center; gap: 6px; margin-top: 12px }
.ai-voice-dots i { width: 6px; height: 6px; border-radius: 50%; background: rgba(255, 255, 255, .25) }
.ai-voice-dots i.is-on { background: var(--primary-on-dark) }

.ai-voice-trust {
  list-style: none; margin: 32px 0 0; padding: 0;
  display: flex; flex-wrap: wrap; justify-content: center; gap: 0;
}
.ai-voice-trust li {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 24px;
  border-left: 1px solid rgba(255, 255, 255, .12);
  font-size: 13px; color: var(--text-2); text-align: left;
}
.ai-voice-trust li:first-child { border-left: 0 }
.ai-voice-trust svg { width: 20px; height: 20px; color: var(--primary-on-dark); flex-shrink: 0 }
@media (max-width: 620px) {
  .ai-voice-arrow { display: none }
  .ai-voice-trust li { width: 50%; border-left: 0; padding: 6px 8px }
  /* pills: the three filters split the bar evenly inside the gutters, so the
     bar never runs past the screen edge */
  .ai-voice-filters { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); width: 100%; max-width: 100%; gap: 2px; padding: 4px }
  .ai-voice-filter { justify-content: center; gap: 5px; padding: 8px 4px; font-size: 12px; white-space: nowrap; min-width: 0 }
  .ai-voice-filter svg { width: 14px; height: 14px; flex-shrink: 0 }
  .ai-voice-count { min-width: 18px; padding: 1px 5px; font-size: 10.5px }
}
/* the smallest phones: the icons go so the labels and counts keep their room */
@media (max-width: 360px) {
  .ai-voice-filter svg { display: none }
  .ai-voice-filter { gap: 4px; padding: 8px 2px }
}

/* ── tabs + panels ── */
.ai-showcase { padding-top: 0 }

.ai-tabsec { border: 0; padding: 0; margin: 0; min-width: 0 }

.ai-tabs {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 6px;
  padding: 6px;
  border-radius: var(--radius-lg);
  background: var(--primary-dark);
}

.ai-tab {
  padding: 14px 10px;
  border-radius: 10px;
  text-align: center;
  font-size: 15px;
  font-weight: 700;
  color: rgba(255, 255, 255, .85);
  cursor: pointer;
  transition: background .18s, color .18s;
}

.ai-tab:hover { color: #fff }

#ai-t-settled:checked  ~ .ai-tabs .ai-tab[for="ai-t-settled"],
#ai-t-accuracy:checked ~ .ai-tabs .ai-tab[for="ai-t-accuracy"] {
  background: var(--bg);
  color: var(--primary-dark);
}

@media (prefers-reduced-motion: reduce) { .ai-tab { transition: none } }

/* Phones keep the two tabs side by side; tighter padding and type let
   "Recent predictions" / 近期赛事预测 fit a half-width tab at 375px. */
@media (max-width: 560px) {
  .ai-tabs { gap: 4px; padding: 4px }
  .ai-tab { padding: 12px 6px; font-size: 14px; line-height: 1.25 }
}

.ai-panel { display: none; margin-top: 20px }

#ai-t-settled:checked  ~ #ai-p-settled,
#ai-t-accuracy:checked ~ #ai-p-accuracy { display: block }

.ai-note {
  margin-bottom: 14px;
  font-size: 13px;
  color: var(--text-3);
}

.ai-note a { color: var(--primary-dark); font-weight: 600 }

/* ── the verdict pair ── */
/* The grid sits on an inner element so one blur and one panel can cover both
   cards at once — a filter on the grid container itself would also blur the
   panel that has to stay readable on top of it. */
.ai-verdict {
  position: relative;
  overflow: hidden;
}

.ai-verdict-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: 16px;
  align-items: start;
}

@media (max-width: 860px) {
  .ai-verdict-grid { grid-template-columns: minmax(0, 1fr) }
}

.ai-fixture, .ai-call { padding: 20px 22px }

.ai-fixture-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--border);
}

.ai-fixture-head img { width: 30px; height: 30px; object-fit: contain }

.ai-fixture-label { font-size: 12px; color: var(--text-3) }

.ai-fixture-head strong {
  font-family: 'Archivo', sans-serif;
  font-size: 17px;
}

.ai-fixture-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  padding: 16px 0;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
  color: var(--text-2);
}

.ai-fixture-meta p + p { margin-top: 4px }

.ai-fixture-teams {
  font-family: 'Archivo', sans-serif;
  font-weight: 800;
  font-size: clamp(18px, 2.4vw, 24px);
  color: var(--text);
}

.ai-details { margin-top: 16px }

.ai-details summary {
  list-style: none;
  padding: 13px 16px;
  border-radius: 10px;
  background: var(--primary);
  color: #fff;
  font-weight: 700;
  font-size: 14px;
  text-align: center;
  cursor: pointer;
}

.ai-details summary::-webkit-details-marker { display: none }
.ai-details summary::after { content: " \25BE" }
.ai-details[open] summary::after { content: " \25B4" }
.ai-details summary:hover { background: var(--primary-dark) }

.ai-breakdown { margin-top: 14px; display: grid; gap: 10px }

.ai-breakdown > div {
  display: grid;
  grid-template-columns: 130px minmax(0, 1fr);
  gap: 12px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
}

.ai-breakdown > div:last-child { border-bottom: 0; padding-bottom: 0 }
.ai-breakdown dt { font-weight: 700; color: var(--text) }
.ai-breakdown dd { color: var(--text-2); line-height: 1.6 }

@media (max-width: 480px) {
  .ai-breakdown > div { grid-template-columns: minmax(0, 1fr); gap: 2px }
}

/* ── the call ── */
.ai-score {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-bottom: 18px;
}

.ai-score-n {
  min-width: 84px;
  padding: 8px 0;
  border-radius: 14px;
  background: #0B3D25;
  color: #fff;
  font-family: 'Archivo', sans-serif;
  font-weight: 900;
  font-size: 52px;
  line-height: 1.15;
  text-align: center;
}

.ai-score-sep {
  font-family: 'Archivo', sans-serif;
  font-weight: 900;
  font-size: 34px;
  color: var(--text-3);
}

.ai-probs {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
  list-style: none;
}

.ai-prob {
  padding: 10px 12px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--bg-2);
}

.ai-prob.is-pick {
  border-color: var(--primary);
  background: var(--primary-light);
}

.ai-prob-label {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  font-size: 12px;
  color: var(--text-3);
}

.ai-prob.is-pick .ai-prob-label { color: var(--primary-dark) }

.ai-prob-pick {
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--primary);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
}

.ai-prob-value {
  display: block;
  margin-top: 2px;
  font-family: 'Archivo', sans-serif;
  font-weight: 800;
  font-size: 24px;
  color: var(--text);
}

.ai-summary-h {
  margin: 18px 0 8px;
  font-size: 13px;
  font-weight: 700;
  color: var(--text-3);
}

.ai-summary { font-size: 14px; line-height: 1.7; color: var(--text-2) }
.ai-summary-lead { color: var(--text); font-weight: 600 }

/* ── settled table ── */
/* On a phone the table (min 560px) is wider than the card, and the cut falls
   cleanly between columns, so nothing looks unfinished. The scrollbar cannot
   carry the hint on its own either: iOS Safari hides it until touched and
   ignores custom styling. So the edges say it instead, with no JS:
   the two `scroll` radial shadows stay pinned to the wrapper's edges, and the
   two `local` white covers ride along with the content and sit on top of them.
   At the start the left cover hides the left shadow and the right one shows;
   scrolled to the end, the reverse. Where the table fits (desktop) both covers
   land on both shadows, and nothing shows. */
.ai-table-wrap {
  overflow-x: auto;
  overscroll-behavior-x: contain;   /* a swipe at the end must not become "back" */
  background:
    linear-gradient(to right, var(--bg) 30%, rgba(255, 255, 255, 0)) left center / 40px 100% no-repeat local,
    linear-gradient(to left, var(--bg) 30%, rgba(255, 255, 255, 0)) right center / 40px 100% no-repeat local,
    radial-gradient(farthest-side at 0 50%, rgba(0, 0, 0, .14), rgba(0, 0, 0, 0)) left center / 16px 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%, rgba(0, 0, 0, .14), rgba(0, 0, 0, 0)) right center / 16px 100% no-repeat scroll;
  background-color: var(--bg);
  /* The site's scrollbar (site.css) is a grey --bg-3 thumb that turns --primary
     only on hover, and touch cannot hover, so here the green is the resting
     state. Chrome 121+ and Firefox read these two; with them present Chrome
     ignores the -webkit- rules below, which are for Safari. */
  scrollbar-width: thin;
  scrollbar-color: var(--primary) var(--bg-2);
}

.ai-table-wrap::-webkit-scrollbar { height: 6px }
.ai-table-wrap::-webkit-scrollbar-track { background: var(--bg-2); border-radius: 999px; margin: 0 14px }
.ai-table-wrap::-webkit-scrollbar-thumb { background: var(--primary); border-radius: 999px }

.ai-table {
  width: 100%;
  min-width: 560px;
  border-collapse: collapse;
  font-size: 14px;
}

.ai-table th {
  padding: 12px 16px;
  text-align: left;
  font-size: 12px;
  font-weight: 700;
  color: var(--text-3);
  background: rgba(5, 38, 88, .06);   /* = --bg-2 over the white card, see .ai-table-wrap */
  white-space: nowrap;
}

/* The wrap scrolls horizontally, so it can't clip with overflow:hidden — the
   two outer header cells round themselves into the card corners instead. */
.ai-table th:first-child { border-top-left-radius: var(--radius-lg) }
.ai-table th:last-child { border-top-right-radius: var(--radius-lg) }

.ai-table td {
  padding: 14px 16px;
  border-top: 1px solid var(--border);
  color: var(--text-2);
}

.ai-td-match { color: var(--text); font-weight: 600 }

.ai-hit {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--primary-light);
  color: var(--primary-dark);
  font-size: 12px;
  font-weight: 700;
}

.ai-hit.is-miss { background: #FBECEA; color: var(--red-dark) }

/* ── strike rate ── */
.ai-rank { list-style: none; display: grid; gap: 10px }

.ai-rank-row {
  display: grid;
  grid-template-columns: 28px 40px minmax(0, 1fr) minmax(80px, 200px) 56px;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.ai-rank-pos {
  font-family: 'Archivo', sans-serif;
  font-weight: 800;
  font-size: 18px;
  color: var(--text-3);
  text-align: center;
}

.ai-rank-row img { width: 40px; height: 40px; object-fit: contain }

.ai-rank-name { font-weight: 700; font-size: 15px; color: var(--text) }
.ai-rank-name small { display: block; font-weight: 400; font-size: 12px; color: var(--text-3) }

.ai-rank-bar {
  height: 8px;
  border-radius: 999px;
  background: var(--bg-3);
  overflow: hidden;
}

.ai-rank-bar > span { display: block; height: 100%; background: var(--ai-accent) }

.ai-rank-rate {
  font-family: 'Archivo', sans-serif;
  font-weight: 800;
  font-size: 18px;
  text-align: right;
  color: var(--text);
}

@media (max-width: 620px) {
  .ai-rank-row { grid-template-columns: 24px 34px minmax(0, 1fr) 52px }
  .ai-rank-bar { grid-column: 1 / -1 }
}

.ai-disclaimer {
  margin-top: 28px;
  padding-top: 18px;
  border-top: 1px solid var(--border);
  font-size: 12px;
  line-height: 1.7;
  color: var(--text-3);
  text-align: center;
}

/* ── signed-out gate ──
   The blur is cosmetic and nothing depends on it: the cards underneath render
   in full and devtools clears both layers in seconds. See the note on $gated in
   page-ai-prediction.php before treating this as a paywall. */
.ai-veil {
  filter: blur(6px);
  user-select: none;
  pointer-events: none;
}

.ai-gate {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}

.ai-gate-panel {
  width: min(100%, 520px);
  padding: 26px 28px;
  border-radius: var(--radius-lg);
  background: var(--bg);
  box-shadow: 0 10px 40px rgba(0, 0, 0, .16);
  text-align: center;
}

.ai-gate-title {
  font-size: 16px;
  font-weight: 600;
  color: var(--text);
  margin-bottom: 18px;
}

.ai-gate-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px;
}

.ai-gate-btn {
  flex: 1 1 180px;
  max-width: 240px;
  padding: 13px 20px;
  border-radius: 999px;
  background: var(--primary);
  color: #fff;
  font-size: 15px;
  font-weight: 700;
  text-decoration: none;
  transition: background .15s ease;
}

.ai-gate-btn:hover { background: var(--primary-dark) }

@media (prefers-reduced-motion: reduce) {
  .ai-gate-btn { transition: none }
}

@media (max-width: 420px) {
  .ai-gate-panel { padding: 20px }
  .ai-gate-btn { flex-basis: 100%; max-width: none }
}


/* ── AI Prediction page, dark ──
   The one dark page on the site. functions.php adds body.ai-dark on it. The
   tokens are remapped on the page's own sections, not on body, so the shared
   header and footer keep the light shell. Nearly every AI rule reads a token,
   so remapping the tokens here does most of the work — the rules below that
   are only the hardcoded colours the tokens can't reach. Greens: --primary
   #009E4F is 4.6:1 on --bg, fine for the 26px+ stat values and headings, so
   small green text (meta, kicker, links) takes --primary-on-dark instead. */
.ai-dark .ai-hero,
.ai-dark .ai-sec {
  --bg: #121A1C;
  --bg-2: #0B1211;
  --bg-3: #1C2725;
  --border: rgba(255, 255, 255, .10);
  --border-2: rgba(255, 255, 255, .18);
  --text: #F2F5F3;
  --text-2: #C3CBC6;
  --text-3: #93A09A;
  --primary-light: rgba(0, 158, 79, .16);
  --primary-on-dark: #3FCB7A;
  --shadow: 0 2px 14px rgba(0, 0, 0, .45);
  --shadow-md: 0 6px 28px rgba(0, 0, 0, .55);
  color-scheme: dark;
}

.ai-dark, .ai-dark::before { background: #0B1211 }

/* hero: the art is dense edge to edge, so a left-heavy scrim buys the copy its
   contrast; it clears by 70% so the brain stays at full strength. */
.ai-dark .ai-hero { background-color: #061410 }
.ai-dark .ai-hero::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, rgba(4, 16, 11, .92) 0%, rgba(4, 16, 11, .72) 40%, rgba(4, 16, 11, 0) 70%);
}
.ai-dark .ai-title { color: #fff }
/* the zh title's ball mark: green art turned white to match the headline */
.ai-dark .ai-title-a::after { filter: brightness(0) invert(1) }
.ai-dark .ai-lede { color: rgba(255, 255, 255, .8) }
.ai-dark .ai-hero .sp-crumb { color: rgba(255, 255, 255, .6) }
.ai-dark .ai-hero .sp-crumb a { color: rgba(255, 255, 255, .75) }
.ai-dark .ai-hero .sp-crumb a:hover,
.ai-dark .ai-hero .sp-crumb span:last-child { color: #fff }

.ai-dark .ai-stat {
  background: rgba(10, 22, 18, .72);
  border: 1px solid rgba(255, 255, 255, .12);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.ai-dark .ai-stat-value { color: var(--primary-on-dark) }
.ai-dark .ai-stat-label { color: rgba(255, 255, 255, .6) }
.ai-dark .ai-stat-note { color: rgba(255, 255, 255, .7) }

/* small green text */
.ai-dark .ai-sub,
.ai-dark .ai-note a,
.ai-dark .ai-model-eyebrow,
.ai-dark .ai-model-meta,
.ai-dark .ai-prob.is-pick .ai-prob-label,
.ai-dark .ai-hit { color: var(--primary-on-dark) }

/* model cards: PHP hands each card a pastel --ai-tint; on dark the tint is the
   accent itself at low alpha, and the accent brightens so it clears AA. */
.ai-dark .ai-model {
  background: color-mix(in srgb, var(--ai-accent) 12%, var(--bg));
  border-color: color-mix(in srgb, var(--ai-accent) 30%, transparent);
}
.ai-dark .ai-model-eyebrow,
.ai-dark .ai-model-meta { color: color-mix(in srgb, var(--ai-accent) 55%, #fff) }
.ai-dark .ai-rank-bar > span { background: color-mix(in srgb, var(--ai-accent) 70%, #fff) }

/* tabs: the strip goes to a surface, the live tab to green on dark */
.ai-dark .ai-tabs { background: var(--bg-3); border: 1px solid var(--border) }
.ai-dark .ai-tab { color: var(--text-2) }
.ai-dark .ai-tab:hover { color: var(--text) }
.ai-dark #ai-t-settled:checked  ~ .ai-tabs .ai-tab[for="ai-t-settled"],
.ai-dark #ai-t-accuracy:checked ~ .ai-tabs .ai-tab[for="ai-t-accuracy"] {
  background: var(--primary-dark);
  color: #fff;
}

/* the call */
.ai-dark .ai-score-n { background: var(--primary-dark) }
.ai-dark .ai-prob.is-pick { border-color: var(--primary-on-dark) }

/* settled table: the header tint was navy-over-white; the miss badge a pink */
.ai-dark .ai-table th { background: rgba(255, 255, 255, .05) }
.ai-dark .ai-hit.is-miss { background: rgba(255, 59, 48, .16); color: #FF7A72 }

/* gate: the blurred card behind it is dark now, so the panel needs an edge */
.ai-dark .ai-gate-panel { border: 1px solid var(--border-2); box-shadow: 0 10px 40px rgba(0, 0, 0, .6) }

/* ── hero layout (.hA) ──
   The one hero left from the ?hero= comparison. It unfixes .ai-hero's height
   because the pick card + stats column is taller than the old fixed band. */

.hA { height: auto }
.hA .ai-hero-inner { height: auto; min-height: 520px; padding-top: 40px }


/* A: copy + a prediction panel */
.hA-inner { grid-template-columns: minmax(0, 1fr) 350px; gap: 32px }
.hA-panel {
  justify-self: end; width: min(100%, 360px);
  padding: 18px 20px; border-radius: var(--radius-lg);
  background: rgba(10, 22, 18, .78); border: 1px solid rgba(255,255,255,.14);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  color: #fff;
}
.hA-panel-h { display: flex; align-items: center; justify-content: space-between; gap: 12px; font-size: 13px; font-weight: 700; color: rgba(255,255,255,.85) }
.hA-panel-h svg { width: 90px; height: 24px; color: var(--primary-on-dark) }
.hA-probs { display: grid; gap: 12px; margin: 18px 0 }
.hA-probs > div { display: grid; grid-template-columns: 64px minmax(0, 1fr); align-items: center; gap: 12px; font-size: 13px }
.hA-probs dt { color: rgba(255,255,255,.75) }
.hA-probs dd { display: flex; align-items: center; gap: 10px; margin: 0 }
.hA-probs b { min-width: 38px; text-align: right; font-family: 'Archivo', sans-serif; font-weight: 800 }
.hA-bar { flex: 1; height: 8px; border-radius: 999px; background: rgba(255,255,255,.12); overflow: hidden }
.hA-bar > span { display: block; height: 100%; border-radius: inherit; background: var(--primary) }
.hA-probs > div:first-child .hA-bar > span { background: var(--primary-on-dark) }
.hA-vs { display: flex; align-items: center; justify-content: center; gap: 16px; padding-top: 14px; border-top: 1px solid rgba(255,255,255,.12); font-size: 12px; font-weight: 700; color: rgba(255,255,255,.7) }
.hA-vs b { color: var(--primary-on-dark) }

.hA-stats { position: relative; z-index: 1; padding-top: 0 }
.hA-stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; padding-bottom: 20px }
.hA-stat { display: flex; align-items: center; gap: 12px; color: #fff }
.hA-stat-icon { flex-shrink: 0; width: 42px; height: 42px; border-radius: 50%; display: grid; place-items: center; background: rgba(0,158,79,.18); color: var(--primary-on-dark) }
.hA-stat-icon svg { width: 22px; height: 22px }
.hA-stat b { display: block; font-family: 'Archivo', sans-serif; font-weight: 800; font-size: 24px; line-height: 1.1 }
.hA-stat small { display: block; margin-top: 2px; font-size: 12px; color: rgba(255,255,255,.65) }

/* B: current headline, stat cards with icons, feature row */
/* Player sits right of centre in the art; pushing the crop right keeps his head
   out from under the stat cards at desktop widths. */
.hB-stats { align-self: end; margin-bottom: 8px }


/* C: centered copy over the stadium, stats band at the foot, features below */

@media (max-width: 1024px) {
  .hA-inner { grid-template-columns: minmax(0, 1fr) }
  .hA-panel { justify-self: stretch; width: 100% }
}
@media (max-width: 620px) {
  .hA-stats { grid-template-columns: minmax(0, 1fr) }
}

/* ── the right column: one HUD stack on a subtle perspective plane ──
   A nearly front-facing vertical HUD stack mapped onto one subtle perspective
   plane. The 3D feeling comes from the whole group's placement in the scene,
   not from rotating or extruding any card: the group turns 5° on Y (right edge
   receding a touch) and 1.5° on X so the column follows the stadium's
   vanishing point, and every card stays a flat rectangle of the same width,
   radius and spacing on that one plane. Surfaces are dark black-green glass
   with a thin muted green outline, a soft emerald top edge, a faint diagonal
   reflection and an ambient shadow. The chart sits under the cards with no
   container of its own. All of it drops below 1024px, where the column sits
   under the copy. */
.hA-inner { perspective: 1400px; perspective-origin: 50% 50% }

.hA-panel,
.hB-stats {
  transform: rotateY(5deg) rotateX(1.5deg);
  transform-origin: center;
}
/* Only A floats: B's background is the video, and a panel drifting over a
   moving scene reads as two unrelated motions. */
/* No float on either: both backgrounds are video now. */
.hB-stats { gap: 10px; margin-right: 4px }

.hA-panel,
.hB-stats .ai-stat {
  border-radius: 8px;
  background:
    linear-gradient(118deg, rgba(255, 255, 255, .07) 0%, rgba(255, 255, 255, 0) 38%),
    rgba(4, 14, 10, .7);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  border: 1px solid rgba(63, 203, 122, .3);
  box-shadow:
    inset 0 1px 0 rgba(120, 230, 160, .3),   /* emerald edge light */
    0 1px 2px rgba(0, 0, 0, .5),
    0 10px 24px rgba(0, 0, 0, .42),          /* ambient shadow */
    0 0 10px rgba(0, 158, 79, .1);
}
/* the chart: part of the same composition, no container */

@keyframes ai-float {
  0%, 100% { translate: 0 0 }
  50%      { translate: 0 -4px }
}
@media (prefers-reduced-motion: reduce) { .hA-panel, .hB-stats { animation: none } }
@media (max-width: 1024px) {
  .hA-inner { perspective: none }
  .hA-panel, .hB-stats { transform: none; animation: none }
}

/* ── hero HUD: U-Bao's pick + KPI strip ──
   One column on the shared perspective plane (.hB-stats). The pick card is the
   hero element; the three KPIs sit under it in one row. Bars are the site's
   verdict-first pattern: the called outcome is the only filled column and it
   carries the label, never colour alone. */
.hud { display: flex; flex-direction: column; gap: 12px }
.hud-pick { text-align: left; padding: 18px 20px 16px }
.hud-eyebrow {
  display: flex; justify-content: space-between; align-items: center; gap: 10px;
  margin: 0 0 12px;
  font-size: 12px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--primary-on-dark);
}
.hud-model { color: rgba(255, 255, 255, .55); letter-spacing: 0; text-transform: none; font-weight: 600 }
.hud-meta { margin: 0 0 10px; font-size: 13px; color: rgba(255, 255, 255, .6) }
.hud-teams { display: flex; align-items: center; justify-content: space-between; gap: 10px; font-size: 16px; font-weight: 700; color: #fff }
.hud-team { display: flex; align-items: center; gap: 6px; min-width: 0 }
.hud-team span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
.hud-team img { width: 30px; height: 30px; object-fit: contain; flex-shrink: 0 }
.hud-teams b { flex-shrink: 0; font-size: 11px; color: var(--primary-on-dark) }
.hud-call { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 12px 0 12px; font-size: 15px; color: #fff }
.hud-badge, .hud-hit {
  padding: 2px 8px; border-radius: 999px;
  font-size: 11px; font-weight: 700;
  background: rgba(0, 158, 79, .18); color: var(--primary-on-dark);
}
.hud-hit.is-miss { background: rgba(255, 59, 48, .16); color: #FF7A72 }
.hud-probs { display: grid; gap: 8px; margin: 0 }
.hud-prob { display: grid; grid-template-columns: 64px minmax(0, 1fr); align-items: center; gap: 10px; font-size: 13px }
.hud-prob dt { color: rgba(255, 255, 255, .6) }
.hud-prob.is-pick dt { color: #fff; font-weight: 700 }
.hud-prob dd { display: flex; align-items: center; gap: 8px; margin: 0 }
.hud-prob b { min-width: 34px; text-align: right; font-family: 'Archivo', sans-serif; font-weight: 800; color: #fff }
.hud-bar { flex: 1; height: 7px; border-radius: 999px; background: rgba(255, 255, 255, .12); overflow: hidden }
.hud-bar > span { display: block; height: 100%; border-radius: inherit; background: rgba(255, 255, 255, .35) }
.hud-prob.is-pick .hud-bar > span { background: var(--primary-on-dark) }
.hud-link { display: inline-block; margin-top: 12px; font-size: 13px; font-weight: 700; color: var(--primary-on-dark); text-decoration: none }
.hud-link:hover { color: #fff }
.hud .uf-empty { padding: 10px 0; font-size: 13px; color: rgba(255, 255, 255, .65); text-align: left }
/* three KPIs in one row: value over a short label */
/* 2x2: three stats, the CTA as the fourth cell. The CTA takes the cards'
   exact box (same radius, a 1px border, stretched to the row) so it reads as
   one of the tiles: label centred, no arrow, no pill. */
.hud-kpis { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px }
.hud-kpis .ai-stat { padding: 14px 10px }
.hud-kpis .ai-stat-value { font-size: 24px }
.hud-cta {
  display: flex; align-items: center; justify-content: center;
  margin: 0; padding: 0 12px; border: 1px solid transparent; border-radius: 8px;
  font-size: 15px; font-weight: 700; white-space: nowrap; animation: none;
}
/* "Start predicting" needs 15px to sit on one line in a ~163px tile;
   开始预测 is four glyphs and keeps the bigger size. */
.hud-cta:lang(zh) { font-size: 18px }
.hud-note { margin: 0; text-align: right; font-size: 13px; font-weight: 700 }
.hud-kpis .ai-stat-label { margin-top: 3px; font-size: 12px; line-height: 1.3; color: rgba(255, 255, 255, .65) }
@media (max-width: 1024px) { .hB-stats.hud { order: 1 } }

/* ── hero ambient video (default, A) ──
   Under the scrim and the copy; the still is its poster. The box keeps the
   source's 1800x770 ratio at the hero's height, so a wide screen gets black
   sides instead of an upscaled, blurred loop, and the edges fade into the
   page. Narrower than that ratio, max-width caps it and cover crops the sides. */
.ai-hero-video {
  position: absolute; top: 0; left: 50%; z-index: 0;
  height: 100%; width: auto; max-width: 100%;
  aspect-ratio: 1800 / 770;
  transform: translateX(-50%);
  object-fit: cover; object-position: center;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 14%, #000 86%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 14%, #000 86%, transparent);
  pointer-events: none;
}
.ai-dark .hA::before, .ai-dark .ai-hero::before { z-index: 1 }
/* Phones and tablets: the hero stacks copy over the pick card and runs far
   taller than the loop, so the loop takes a band at the top instead of being
   blown up over the whole stack, and fades out downward. The desktop scrim is
   left-heavy for a two-column layout; stacked, a vertical one keeps the art
   visible behind the headline and darkens toward the body copy. */
@media (max-width: 1024px) {
  .ai-hero-video {
    height: 560px; width: 100%; max-width: none;
    -webkit-mask-image: linear-gradient(180deg, #000 55%, transparent);
            mask-image: linear-gradient(180deg, #000 55%, transparent);
  }
  .ai-dark .ai-hero::before {
    background: linear-gradient(180deg, rgba(4, 16, 11, .35) 0%, rgba(4, 16, 11, .6) 260px, rgba(4, 16, 11, .82) 480px, rgba(4, 16, 11, .9) 100%);
  }
}

/* ── dashboard widgets in the tabs ── */
.ai-widget { display: block; width: 100%; border: 0; background: transparent }

/* ── language switch ──
   Standalone, not inside the account popup: that popup is hidden wherever the
   dashboard does not exist (UFOOTBALL_AI_LIVE), and it sits outside
   .hdr-nav-right because that is display:none under 640px — so on a phone the
   popup was the only way to change language. With two languages a segmented
   pair beats a disclosure: one tap, and the current one is readable without
   opening anything. */
.lang-pill {
  display: flex;
  align-items: center;
  gap: 2px;
  margin-left: 10px;
  padding: 3px;
  border-radius: 999px;
  background: var(--bg-2);
  flex-shrink: 0;
}

.lang-pill-a {
  display: block;
  padding: 5px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .04em;
  color: var(--text-3);
  text-decoration: none;
  transition: background .15s ease, color .15s ease;
}

.lang-pill-a:hover { color: var(--text) }

/* The active language carries the fill; the other stays quiet. */
.lang-pill-a.on { background: var(--primary); color: #fff }

.lang-pill-a:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px }

@media (prefers-reduced-motion: reduce) {
  .lang-pill-a { transition: none }
}

/* ═══════════════════════════ Motion polish ═══════════════════════════
   One shared timing system for interaction feedback. Principle 6 holds: every
   rule here answers a state change — a press, an open, a data swap, a scroll —
   nothing loops and nothing decorates. Exponential ease-out throughout (no
   bounce), transform/opacity only, and all of it stands down under
   prefers-reduced-motion at the end of this block. */
:root {
  --ease-out: cubic-bezier(.22, 1, .36, 1);
  --dur-press: 120ms;
  --dur-state: 200ms;
  --dur-swap: 280ms;
}

/* 1. Press feedback — controls give slightly under the finger, so a tap on a
   phone at 1am reads as registered before the data arrives. */
.uf-daynav, .uf-seg-btn, .np-tab, .ml-tab, .lang-pill-a, .bn-item,
.np-sub button, .np-pager .page-numbers, .nav-drop-d > summary {
  transition:
    background-color var(--dur-state) var(--ease-out),
    color var(--dur-state) var(--ease-out),
    border-color var(--dur-state) var(--ease-out),
    box-shadow var(--dur-state) var(--ease-out),
    transform var(--dur-press) var(--ease-out);
}
.uf-daynav:active, .uf-seg-btn:active, .np-tab:active, .ml-tab:active,
.lang-pill-a:active, .bn-item:active, .np-sub button:active,
.np-pager .page-numbers:active, .nav-drop-d > summary:active { transform: scale(.96) }

/* 2. Standings / Scorers / Assists — the active pill slides to the tab you
   picked instead of blinking across. The thumb is the old .on surface moved to
   a pseudo-element; browsers without :has keep the original blink. */
@supports selector(:has(*)) {
  .uf-seg { position: relative; isolation: isolate }
  .uf-seg::before {
    content: ''; position: absolute; z-index: -1; top: 3px; bottom: 3px; left: 3px;
    width: calc((100% - 10px) / 3);
    border-radius: 8px;
    background: var(--bg);
    box-shadow: 0 1px 3px rgba(0, 0, 0, .08);
    transition: transform var(--dur-swap) var(--ease-out);
  }
  .uf-seg:has(.uf-seg-btn:nth-child(2).on)::before { transform: translateX(calc(100% + 2px)) }
  .uf-seg:has(.uf-seg-btn:nth-child(3).on)::before { transform: translateX(calc(200% + 4px)) }
  .uf-seg-btn.on { background: transparent; box-shadow: none }
}

/* 3. Data lands — when the table arrives (after the skeleton) or a tab swaps
   it, rows settle in top-down instead of snapping. League paging keeps its own
   slide; app.js only adds .uf-rows-in on the non-sliding path. */
@keyframes uf-row-in { from { opacity: 0; transform: translateY(4px) } }
.uf-rows-in tbody tr, .uf-rows-in .ps-row { animation: uf-row-in var(--dur-swap) var(--ease-out) backwards }
.uf-rows-in tbody tr:nth-child(2), .uf-rows-in .ps-row:nth-child(2) { animation-delay: 20ms }
.uf-rows-in tbody tr:nth-child(3), .uf-rows-in .ps-row:nth-child(3) { animation-delay: 40ms }
.uf-rows-in tbody tr:nth-child(4), .uf-rows-in .ps-row:nth-child(4) { animation-delay: 60ms }
.uf-rows-in tbody tr:nth-child(5), .uf-rows-in .ps-row:nth-child(5) { animation-delay: 80ms }
.uf-rows-in tbody tr:nth-child(n+6), .uf-rows-in .ps-row:nth-child(n+6) { animation-delay: 100ms }

/* 4. Menus (Leagues, account) drop in from their trigger rather than popping. */
@keyframes uf-menu-in { from { opacity: 0; transform: translateY(-4px) } }
.nav-drop-d[open] > .nav-drop-menu { animation: uf-menu-in var(--dur-state) var(--ease-out) }

/* 5. Header — .hdr.scrolled (frosted, soft shadow) was in site.css but nothing
   ever set it; footer.php now toggles it past the first few pixels. */
.hdr { transition: background-color var(--dur-state) var(--ease-out), box-shadow var(--dur-state) var(--ease-out) }

/* 6. News imagery — one consistent hover across the homepage, news index and
   related cards (the match page's .mp-news-card already did this): the photo
   eases in 4%, the frame stays put. Pointer devices only. */
.np-feat-img { overflow: hidden }
@media (hover: hover) {
  .tn2-feat-img img, .tn2-card-img img, .np-feat-img img { transition: transform 420ms var(--ease-out) }
  .tn2-feat-img:hover img, .tn2-card:hover .tn2-card-img img, .np-feat-img:hover img { transform: scale(1.04) }
}

@media (prefers-reduced-motion: reduce) {
  .uf-seg::before, .hdr,
  .tn2-feat-img img, .tn2-card-img img, .np-feat-img img { transition: none }
  .uf-daynav:active, .uf-seg-btn:active, .np-tab:active, .ml-tab:active,
  .lang-pill-a:active, .bn-item:active, .np-sub button:active,
  .np-pager .page-numbers:active, .nav-drop-d > summary:active,
  .tn2-feat-img:hover img, .tn2-card:hover .tn2-card-img img, .np-feat-img:hover img { transform: none }
  .uf-rows-in tbody tr, .uf-rows-in .ps-row, .nav-drop-d[open] > .nav-drop-menu { animation: none }
}

/* ─────────── Motion polish — rest of the site ───────────
   Same timing system as the block above, carried to articles, the news index,
   category pages, the match page and About, so no page feels like it was left
   behind. Still only hovers and presses — nothing moves on its own. */

/* Hover colour changes ease instead of snapping. */
.np-trow-title, .sp-tag, .sp-soc, .sp-cat-pill, .ab-cta-btn, .ct-srow,
.ct-row-title a, .ct-crumb a, .tn2-feat-title a, .tn2-card-title a, .np-feat-title a {
  transition:
    color var(--dur-state) var(--ease-out),
    border-color var(--dur-state) var(--ease-out),
    background-color var(--dur-state) var(--ease-out),
    filter var(--dur-state) var(--ease-out),
    transform var(--dur-press) var(--ease-out);
}

/* The same give under the finger as the homepage controls. The hero CTA lifts
   1px on hover (site.css); pressing settles it back down. */
.sp-tag:active, .sp-soc:active, .sp-cat-pill:active, .ab-cta-btn:active { transform: scale(.96) }
.hero-cta:active { transform: translateY(0) scale(.98) }

/* Article thumbnails — the Trending list (most pages) and category rows get the
   same 4% photo ease as the news cards. Frames clip so the image never spills. */
.ct-row-img { display: block; overflow: hidden; border-radius: 10px }
.ct-srow-thumb { overflow: hidden; border-radius: 8px }
@media (hover: hover) {
  .np-trow-thumb img, .ct-row-img img, .ct-srow-thumb img { transition: transform 420ms var(--ease-out) }
  .np-trow:hover .np-trow-thumb img, .ct-row:hover .ct-row-img img,
  .ct-srow:hover .ct-srow-thumb img { transform: scale(1.04) }
}

@media (prefers-reduced-motion: reduce) {
  .np-trow-title, .sp-tag, .sp-soc, .sp-cat-pill, .ab-cta-btn, .ct-srow,
  .ct-row-title a, .ct-crumb a, .tn2-feat-title a, .tn2-card-title a, .np-feat-title a,
  .np-trow-thumb img, .ct-row-img img, .ct-srow-thumb img { transition: none }
  .sp-tag:active, .sp-soc:active, .sp-cat-pill:active, .ab-cta-btn:active, .hero-cta:active,
  .np-trow:hover .np-trow-thumb img, .ct-row:hover .ct-row-img img,
  .ct-srow:hover .ct-srow-thumb img { transform: none }
}

/* The league you're reading, marked inside the Leagues menu (header.php). */
.nav-drop-a.on { background: var(--bg-2); color: var(--primary-dark, #007A3D); font-weight: 600 }

/* Scorers / assists avatar (app.js playerAvatar): the player's headshot in the
   round .ps-avatar slot, club crest as a small badge on its corner. The photos
   come on white, so the circle gets a white ground and a hairline to sit on the
   grey row. */
.ps-face { position: relative; flex-shrink: 0; width: 40px; height: 40px }
.ps-face .ps-avatar {
  display: block; width: 40px; height: 40px; border-radius: 50%; overflow: hidden;
  background: #fff; box-shadow: 0 0 0 1px var(--border);
}
/* display:block is the fix: the slot is a <span>, inline by default, so the
   site.css .ps-avatar width/height/radius never applied and photos rendered square. */
.ps-face .ps-avatar img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: 50% 20% }
.ps-club {
  position: absolute; right: -4px; bottom: -4px;
  width: 20px; height: 20px; padding: 2px;
  border-radius: 50%; background: #fff; box-shadow: 0 0 0 1px var(--border);
  object-fit: contain;
}
/* No headshot: the crest takes the whole circle and the badge would repeat it. */
.ps-face.is-crest .ps-avatar img { object-fit: contain; padding: 5px }
.ps-face.is-crest .ps-club { display: none }
