/*
 * The fixture page — favourite button, score header, tab bar and the panels
 * behind it. Every tab has a panel now, each in its own stylesheet
 * (`fixture-preview.css`, `fixture-predictions.css`, `fixture-facts.css`,
 * `match-lineup.css`, `fixture-statistics.css`, `fixture-commentary.css`);
 * `.fixture-details__panel-empty` below is kept for the next tab that lands
 * before its panel does.
 *
 * Constrained to the shell width rather than the window, same as the search
 * overlay and the story viewer: on a phone that is genuinely full-bleed, and on
 * desktop it keeps the mini app inside its own frame instead of taking over the
 * browser tab.
 *
 * Two layers, and they stay apart because they animate different properties:
 *
 *   .fixture-details          the fade. Also the ground, so nothing of the page
 *                             behind shows through mid-transition.
 *   .fixture-details__sheet   the travel — a short rise on entry.
 */

.fixture-details {
  /* Distance the sheet rises through on entry. Small on purpose: the page is
     arriving, not being thrown. */
  --enter-y: 12px;

  position: fixed;
  inset: 0;
  /*
   * Under the search overlay's 90 and the story viewer's 100. This page is
   * opened *from* the fixtures list, and both of those cover that list
   * entirely — so neither can be up at the same time as this, and if that ever
   * changes, the surface opened from this one has to win.
   */
  z-index: 80;
  display: flex;
  max-width: var(--app-max-width);
  margin-inline: auto;
  background: var(--bg);
  opacity: 0;
  transition: opacity var(--duration) var(--easing);
}

/* A class beats the UA [hidden] rule, so display has to be turned off by hand. */
.fixture-details[hidden] {
  display: none;
}

.fixture-details[data-open="true"] {
  --enter-y: 0px;

  opacity: 1;
}

.fixture-details__sheet {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  /* Safe-area clearance only, no extra `--space-2` on top of it: this sits
     above the scrolling body, so the sticky tab row (tab-bar.css) sticks
     flush against whatever's left here — any padding beyond the notch/status
     bar itself reads as a gap above it once stuck. `.fixture-details__bar`'s
     own margin-top is what gives the back button its breathing room at
     rest instead. */
  padding-top: var(--safe-top);
  transform: translateY(var(--enter-y));
  transition: transform var(--duration) var(--easing);
}

/* --- Bar ------------------------------------------------------------------ */

/*
 * Leave on the left, act on the right — and no title between them. The header
 * stack below is the page's title; a second one spelling the fixture out in
 * words would say twice what two crests and a scoreline already say once, at
 * the top of a screen the score block is the whole point of.
 */
.fixture-details__bar {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  /* Carries the top spacing `.fixture-details__body` used to reserve for
     every child — moved here, onto the one child that actually scrolls
     away, so the sticky tab row (tab-bar.css) isn't measured against it too
     and left sitting a `--space-4` gap below the top once stuck. */
  margin-top: var(--space-4);
  padding-inline: var(--space-3);
}

.fixture-details__spacer {
  flex: 1;
}

/*
 * .icon-btn is a grey chip built to lift off the white page, which is exactly
 * what all three of these are doing — so unlike the app bar's copy they keep
 * their fill. Only the size comes down, to the 34px the header row already uses.
 */
.fixture-details__back,
.fixture-details__action {
  width: 34px;
  height: 34px;
}

/*
 * Following fills the bell and tints its chip. --accent-soft is the token
 * tokens.css reserves for exactly this, and the accent is what "this one is
 * active" means everywhere else in the app — so a followed match needs no
 * further explanation than the colour it shares with every other selection.
 */
.fixture-details__follow {
  transition:
    background-color var(--duration) var(--easing),
    border-color var(--duration) var(--easing),
    color var(--duration) var(--easing);
}

.fixture-details__follow[aria-pressed="true"] {
  background: var(--accent-soft);
  /* Transparent rather than removed: a border that disappeared would resize the
     chip by two pixels on every toggle. */
  border-color: transparent;
  color: var(--accent);
}

/* --- Body ----------------------------------------------------------------- */

.fixture-details__body {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  overflow-y: auto;
  /* The page behind is already scroll-locked; this stops a flick at either end
     from handing the gesture back to it anyway. */
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  /* No top value — see the comment on `.fixture-details__bar`'s own
     margin-top, which carries that spacing instead. */
  padding: 0 0 var(--space-6);
}

/* --- Panels ---------------------------------------------------------------- */

/*
 * The tab row's panels. Almost no rules of its own beyond being the box they
 * sit in: each panel owns its own padding and its own cross-fade (see
 * `.fixture-predictions`), the same arrangement the club and league pages'
 * panel containers have.
 *
 * The exception is the density below.
 */

