/* ============================================================
   PACY — MOTION
   ------------------------------------------------------------
   Two signature interactions, deliberately different:

     Lightning Reveal — a match that did not exist before arrives.
                        Once per match id, per session. ~900ms.
     Pacy Pulse       — a match already on screen changed.
                        Repeatable, shorter, local to one card.

   Everything animates on opacity and transform only, so no
   frame triggers layout. Nothing loops forever.
   ============================================================ */

/* --- calm entry for matches present at load ------------------ */
/* Existing matches must not use the reveal; they get a staggered
   fade so first paint feels settled rather than eventful. */
@keyframes cardFadeIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
.card.enter {
  animation: cardFadeIn var(--d-slow) var(--ease-out) backwards;
  animation-delay: var(--stagger, 0ms);
}

/* ============================================================
   LIGHTNING REVEAL
   ============================================================ */

.card.reveal {
  /* The card is present and usable for the whole animation; only
     its finish changes. */
  animation: revealRise var(--d-reveal) var(--ease-out) backwards;
}
@keyframes revealRise {
  0%   { opacity: 0; transform: translateY(10px); }
  55%  { opacity: 1; }
  100% { opacity: 1; transform: none; }
}

/* 1 — the trace: a bolt of light runs the width of the card.
   Amber leads, a white-hot core follows, blue trails — the same
   colour order a real arc has, and the reason it reads as a strike
   rather than a loading bar. */
.reveal-trace {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  height: 4px;
  width: 52%;
  z-index: 4;
  pointer-events: none;
  border-radius: 0 0 4px 4px;
  background: linear-gradient(90deg,
    transparent 0%,
    var(--bolt-deep) 22%,
    var(--bolt-core) 40%,
    var(--white) 52%,
    var(--bolt-hot) 66%,
    rgba(255, 176, 32, .35) 82%,
    transparent 100%);
  filter: drop-shadow(0 0 8px rgba(127, 196, 255, .95))
          drop-shadow(0 0 14px rgba(255, 176, 32, .55));
  animation: traceRun 380ms var(--ease-out) forwards;
}
@keyframes traceRun {
  from { transform: translateX(-110%); opacity: 0; }
  30%  { opacity: 1; }
  to   { transform: translateX(320%); opacity: 0; }
}

/* 2 — the outline draws itself with the same energy.
   The ring is an overlay, so only its border may paint. The usual
   `padding-box` gradient-border trick fills the interior with an
   opaque colour, which here sat on top of the card and hid the
   match completely. Masking out the content box leaves just the
   2px ring and keeps everything beneath visible. */
