/* ===================================================================
   One flow language for every travelling light on the site.

   Ten separate treatments had drifted apart: durations of 2.8s, 3s,
   3.5s, 3.6s, 4s and 4.6s, stroke widths from 2 to 3, six different
   stroke colours and five different dash ratios. Same effect, built
   five times, looking different on every page.

   This sheet loads last and pulls all of them onto the 2.8s cycle the
   V7.11 handover already names as the standard. Tune the variables
   below and the whole site moves together.

   Two rules about HOW this overrides, both deliberate:

   1. Longhands only — never the `animation` shorthand. The shorthand
      resets animation-play-state to `running`, which would defeat
      every offscreen and hidden-tab pause on the site. Setting
      animation-duration alone leaves the name and the play-state
      exactly as each scene declared them.

   2. The selectors are copied verbatim from the rules they override,
      so this wins on load order rather than by escalating specificity
      or reaching for !important.

   Paths normalised to pathLength="100" (the homepage sponsor board)
   take --flow-dash-100, which is the same ratio on that scale.
   =================================================================== */

:root {
  --flow-dur: 2.8s;
  --flow-width: 2.6;
  --flow-dash: .06 .94;
  --flow-dash-100: 6 94;          /* identical ratio, pathLength="100" */
  --flow-stroke: #d6fbff;   /* slightly brighter: the glow is tighter now */
  --flow-near: #2ddfff;
  --flow-bloom: #007aff;
  /* One small-radius shadow, not two wide ones. Measured on
     Championships (24 routes, 10 animating): two wide shadows per path
     cost 9.6ms per frame, the same pair on the container 4.7ms, and
     this single tight shadow 0.3ms — free, to two decimal places.
     Wide blur is what costs; the light itself is the stroke colour. */
  --flow-filter: drop-shadow(0 0 2.5px var(--flow-near));
}

/* ---- the illustration routes over artwork ----

   The glow sits on the SVG, not on each path. Measured on Championships,
   which carries the most routes on the site (24 paths, 10 animating at
   once): a drop-shadow per path cost 9.0ms per frame over baseline,
   the same glow on the container costs 3.7ms. Identical appearance,
   because these overlays contain nothing but current paths — there is
   no static track underneath to light up by accident. */
body .image-route-glow {
  filter: var(--flow-filter);
}
body .image-route-glow path {
  animation-duration: var(--flow-dur);
  animation-timing-function: linear;
  stroke: var(--flow-stroke);
  stroke-width: var(--flow-width);
  stroke-dasharray: var(--flow-dash);
  filter: none;
}

/* ---- panel outlines ----

   Some artwork already draws its line as a lit edge. The About card is
   the case: its outline is painted at luminance 246 and the travelling
   light is #d6fbff, luminance 246 — the same colour, so the light
   vanished into the line and the card just looked like flat white
   strokes.

   A panel is not traced. It carries the light along its whole length
   and breathes, so it reads as the panel being lit rather than as
   something crawling around its edge. Saturated cyan rather than near
   white, because it has to register against a white line. */
/* The three ID-qualified rules further down carry an ID, so a bare
   class never reaches a panel that sits inside #mission, #sponsors or
   #where-we-play — the About card is in #mission, and its panel kept
   the travelling-light stroke while only the animation changed. Stated
   at the same level here rather than beaten with !important. */
