/* ============================================================
   PACY — FOCUS CARDS
   ------------------------------------------------------------
   Two large cards per row on desktop, one on mobile. Deliberately
   large: the promise is understanding a match in three seconds,
   which a dense table cannot deliver however much it fits.
   ============================================================ */

.match-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(440px, 1fr));
  gap: var(--s-5);
}
/* Each card is its own height.
   Grid rows stretch to the tallest item by default, which equalised a row
   at the cost of padding shorter cards with blank space. Expanding one card
   then grew its neighbours with it, so opening one match looked like opening
   the three beside it. Doing this only while something is expanded traded
   that for a different surprise — the neighbours visibly shrank the moment
   you clicked. A card is now always the size of what is in it. */
.match-grid { align-items: start; }

/* --- competition grouping ------------------------------------ */
.comp-group + .comp-group { margin-top: var(--s-8); }

/* Long scoreboards stay quick: sections outside the viewport are painted
   only as the user approaches them, while their space remains reserved. */
@supports (content-visibility: auto) {
  .comp-group {
    content-visibility: auto;
    contain-intrinsic-size: auto 560px;
  }
}

.comp-head {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding-bottom: var(--s-3);
  margin-bottom: var(--s-4);
  border-bottom: 1px solid var(--surface-line);
  transition: border-color var(--d-med) var(--ease-out);
}
.comp-head .crest {
  width: 26px; height: 26px; flex: none;
  transition: transform var(--d-med) var(--ease-out),
              filter var(--d-med) var(--ease-out);
}
.comp-head h3 {
  font-size: var(--t-h3);
  font-family: var(--font-display);
}
.comp-head .country {
  font-size: var(--t-meta);
  color: var(--ink-soft);
}
.comp-head .count {
  margin-inline-start: auto;
  font-size: var(--t-meta);
  color: var(--ink-faint);
}

/* --- the card ------------------------------------------------ */
.card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--surface-line);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-1);
  overflow: hidden;
  /* Grid rows stretch to the tallest card. Without this the extra
     height lands after the footer as dead space; the body absorbs
     it instead and the footer stays pinned to the bottom edge. */
  display: flex;
  flex-direction: column;
  transition: box-shadow var(--d-med) var(--ease-out),
              border-color var(--d-med) var(--ease-out),
              transform var(--d-med) var(--ease-out);
}
.card-body { flex: 1 1 auto; }
.card-foot { margin-top: auto; }
.card:focus-within { border-color: var(--blue-300); }

/* A soft pointer-only lift gives the board depth without adding work while
   the page is scrolling. The sheen moves on the compositor and never loops. */
.card-glow,
.card-sheen {
  position: absolute;
  z-index: 0;
  pointer-events: none;
}
.card-glow {
  inset: 0;
  opacity: 0;
  background: radial-gradient(circle 190px at var(--glow-x, 50%) var(--glow-y, 35%),
    rgba(72, 139, 255, .19), transparent 72%);
  transition: opacity var(--d-med) var(--ease-out);
}
.card-sheen {
  inset-block: -35%;
  inset-inline-start: -55%;
  width: 42%;
  opacity: 0;
  transform: translate3d(-30%, 0, 0) skewX(-17deg);
  background: linear-gradient(90deg,
    transparent, rgba(86, 151, 255, .12) 28%,
    rgba(255, 255, 255, .48) 50%, rgba(86, 151, 255, .14) 72%, transparent);
  filter: blur(1px);
  transition: opacity 120ms var(--ease-out), transform 680ms var(--ease-out);
}
/* Raise only the permanent structure. Temporary goal/reveal overlays are
   deliberately excluded so their absolute positioning remains untouched. */
.card-top,
.card-body,
.card-expand,
.card-foot { position: relative; z-index: 1; }

@property --circuit-angle {
  syntax: "<angle>";
  initial-value: 0deg;
  inherits: false;
}
.card:not(.reveal):not(.pulse)::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 4;
  padding: 2px;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  background: conic-gradient(from var(--circuit-angle),
    transparent 0 66%, var(--electric) 76%, var(--bolt-core) 82%,
    var(--white) 85%, var(--bolt-hot) 89%, transparent 96%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
}