/*
 * Every panel's contents, one tenth smaller on a phone.
 *
 * `zoom`, not `transform: scale()`. A transform would paint the panel smaller
 * while leaving its box the old size — a tenth of the shell's width left empty
 * down one edge, taps landing off the mark, and text resampled rather than
 * re-rendered. `zoom` is a layout scale: lengths, type and the crest boxes
 * `Logo()` writes as inline styles all come down together, the panel still
 * fills the width it is given, and everything re-wraps at its new size and
 * stays crisp.
 *
 * Not the `--*-scale` knob `.fixture-score` and `.match-row` use either, and
 * the difference is what each is for: those are density dials a block was
 * authored around, one token multiplied per length, tuned for that block. This
 * is one instruction to the whole subtree — six panels, two of them written and
 * four still to come — and threading a multiplier through every rule of every
 * one of them would be a worse version of what the browser does here in a line.
 *
 * Phone only. 500px is layout.css's own definition of "wider than the shell" —
 * on a desktop tab the mini app sits in its frame with room around it, and the
 * reason to tighten it is not there.
 */
.fixture-details__panels {
  zoom: 0.9;
}

@media (min-width: 500px) {
  .fixture-details__panels {
    zoom: 1;
  }
}

/*
 * The stand-in behind the five tabs with nothing written for them yet. A plain
 * centred line, deliberately plain: it says a section is coming rather than
 * dressing an empty box up as content, and it is one `PANELS` entry away from
 * being replaced (FixtureDetails.js).
 */
.fixture-details__panel-empty {
  padding: var(--space-8) var(--space-4);
  font-size: var(--text-sm);
  color: var(--text-muted);
  text-align: center;
  opacity: 1;
  transition: opacity var(--duration) var(--easing);
}

/* A class beats the UA [hidden] rule — same note as `.fixture-details[hidden]`
   above. This one only needs it because the rule above sets `padding`, not
   `display`, but the pair has to stay explicit either way. */
.fixture-details__panel-empty[hidden] {
  display: none;
}

.fixture-details__panel-empty[data-open="false"] {
  opacity: 0;
}

/* --- Score header ---------------------------------------------------------- */

/*
 * Home, score, away. The two team columns share a width and the centre takes
 * what is left, so the scoreline is centred on the page rather than on whatever
 * the longer club name happens to be — and a long name on one side cannot push
 * the score off the middle.
 *
 * --header-scale is this block's density knob, the same arrangement
 * --fixture-scale gives the list: every length below is a token multiplied by
 * it, so the header is retuned here rather than across a dozen rules and the
 * tokens stay the source of truth. BADGE_SIZE in FixtureDetails.js is the one
 * length outside it — `Logo()` writes that box as an inline style — so the two
 * move together by hand.
 */
.fixture-score {
  --header-scale: 0.95;
  /* One knob for the crest and everything measured against it: the star's box
     is the crest's height, so the two are centred on each other by
     construction rather than by a hand-tuned offset. */
  --badge-size: calc(56px * var(--header-scale));
  /*
   * How far the star is pulled in from the column's outer edge, towards the
   * crest it belongs to. It has a ceiling: the crest is centred in a 1fr column
   * whose width depends on how wide the scoreline is, so a bigger inset walks
   * the star towards the mark and eventually under it. --space-2 leaves
   * clearance at every scoreline this feed produces.
   */
  --star-inset: calc(var(--space-2) * var(--header-scale));

  display: grid;
  /*
   * Two rows sharing three columns: crests and scoreline above, scorers below.
   * One grid rather than two stacked ones is what makes the lists line up with
   * the teams they belong to — a separate block underneath would be a second set
   * of tracks that agrees with these at one viewport width and drifts at every
   * other. The row is `auto`, so a fixture with no goals collapses it to nothing.
   */
  grid-template-columns: 1fr auto 1fr;
  align-items: start;
  column-gap: calc(var(--space-2) * var(--header-scale));
  row-gap: calc(var(--space-3) * var(--header-scale));
  padding-inline: calc(var(--space-4) * var(--header-scale));
}

.fixture-team {
  position: relative;
  min-width: 0;
}

/*
 * The star sits in the column's outer corner, level with the crest — its box is
 * exactly the crest's height, so `place-items: center` puts the glyph on the
 * crest's own centreline whatever --header-scale is set to. It is a sibling of
 * the navigating button, never a child: nested buttons are invalid, and later
 * in the DOM means the touch that lands on the star is never also the one that
 * opens the team.
 */
.fixture-team__star {
  position: absolute;
  top: 0;
  display: grid;
  place-items: center;
  width: calc(32px * var(--header-scale));
  height: var(--badge-size);
  color: var(--text-muted);
}