body #where-we-play .image-route-glow .route-panel,
body #mission .image-route-glow .route-panel,
body #sponsors .image-route-glow .route-panel,
.image-route-glow .route-panel {
  stroke: #2ddfff;
  stroke-width: 3;
  stroke-dasharray: none;
  stroke-linejoin: round;
  opacity: .9;
  filter: drop-shadow(0 0 7px #00d5ffcc) drop-shadow(0 0 18px #008cff66);
  animation-name: panel-breathe;
  animation-duration: 3.4s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
}
@keyframes panel-breathe {
  0%, 100% { opacity: .55; }
  50%      { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  body #where-we-play .image-route-glow .route-panel,
  body #mission .image-route-glow .route-panel,
  body #sponsors .image-route-glow .route-panel,
  .image-route-glow .route-panel { animation: none; opacity: .85; }
}
/* Mobile drops blur everywhere else; keep a single tight one here or the
   panel loses the only thing that separates it from the painted line. */
@media (max-width: 700px) {
  .image-route-glow .route-panel {
    filter: drop-shadow(0 0 5px #00d5ffcc) !important;
  }
}

/* ---- About: the court perimeter and the India map ---- */
body .about-network-wires .about-current,
body.approved-about .about-map-links .about-map-current {
  animation-duration: var(--flow-dur);
  animation-timing-function: linear;
  stroke: var(--flow-stroke);
  stroke-width: var(--flow-width);
  stroke-dasharray: var(--flow-dash);
  filter: var(--flow-filter);
}

/* ---- Local Cricket: the journey gaps ---- */
body .journey-wires .journey-current {
  animation-duration: var(--flow-dur);
  animation-timing-function: linear;
  stroke: var(--flow-stroke);
  stroke-width: var(--flow-width);
  stroke-dasharray: var(--flow-dash);
  filter: var(--flow-filter);
}

/* ---- the shared scene diagrams ---- */
.scene-wire .wire-pulse,
.v5-wires .v5-wire-pulse,
.ground-court-light path + path {
  animation-duration: var(--flow-dur);
  animation-timing-function: linear;
  stroke: var(--flow-stroke);
  stroke-width: var(--flow-width);
  stroke-dasharray: var(--flow-dash);
  filter: var(--flow-filter);
}

/* ---- the visual-system link pulse and the committee branches ---- */
.v-link-pulse,
/* Four scene-specific rules re-style .v-link-pulse with a descendant
   selector, so a bare class never reached them — .v-gate-art was still
   running at 4s with a 4px white stroke. Matched here so the link
   pulses agree with everything else. */
.v-city .v-link-pulse,
.v-gate-art .v-link-pulse,
.v-city-art .v-link-pulse,
.v-club-close-art .v-link-pulse,
.tr-closing-art .v-link-pulse,
/* the committee branches are declared as `.v6-connectors
   .v7-branch-current`, so a bare class would not have reached them */
.v6-connectors .v7-branch-current {
  animation-duration: var(--flow-dur);
  animation-timing-function: linear;
  stroke: var(--flow-stroke);
  stroke-width: var(--flow-width);
  stroke-dasharray: var(--flow-dash);
  filter: var(--flow-filter);
}

/* ---- the homepage sponsor board ----
   These paths carry pathLength="100" and their keyframe travels to
   stroke-dashoffset:-100, so the dash has to be expressed on that
   scale. Same ratio, same apparent speed. */
.sponsor-wires .wire-pulse {
  animation-duration: var(--flow-dur);
  animation-timing-function: linear;
  stroke: var(--flow-stroke);
  stroke-width: var(--flow-width);
  stroke-dasharray: var(--flow-dash-100);
  filter: var(--flow-filter);
}

/* ---- the three ID-qualified overrides in final-motion.css ----
   `body #where-we-play .image-route-glow path` (and #mission, #sponsors)
   carries an ID, so it outranks the rule above no matter what order the
   sheets load in. Matched here rather than beaten with !important —
   these three sections were the only ones still drawing a 3px stroke
   and a different blue. */
body #where-we-play .image-route-glow path,
body #mission .image-route-glow path,
body #sponsors .image-route-glow path {
  animation-duration: var(--flow-dur);
  animation-timing-function: linear;
  stroke: var(--flow-stroke);
  stroke-width: var(--flow-width);
  stroke-dasharray: var(--flow-dash);
  filter: none;
}

/* ---- neon tubes ----

   The gate artwork paints its own neon. The overlay is not there to
   draw the line -- the line is already there, white hot -- it is there
   to make it look alive.

   Two attempts before this one failed for opposite reasons, both worth
   recording. A near-white 3px stroke laid over an already near-white
   tube changes almost no pixels, so nothing appeared to happen. Then
   `mix-blend-mode: screen`, to add light rather than replace it, took
   the artwork off the page entirely: .v-gate-art sits at z-index:-1,
   and giving its child a blend mode wrecked the compositing order for
   the whole host. No blend mode here.

   What works is a bloom that reaches past the tube into the dark
   around it, swinging between a quarter and full strength. The tube
   itself does not change much; its halo swells, which is what a tube
   coming on actually looks like. The bloom is on the container rather
   than the paths, which is what the note at the top of this sheet
   found to be four times cheaper for the same appearance.

   Stated at ID level for the same reason the panel rules are, so a
   bare class cannot be outranked by `body #id .image-route-glow path`
   further up this sheet. */
body .image-route-glow:has(.route-tube) {
  filter: drop-shadow(0 0 7px #00b7ffcc) drop-shadow(0 0 22px #007aff88);
}
body #start .image-route-glow .route-tube,
body #team .image-route-glow .route-tube,
body #hero .image-route-glow .route-tube,
.image-route-glow .route-tube {
  stroke: #d8f3ff;
  stroke-width: 2.8;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: none;
  stroke-dashoffset: 0;
  filter: none;
  animation-name: tube-flicker;
  animation-duration: 6.4s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}

/* A fluorescent tube striking.

   A smooth swell reads as a lamp on a dimmer, not as a tube. What
   makes a tube a tube is the stutter: it gulps, catches, drops out
   once or twice more, then holds -- and even when it has settled it
   never sits perfectly still.

   So this is not a sine. It is two flicker bursts per 6.4s cycle with
   a slow drift between them, and the gaps inside a burst are 1.5-2%
   of the cycle, which is 96-128ms -- fast enough to snap rather than
   fade. `linear` is deliberate: an eased blink is a fade, and a fade
   is the thing this is replacing.

   image-glow.js already offsets each path in a scene by -0.7s, so the
   gate's three frames strike at different moments instead of blinking
   in unison, the way a row of real tubes does. */
@keyframes tube-flicker {
  0%    { opacity: .80; }
  7%    { opacity: .96; }
  9.5%  { opacity: .26; }
  11%   { opacity: 1; }
  13%   { opacity: .40; }
  14.5% { opacity: .98; }
  16%   { opacity: .55; }
  17%   { opacity: 1; }
  24%   { opacity: .90; }
  38%   { opacity: 1; }
  50%   { opacity: .86; }
  57%   { opacity: .97; }
  59%   { opacity: .24; }
  60.5% { opacity: 1; }
  62%   { opacity: .45; }
  63%   { opacity: .99; }
  70%   { opacity: .92; }
  86%   { opacity: 1; }
  100%  { opacity: .80; }
}
@media (prefers-reduced-motion: reduce) {
  body #start .image-route-glow .route-tube,
  body #team .image-route-glow .route-tube,
  body #hero .image-route-glow .route-tube,
  .image-route-glow .route-tube { animation: none; opacity: .8; }
}

/* Below 760px revision.css swaps the closing gate for a portrait crop:
   it hides the wide gate's image and its court wire and shows
   .v-gate-mobile-art instead. The wide gate's route glow was never in
   that list, because as a thin travelling dash inside an overflow-
   clipped host it never showed. Lit as a solid tube it is a brighter
   thing to leave lying around, so it is hidden with the image it
   belongs to rather than left to the clipping. */
@media (max-width: 760px) {
  .v-gate-art > .image-route-glow { display: none; }
}