@media (hover: hover) and (pointer: fine) {
  .card:not(.reveal):hover {
    transform: perspective(900px) translate3d(0, -8px, 0)
               rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) scale(1.012);
    box-shadow: 0 22px 52px rgba(1, 15, 35, .2),
                0 0 0 1px rgba(37, 99, 235, .12);
    border-color: color-mix(in srgb, var(--electric) 42%, var(--surface-line-strong));
  }
  .card:hover .card-glow { opacity: 1; }
  .card:hover .card-sheen {
    opacity: .8;
    transform: translate3d(390%, 0, 0) skewX(-17deg);
  }
  .card:hover .competitor .crest { transform: translate3d(0, -1px, 0) scale(1.055); }
  .card:hover .score-value { transform: translate3d(2px, 0, 0); }
  .card:hover .expand-btn[href] svg { transform: translateX(3px); }
  .card:active { transform: translate3d(0, -1px, 0) scale(.998); }
  .card:not(.reveal):not(.pulse):hover::after {
    animation: cardCircuit 900ms var(--ease-out) both;
  }
  .comp-group:hover > .comp-head { border-color: var(--blue-300); }
  .comp-group:hover > .comp-head .crest {
    transform: scale(1.08);
    filter: drop-shadow(0 4px 8px rgba(37, 99, 235, .2));
  }
}
@keyframes cardCircuit {
  0% { --circuit-angle: 0deg; opacity: 0; }
  12%, 72% { opacity: 1; }
  100% { --circuit-angle: 360deg; opacity: .22; }
}

/* A live card earns one quiet signal: a coloured top edge. Not a
   permanent glow — that would make every live card shout. */
.card[data-status="live"]::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  height: 3px;
  background: linear-gradient(90deg, var(--live), #FF7A5C);
  z-index: 3;
}
.card[data-status="postponed"],
.card[data-status="cancelled"],
.card[data-status="suspended"] { background: var(--surface-sunk); }

.card-top {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-4) var(--s-5) var(--s-3);
  font-size: var(--t-meta);
  color: var(--ink-soft);
  min-width: 0;
}
.card-top .comp-crest { width: 20px; height: 20px; flex: none; border-radius: 4px; }
.card-top .comp-name {
  font-weight: 600;
  color: var(--ink-mid);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.card-top .sep { color: var(--ink-faint); }
.card-top .card-status { margin-inline-start: auto; flex: none; }

/* --- teams + score ------------------------------------------- */
.card-body { padding: var(--s-2) var(--s-5) var(--s-5); }

.matchup {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: var(--s-4);
}

.competitors { display: grid; gap: var(--s-3); min-width: 0; }

.competitor {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  min-width: 0;
  /* Reserve the crest's height so a one-line and a two-line name
     produce the same row height, keeping the two sides aligned. */
  min-height: 38px;
}
.competitor .crest {
  width: 38px; height: 38px;
  flex: none;
  border-radius: 8px;
  object-fit: contain;
  image-rendering: auto;
  transition: transform var(--d-med) var(--ease-out),
              filter var(--d-med) var(--ease-out);
}
/* Team names wrap rather than truncate. "Golden State Warriors"
   ellipsised to "Golden State Warr…" fails the three-second
   promise, so the name is allowed a second line and the row grows
   instead. Two lines is the ceiling — beyond that the card starts
   losing its shape. */
.competitor .name {
  font-family: var(--font-display);
  font-size: var(--t-team);
  font-weight: 600;
  letter-spacing: -.01em;
  line-height: 1.18;
  min-width: 0;
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* The loser of a finished match recedes; the winner does not
   need a trophy icon to be obvious. */
.card[data-status="finished"] .competitor:not(.is-winner) .name,
.card[data-status="finished"] .competitor:not(.is-winner) .score-value { color: var(--ink-soft); }
.competitor.is-winner .name { font-weight: 700; }

.competitor .meta {
  font-size: var(--t-meta);
  color: var(--ink-soft);
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin-top: 2px;
}

/* Serving / possession indicator, shared across sports. */
.poss {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--electric);
  flex: none;
}

.scores {
  display: grid;
  gap: var(--s-3);
  text-align: end;
  justify-items: end;
}
.score-value {
  font-family: var(--font-display);
  font-size: var(--t-score);
  transition: transform var(--d-med) var(--ease-out),
              color var(--d-med) var(--ease-out);
  font-weight: 700;
  line-height: var(--lh-tight);
  letter-spacing: -.03em;
  color: var(--ink);
  /* Reserve the width of two digits so a 9 → 10 change does not
     reflow the row. */
  min-width: 1.6ch;
  text-align: end;
  display: block;
}
.score-value.pending { color: var(--ink-faint); font-size: var(--t-score-sm); }

/* Kickoff time replaces the score before a match starts. */
.kickoff {
  text-align: end;
}
/* A kickoff time is not a score and should not compete with one
   for size — at score scale, "05:52 AM" swallowed half the card
   on mobile. */
.kickoff .time {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 1.2rem + 1vw, 2rem);
  font-weight: 700;
  letter-spacing: -.02em;
  display: block;
  line-height: 1.15;
  white-space: nowrap;
}
.kickoff .tz {
  font-size: var(--t-meta);
  color: var(--ink-soft);
}