.fixture-team--home .fixture-team__star {
  left: var(--star-inset);
}

.fixture-team--away .fixture-team__star {
  right: var(--star-inset);
}

/* Filled blue: --accent owns "this one is selected", and a favourite is that. */
.fixture-team__star[aria-pressed="true"] {
  color: var(--accent);
}

.fixture-team__link {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(var(--space-2) * var(--header-scale));
  width: 100%;
  min-width: 0;
  /* The star is beside the crest, not above it, so nothing has to be cleared. */
  padding-inline: calc(var(--space-1) * var(--header-scale));
}

/*
 * The box the crest is fitted into. Fixed at the crest's own size so the column
 * keeps its height whether the mark is a wide pennant or a tall shield, and so
 * the star opposite has something stable to centre against.
 */
.fixture-team__badge {
  display: grid;
  place-items: center;
  height: var(--badge-size);
}

/*
 * Contained, not covered, and not rounded.
 *
 * `.logo` fills its box (`object-fit: cover`) and `TeamLogo` masks it into a
 * disc, which is right at 18px in a list where a crest is an identifier. Here
 * it is the picture: a shield or a pennant cropped to a circle loses its points
 * and its bottom, and at 53px that is the first thing the eye lands on. So the
 * mark is fitted whole inside the box, and the grey disc behind it goes with
 * the crop — an image with its own transparent background does not need a
 * plate under it.
 */