.reveal-outline,
.card.pulse .pulse-ring {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  border-radius: var(--r-lg);
  padding: 2px;                 /* ring thickness */
  -webkit-mask:
    linear-gradient(#fff 0 0) content-box,
    linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask:
    linear-gradient(#fff 0 0) content-box,
    linear-gradient(#fff 0 0);
  mask-composite: exclude;
}

/* The travelling head carries both tones so the arc stays legible
   all the way round the card, not just on the light edges. */
.reveal-outline {
  padding: 3px;
  background: conic-gradient(from var(--ang, 0turn),
    var(--bolt-hot)  0turn,
    var(--white)     .022turn,
    var(--bolt-core) .05turn,
    var(--bolt-deep) .10turn,
    transparent      .22turn,
    transparent      1turn);
  filter: drop-shadow(0 0 6px rgba(127, 196, 255, .8));
  animation: outlineDraw 620ms 180ms var(--ease-out) forwards;
  opacity: 0;
}
@property --ang {
  syntax: "<angle>";
  initial-value: 0turn;
  inherits: false;
}
@keyframes outlineDraw {
  0%   { opacity: 0; --ang: 0turn; }
  25%  { opacity: 1; }
  75%  { opacity: 1; }
  100% { opacity: 0; --ang: 1turn; }
}

/* 3 — the NEW MATCH label, temporary by design.
   It takes the status badge's slot rather than the competition
   name's: sitting top-left it covered the competition, and the
   card already signals live status with its red top edge. The
   badge returns when the flag leaves, and because the flag is
   absolutely positioned neither swap moves any layout. */
.card.reveal .card-status { visibility: hidden; }

.reveal-flag {
  position: absolute;
  inset-block-start: var(--s-4);
  inset-inline-end: var(--s-5);
  z-index: 5;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px var(--s-3);
  border-radius: var(--r-sm);
  background: var(--electric);
  color: var(--white);
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  box-shadow: 0 2px 10px rgba(37, 99, 235, .5);
  animation: flagIn 240ms 280ms var(--ease-spring) backwards,
             flagOut 300ms 2600ms var(--ease-out) forwards;
}
@keyframes flagIn  { from { opacity: 0; transform: translateY(-6px) scale(.9); } }
@keyframes flagOut { to   { opacity: 0; transform: translateY(-4px); } }

.reveal-flag svg { width: 11px; height: 11px; }

/* 4 — names and time resolve in after the outline lands. */
.card.reveal .competitors,
.card.reveal .scores,
.card.reveal .kickoff {
  animation: contentResolve 420ms 320ms var(--ease-out) backwards;
}
@keyframes contentResolve {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}

/* 5 — the glow fades and the card settles. Both tones again, so
   the afterglow matches the arc that produced it. */
.card.reveal::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  border-radius: var(--r-lg);
  box-shadow: 0 0 0 1px rgba(127, 196, 255, .55),
              0 0 26px rgba(37, 99, 235, .38),
              0 8px 34px rgba(255, 176, 32, .22);
  animation: glowSettle 780ms 320ms var(--ease-out) forwards;
}
@keyframes glowSettle { to { opacity: 0; } }

/* ============================================================
   PACY PULSE — an existing match changed
   ============================================================ */

/* 1 — one circuit of light around the affected card only.
   Geometry and masking are shared with .reveal-outline above; only
   the gradient and timing differ. */
/* One circuit, event-coloured, with a white-hot leading edge so it
   reads as the same electrical family as the reveal without being
   mistaken for it. */
.card.pulse .pulse-ring {
  padding: 3px;
  background: conic-gradient(from var(--ang, 0turn),
    var(--white)                      0turn,
    var(--pulse-hue, var(--electric)) .018turn,
    var(--pulse-hue, var(--electric)) .08turn,
    transparent                       .18turn,
    transparent                       1turn);
  filter: drop-shadow(0 0 5px var(--pulse-glow, rgba(37, 99, 235, .7)));
  animation: pulseRun var(--d-pulse) var(--ease-in-out) forwards;
}
@keyframes pulseRun {
  0%   { opacity: 0;  --ang: 0turn; }
  12%  { opacity: 1; }
  88%  { opacity: 1; }
  100% { opacity: 0;  --ang: 1turn; }
}

/* 2 — the changed number flips rather than swapping abruptly. */
.score-value.flip { animation: scoreFlip 460ms var(--ease-spring); }
@keyframes scoreFlip {
  0%   { transform: translateY(0)    scale(1);    }
  30%  { transform: translateY(-22%) scale(1.16); }
  60%  { transform: translateY(6%)   scale(.97);  }
  100% { transform: translateY(0)    scale(1);    }
}

/* Quiet clock replacement: enough motion to stop digits looking torn during
   a scrape update, never enough to call attention away from the score. */
.clock.clock-settle { animation: clockSettle 180ms var(--ease-out); }
@keyframes clockSettle {
  from { opacity: .45; transform: translateY(-2px); }
  to { opacity: 1; transform: none; }
}

/* 3 — a temporary, controlled tint on the side that scored. */
.competitor.scored { animation: scoredTint 1500ms var(--ease-out) forwards; }
@keyframes scoredTint {
  0%   { background: rgba(37, 99, 235, .16); }
  100% { background: transparent; }
}
.competitor {
  border-radius: var(--r-sm);
  padding-inline: var(--s-2);
  margin-inline: calc(var(--s-2) * -1);
}

/* 4 — a compact event label: "GOAL — 67'".
   Shares the status badge's corner for the same reason as the
   reveal flag, so it never lands on top of it. */
.card.pulse .card-status { visibility: hidden; }

.pulse-flag {
  position: absolute;
  inset-block-start: var(--s-4);
  inset-inline-end: var(--s-5);
  z-index: 5;
  padding: 3px var(--s-3);
  border-radius: var(--r-sm);
  background: var(--pulse-hue, var(--electric));
  color: var(--white);
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  white-space: nowrap;
  animation: flagIn 200ms var(--ease-spring) backwards,
             flagOut 280ms 2200ms var(--ease-out) forwards;
}

/* Event colour carries meaning beyond the word on the label. */
.card[data-pulse="goal"]    { --pulse-hue: var(--good);      --pulse-glow: rgba(14,124,85,.7); }
.card[data-pulse="score"]   { --pulse-hue: var(--electric);  --pulse-glow: rgba(37,99,235,.7); }
.card[data-pulse="card"]    { --pulse-hue: #D9A400;          --pulse-glow: rgba(217,164,0,.7); }
.card[data-pulse="redcard"] { --pulse-hue: var(--danger);    --pulse-glow: rgba(179,38,30,.7); }
.card[data-pulse="period"]  { --pulse-hue: var(--bolt-hot);  --pulse-glow: rgba(255,176,32,.7); }
.card[data-pulse="final"]   { --pulse-hue: var(--navy-400);  --pulse-glow: rgba(23,74,126,.7); }
.card[data-pulse="wicket"]  { --pulse-hue: var(--danger);    --pulse-glow: rgba(179,38,30,.7); }

/* ============================================================
   SKELETONS
   Match the final card's dimensions exactly so nothing shifts
   when real data replaces them (CLS budget is 0.1).
   ============================================================ */

.skeleton { pointer-events: none; }
.sk {
  border-radius: var(--r-sm);
  background: var(--surface-line);
  position: relative;
  overflow: hidden;
}
/* The shimmer is a faceted plane sweeping past, echoing the logo
   rather than the usual soft gradient. */
.sk::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(105deg,
    transparent 0%,
    transparent 38%,
    rgba(255, 255, 255, .55) 38.2%,
    rgba(255, 255, 255, .55) 50%,
    transparent 50.2%,
    transparent 100%);
  transform: translateX(-100%);
  animation: skSweep 1400ms var(--ease-in-out) infinite;
}
@keyframes skSweep { to { transform: translateX(100%); } }

.sk-line   { height: 12px; }
.sk-title  { height: 20px; width: 60%; }
.sk-crest  { width: 38px; height: 38px; border-radius: 8px; }
.sk-score  { width: 46px; height: 44px; border-radius: var(--r-sm); }

/* ============================================================
   REDUCED MOTION
   The brief requires a calm outline and label, with no movement.
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .scroll-x { scroll-behavior: auto; }
  .arena-grid, .arena-orb, .arena-bolt { animation: none !important; }

  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }

  /* The reveal still communicates — it just stops moving. */
  .card.reveal {
    outline: 2px solid var(--electric);
    outline-offset: -2px;
  }
  .reveal-trace, .reveal-outline, .card.reveal::after { display: none; }
  .reveal-flag {
    animation: none !important;
    opacity: 1;
  }
  /* A solid ring rather than a travelling one. The mask still
     applies, so this paints the 2px edge only. */
  .card.pulse .pulse-ring {
    animation: none !important;
    opacity: 1;
    background: var(--pulse-hue, var(--electric));
  }
  .pulse-flag { animation: none !important; opacity: 1; }
  .sk::after { animation: none !important; }
  .badge-live .dot, .nav-link .live-dot { animation: none !important; }
}

/* A user-facing switch, independent of the OS setting, because
   the OS setting is often not where people look. */
[data-motion="off"] *,
[data-motion="off"] *::before,
[data-motion="off"] *::after {
  animation-duration: .001ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: .001ms !important;
}
[data-motion="off"] .scroll-x { scroll-behavior: auto; }
[data-motion="off"] .arena-grid,
[data-motion="off"] .arena-orb,
[data-motion="off"] .arena-bolt { animation: none !important; }
[data-motion="off"] .card:hover { transform: none !important; }
[data-motion="off"] .reveal-trace,
[data-motion="off"] .reveal-outline,
[data-motion="off"] .card.reveal::after { display: none; }
[data-motion="off"] .card.reveal {
  outline: 2px solid var(--electric);
  outline-offset: -2px;
}
[data-motion="off"] .reveal-flag,
[data-motion="off"] .pulse-flag { animation: none !important; opacity: 1; }