/* --- spoiler-protected score --------------------------------- */
.spoiler-hidden .scores,
.spoiler-hidden .sport-module,
.spoiler-hidden .last-event { filter: blur(9px); pointer-events: none; user-select: none; }
.spoiler-reveal {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-end: var(--s-5);
  transform: translateY(-50%);
  z-index: 2;
  background: var(--surface);
  border: 1px solid var(--surface-line-strong);
  border-radius: var(--r-md);
  padding: var(--s-2) var(--s-4);
  font-size: var(--t-meta);
  font-weight: 600;
  min-height: 40px;
  box-shadow: var(--sh-2);
}

/* --- sport module (the per-sport strip) ---------------------- */
.sport-module {
  margin-top: var(--s-4);
  padding-top: var(--s-4);
  border-top: 1px solid var(--surface-line);
  display: flex;
  align-items: center;
  gap: var(--s-4);
  flex-wrap: wrap;
  font-size: var(--t-meta);
  color: var(--ink-mid);
  /* One line of module content, reserved. The server renders this strip
     empty — it knows the match is live but not what the clock reads — and
     the client fills it a moment later. Reserving the line here is what
     keeps that from moving every card below it down the page. */
  min-height: 39px;
}
.mod-item { display: inline-flex; align-items: center; gap: var(--s-2); }
.basketball-state {
  gap: 7px;
  padding: 4px 9px;
  border: 1px solid var(--surface-line);
  border-radius: 999px;
  background: var(--surface-sunk);
}
.basketball-state .period-label {
  font-family: var(--font-display);
  font-weight: 800;
  color: var(--ink);
}
.basketball-state .state-sep { color: var(--ink-faint); }
.mod-item .k {
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--ink-faint);
}
.mod-item .v { font-weight: 600; color: var(--ink); }
.mod-item .v.tnum { font-variant-numeric: tabular-nums; }

.card-prob {
  margin-top: var(--s-4);
  padding-top: var(--s-3);
  border-top: 1px solid var(--surface-line);
  font-size: var(--t-micro);
  color: var(--ink-mid);
  /* Reserved for the same reason as .sport-module: the server knows this
     match will carry a probability, but not what it is. */
  min-height: 85px;
}
.card-prob-title,
.card-prob-head,
.card-prob-labels { display: flex; align-items: center; }
.card-prob-title { gap: 5px; font-weight: 700; color: var(--electric); }
.card-prob-title svg { width: 12px; height: 12px; }
.card-prob-loading { display: block; margin-top: 6px; color: var(--ink-faint); }
.card-prob-head { justify-content: space-between; gap: var(--s-3); }
.card-prob-score { font-weight: 700; color: var(--ink); }
.card-prob-bar {
  display: flex; height: 5px; margin-block: 8px 6px;
  overflow: hidden; border-radius: 999px; background: var(--surface-line);
}
.card-prob-bar i:first-child { background: var(--electric); }
.card-prob-bar i:last-child { background: var(--navy-300); }
.card-prob-labels { justify-content: space-between; font-weight: 700; }
.card-prob-labels span {
  max-width: 48%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.card-prob-labels span:last-child { text-align: end; }

.clock {
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--live);
}

/* --- last event line ----------------------------------------- */
.last-event {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin-top: var(--s-3);
  font-size: var(--t-meta);
  color: var(--ink-mid);
  min-width: 0;
}
.last-event .ev-icon { width: 16px; height: 16px; flex: none; }
.last-event .ev-min {
  font-weight: 700;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.last-event .ev-text {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* --- "why this matters" -------------------------------------- */
/* Only rendered when a match genuinely carries stakes; ordinary
   fixtures are left alone rather than padded with filler. */
.stakes {
  display: flex;
  align-items: flex-start;
  gap: var(--s-3);
  margin-top: var(--s-4);
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-md);
  background: var(--blue-050);
  border-inline-start: 3px solid var(--electric);
  font-size: var(--t-meta);
  color: var(--ink-mid);
  line-height: 1.45;
}
.stakes svg { width: 16px; height: 16px; flex: none; color: var(--electric); margin-top: 2px; }

/* --- card footer --------------------------------------------- */
.card-foot {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding: var(--s-3) var(--s-5);
  border-top: 1px solid var(--surface-line);
  background: var(--surface-sunk);
  font-size: var(--t-meta);
  color: var(--ink-soft);
  /* Wrap to a clean second row when narrow rather than letting the
     button labels break mid-phrase. */
  flex-wrap: wrap;
}
.card-foot .spacer { margin-inline-start: auto; }

.fav-btn {
  width: var(--tap); height: var(--tap);
  display: inline-grid; place-items: center;
  border-radius: var(--r-md);
  color: var(--ink-faint);
  transition: color var(--d-fast) var(--ease-out),
              background var(--d-fast) var(--ease-out);
}
.fav-btn:hover { color: var(--electric); background: var(--blue-050); }
.fav-btn[aria-pressed="true"] { color: var(--electric); }
.fav-btn svg { width: 20px; height: 20px; }

.expand-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  min-height: var(--tap);
  padding-inline: var(--s-3);
  border-radius: var(--r-md);
  font-size: var(--t-meta);
  font-weight: 600;
  color: var(--ink-mid);
  white-space: nowrap;   /* never break a label across lines */
}
.expand-btn:hover { color: var(--ink); background: var(--blue-050); }
.expand-btn svg {
  width: 16px; height: 16px;
  transition: transform var(--d-med) var(--ease-out);
}
.expand-btn[aria-expanded="true"] svg { transform: rotate(180deg); }