.fixture-team__badge .logo {
  width: auto;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

.fixture-team__badge .logo:not(.logo--monogram) {
  background: none;
  border-radius: 0;
}

/* The fallback still needs its plate — a bare monogram has nothing to sit on. */
.fixture-team__badge .logo--monogram {
  width: var(--badge-size);
  border-radius: var(--radius-full);
  font-size: calc(var(--text-lg) * var(--header-scale));
}

/*
 * Wraps rather than truncating. A crest with "Borussia Mönchengla…" under it
 * has told you less than the crest did on its own, and this is the one place in
 * the app with room for the whole name — the list is where names get cut.
 */
.fixture-team__name {
  margin-top: calc(var(--space-2) * var(--header-scale));
  font-size: calc(var(--text-sm) * var(--header-scale));
  font-weight: var(--weight-semibold);
  line-height: 1.25;
  text-align: center;
  text-wrap: balance;
}

/*
 * The four nodes the status swap switches on and off.
 *
 * Not optional, and not defensive: `[hidden] { display: none }` is a *UA* rule,
 * so any author `display` in this file outranks it and the element stays on
 * screen with the attribute set. That is exactly what happened here — a
 * scheduled fixture drew the live clock's prime and its refresh mark under the
 * kick-off time, because `.fixture-score__status` is `display: flex`. The
 * overlay roots make the same declaration for the same reason.
 *
 * Two of these do not currently set `display` and so do not strictly need it.
 * They are listed anyway: the failure is silent, and the next person to give
 * one of them a `display` should not have to rediscover this.
 */
.fixture-score__line[hidden],
.fixture-score__standin[hidden],
.fixture-score__status[hidden],
.fixture-score__event[hidden],
.fixture-scorers[hidden],
.fixture-scorers__mark[hidden] {
  display: none;
}

/*
 * The scoreline is centred on the crests, not on the whole column: the names
 * below run to one line or two depending on the club, and a score that tracked
 * the column's centre would sit at a different height on every fixture.
 */
.fixture-score__centre {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(var(--space-1) * var(--header-scale));
  min-height: var(--badge-size);
}

/*
 * The scoreline. Tabular figures for the same reason the list's score column
 * has them: a goal must change the number without moving it, and Plus Jakarta
 * Sans is proportional by default.
 */
.fixture-score__value {
  font-size: calc(var(--text-2xl) * var(--header-scale));
  font-weight: var(--weight-bold);
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
  white-space: nowrap;
}

.fixture-score__dash {
  margin-inline: calc(var(--space-2) * var(--header-scale));
  color: var(--text-muted);
}

/*
 * The kick-off time, or the word a fixture with no score has for itself. Set
 * smaller than the scoreline it replaces: "21:00" at the score's size reads as
 * a result, which is the one thing it is not.
 */
.fixture-score__standin {
  font-size: calc(var(--text-xl) * var(--header-scale));
  font-weight: var(--weight-semibold);
}

/*
 * Live. The red is --highlight, which owns exactly one fact in this app, and it
 * is the same fact the running minute and the scoreline already carry on the
 * row this page was opened from — so the page and the list agree about what is
 * in play, in the same colour.
 *
 * Scheduled and finished scorelines are deliberately not coloured here: both are
 * ordinary text, which is what body colour already gives them.
 */
.fixture-score[data-status="live"] .fixture-score__value,
.fixture-score[data-status="live"] .fixture-score__status {
  color: var(--highlight);
}

/*
 * The final score, once it is final: the winner keeps the full weight and the
 * page's text colour, the loser drops to the muted grey and one step of weight.
 *
 * Only the loser is restyled. Making the winner *more* than it already is has
 * nowhere to go — the scoreline is --weight-bold, the top of the scale in
 * tokens.css — so the contrast is built by taking emphasis off the other digit
 * rather than by inventing a heavier one. The result reads the same way and
 * keeps the winning number at exactly the size and weight it has in every other
 * state, which is what stops a result looking like a different component.
 *
 * A draw sets `draw` on both and neither is touched: level is not two losses.
 */
.fixture-score__digit[data-outcome="loss"] {
  color: var(--text-muted);
  font-weight: var(--weight-semibold);
}

/*
 * One value, centred under the scoreline. Nothing sits beside it: the seconds
 * hand counting is what says the number is live, so the mark that used to say it
 * is gone and the line keeps the page's centreline.
 *
 * Muted by default, because that is what it is in every state but one — a
 * finished match's "Finished" is metadata about a score that has stopped
 * moving. Live overrides it to the red above, where the clock is not metadata
 * but the second half of the claim the scoreline is making.
 */
.fixture-score__status {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  font-size: calc(var(--text-sm) * var(--header-scale));
  font-weight: var(--weight-semibold);
  font-variant-numeric: tabular-nums;
}

/*
 * The latest thing to happen in the match. Absent entirely when the feed has no
 * event for the fixture — which is every fixture in the current export — rather
 * than drawn as an empty line waiting to be filled.
 */
.fixture-score__event {
  display: flex;
  align-items: center;
  gap: calc(var(--space-1) * var(--header-scale));
  color: var(--text-secondary);
  font-size: calc(var(--text-xs) * var(--header-scale));
  font-weight: var(--weight-medium);
  text-align: center;
}

.fixture-event__icon {
  display: grid;
  place-items: center;
  color: var(--text-muted);
}

/*
 * Who scored, under the team it counted for: home names run to the right edge of
 * their column and away names from the left edge of theirs, so both lists lean
 * on the centre mark between them and the block reads inward rather than as two
 * unrelated paragraphs.
 *
 * Set small and secondary on purpose. This is the supporting detail under a
 * result, and at --text-xs it stays a caption beside crests and a 30px
 * scoreline instead of competing with them.
 */
.fixture-scorers {
  min-width: 0;
  color: var(--text-secondary);
  font-size: calc(var(--text-xs) * var(--header-scale));
  line-height: 1.45;
}

.fixture-scorers--home {
  text-align: right;
}

.fixture-scorers--away {
  text-align: left;
}

/*
 * A scorer and their minutes are one run of text, and at this column width that
 * run wraps — "Preview Scorer 1 11', 45', 79'" does not fit beside a crest on a
 * 390px screen, and neither would most real names with a brace on them.
 *
 * So the lines are spaced. Without the gap a wrapped second line is
 * indistinguishable from the next scorer, and a four-goal column becomes a
 * paragraph you have to parse rather than a list you can count. The reference
 * this is drawn from has no gap because nothing in it wraps; the gap is what
 * keeps the same reading at a width where things do.
 */
.fixture-scorers__line {
  text-wrap: pretty;
}

.fixture-scorers__line + .fixture-scorers__line {
  margin-top: calc(var(--space-1) * var(--header-scale));
}

.fixture-scorers__minutes {
  /* Tabular, like every other number in this block: minutes sit in a ragged
     column here and proportional figures make that edge look accidental. */
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/*
 * The mark between the two lists, in the same column the scoreline is in. Muted:
 * it labels what the lists are, and a goal icon in the accent or the live red
 * would be claiming one of the roles those colours already own.
 *
 * Top-aligned with the first line of each list rather than centred on the block,
 * so a side with four goals does not drag it halfway down the page.
 */
.fixture-scorers__mark {
  display: grid;
  place-items: center;
  /* One line box of the lists either side, so the glyph sits on their first
     line however many lines follow it. */
  height: calc(var(--text-xs) * var(--header-scale) * 1.45);
  color: var(--text-muted);
}

/*
 * The tab row that used to live here is `.tab-bar` (styles/components/tab-bar.css),
 * shared with the club page. Nothing about it was fixture-specific — it moved
 * whole, class names and all, when the second caller arrived.
 */

/* --- Page behind ----------------------------------------------------------- */

/*
 * The list must not scroll under the page. Position is preserved on the
 * document, which is what lets the close land the user exactly where they were.
 */
body[data-fixture-open] {
  overflow: hidden;
}