/* ============================================================
   LEVEL 2 — INLINE EXPANSION
   Opens in place so the card the user chose stays put.
   ============================================================ */

.card-expand {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--d-slow) var(--ease-out);
}
.card-expand > .inner { overflow: hidden; }
.card[data-expanded="true"] .card-expand { grid-template-rows: 1fr; }

.expand-pad {
  padding: var(--s-5);
  border-top: 1px solid var(--surface-line);
  display: grid;
  gap: var(--s-5);
}

.expand-cols {
  display: grid;
  /* auto-fit rather than a fixed pair: a row holding one block should use the
     width rather than leave half the panel empty beside it. */
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--s-5);
}
.expand-cols + .expand-cols { margin-top: var(--s-5); }

/* --- match facts ---------------------------------------------
   Shown for every match, from data Pacy already holds. */
.fact-list { margin: 0; display: grid; gap: 6px; }
.fact {
  display: grid;
  grid-template-columns: minmax(84px, auto) minmax(0, 1fr);
  gap: var(--s-3);
  font-size: var(--t-meta);
}
.fact dt { color: var(--ink-faint); }
.fact dd { margin: 0; color: var(--ink); text-wrap: pretty; }

.mini-title {
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: var(--s-3);
}

/* recent events */
.ev-list { display: grid; gap: var(--s-3); }
.ev-row {
  display: grid;
  grid-template-columns: 40px 20px 1fr;
  align-items: baseline;
  gap: var(--s-3);
  font-size: var(--t-meta);
}
.ev-row .min { font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; }
.ev-row .who { color: var(--ink-mid); }
.ev-row .who b { color: var(--ink); font-weight: 600; }

/* three key statistics */
.stat-rows { display: grid; gap: var(--s-4); }
.stat-row { font-size: var(--t-meta); }
.stat-row .stat-head {
  display: flex;
  justify-content: space-between;
  margin-bottom: 6px;
}
.stat-row .stat-name { color: var(--ink-soft); }
.stat-value { font-weight: 700; color: var(--ink); }
.stat-bar {
  height: 6px;
  border-radius: var(--r-pill);
  background: var(--surface-line);
  overflow: hidden;
  display: flex;
}
.stat-bar i {
  display: block;
  height: 100%;
  background: var(--electric);
  transition: width var(--d-slow) var(--ease-out);
}
.stat-bar i + i { background: var(--navy-300); }

/* top performers */
.performers { display: grid; gap: var(--s-3); }
/* Two rows per player: who, then what.
   Name, club and stat line competing for one 440px row truncated the club to
   "Pittsb..." and broke ".307 Batting Average" across three lines. Given a
   row each, nothing needs to be cut. */
.performer {
  display: grid;
  grid-template-columns: 30px minmax(0, 1fr);
  column-gap: var(--s-3);
  row-gap: 1px;
  align-items: start;
  font-size: var(--t-meta);
}
.performer .avatar {
  width: 30px; height: 30px;
  border-radius: 50%;
  background: var(--blue-050);
  color: var(--med-blue);
  display: grid; place-items: center;
  font-weight: 700;
  font-size: var(--t-micro);
  flex: none;
}
.performer .avatar { grid-row: span 2; }
.performer .p-who {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 8px;
  min-width: 0;
}
.performer .p-name { font-weight: 600; color: var(--ink); }
/* The club, so a name is attributable to one of the two sides playing. */
.performer .p-team { font-size: var(--t-micro); color: var(--ink-faint); }
.performer .p-line {
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
  text-wrap: pretty;
}

/* form comparison */
.form-compare { display: grid; gap: var(--s-3); }
.form-row { display: flex; align-items: center; gap: var(--s-3); font-size: var(--t-meta); }
.form-row .f-team {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--ink-mid);
}
.form-pips { display: flex; gap: 4px; margin-inline-start: auto; flex: none; }
.pip {
  width: 22px; height: 22px;
  border-radius: 5px;
  display: grid; place-items: center;
  font-size: 11px;
  font-weight: 700;
  color: var(--white);
}
.pip-W { background: var(--good); }
.pip-D { background: var(--ink-faint); }
.pip-L { background: var(--danger); }

.expand-actions { display: flex; gap: var(--s-3); flex-wrap: wrap; }
