/*
 * League strip — story bubbles that double as the fixture filter.
 *
 * Two layers ride on one avatar and never merge:
 *   .category__ring   story state   absent / unread blue / viewed grey
 *   .category__fill   filter state  dark disc under the monogram
 * Both can be on at once, which is the whole point — a selected league that
 * also has unread news has to say so.
 */

.category-bar__track {
  display: flex;
  /* The bubbles' own edge-to-edge padding is only ~2.9px once a story ring
     is drawn (it nearly fills the bubble box), so a little extra breathing
     room comes from here rather than shrinking the ring. */
  gap: 6px;
  padding-inline: var(--space-3);
  width: max-content;
}

.category {
  /*
   * 0.92 is a deliberate local override of the app-wide 0.96 — a 44px circle
   * with nothing around it needs more travel to read as pressed than a wide
   * row does. It goes through --press-scale rather than a bespoke transform so
   * [data-pressable] still owns the press, timing and reduced-motion fallback.
   */
  --press-scale: 0.92;

  /*
   * Mirrors RING_SIZE / the avatar size in CategoryBar.js. The avatar matches
   * the "add" circle's diameter so every disc in the strip is one size; the
   * bubble carries that plus the ring's own width and breathing gap.
   */
  --bubble-size: 46px;
  --avatar-size: 37px;

  display: block;
  flex: none;
  color: var(--text-muted);

  /*
   * The story ring is sized off --bubble-size (in CategoryBar.js) and nearly
   * fills the bubble box already — only ~1.45px of padding per side. A
   * negative margin here to tighten unringed avatars would pull ringed
   * neighbours into each other, so spacing stays at the track's own gap: 0.
   */
}

/* The focus outline follows the bubble instead of base.css's square. */
.category:focus-visible {
  border-radius: var(--radius-full);
}

.category__bubble {
  position: relative;
  display: grid;
  place-items: center;
  width: var(--bubble-size);
  height: var(--bubble-size);
}

/* --- Story ring ----------------------------------------------------------- */

.category__ring {
  position: absolute;
  inset: 0;
  /* Empty until a stack exists — no ring is the "nothing to view" state. */
  display: block;
  pointer-events: none;
}

.story-ring {
  display: block;
}

/*
 * One dash per item. --seg / --seg-rest / --seg-offset are written per segment
 * in CategoryBar.js from the shared circumference, so the gaps stay even at
 * any count and a single item draws an unbroken circle.
 */
.story-ring__segment {
  fill: none;
  stroke: var(--story-ring-color, var(--border-strong));
  /* Mirrors RING_STROKE in CategoryBar.js. */
  stroke-width: 2.9;
  stroke-linecap: round;
  stroke-dasharray: var(--seg) var(--seg-rest);
  stroke-dashoffset: var(--seg-offset);
  /* Start the run at 12 o'clock rather than 3. */
  transform: rotate(-90deg);
  transform-origin: center;
  transition: stroke var(--duration) var(--easing);
  /*
   * Draw-on. Runs on mount, and the segments are only rebuilt when the item
   * count changes — so this plays when news actually arrives and never when a
   * stack is merely marked read.
   *
   * stroke-dasharray is a paint property: it repaints the stroke, it does not
   * reflow anything, so this stays inside the transform/opacity spirit of the
   * rest of the app. It is also the only way to genuinely draw a stroke on.
   */
  animation: story-ring-draw var(--spring-duration) var(--easing) both;
  animation-delay: calc(var(--i) * var(--stagger-step));
}

@keyframes story-ring-draw {
  from {
    stroke-dasharray: 0 var(--seg-rest);
  }
}

.category__bubble[data-story="unread"] {
  --story-ring-color: var(--accent);
}

/* Viewed: the ring desaturates to flat grey and the avatar drops back with it. */
.category__bubble[data-story="read"] {
  --story-ring-color: var(--border-strong);
}

/* Dim the avatar, not the bubble — dimming the bubble would wash out the ring
   that has already been greyed, and read out as two states deep instead of one. */
.category__bubble[data-story="read"] .category__icon {
  opacity: 0.72;
}

/* --- Avatar and filter fill ----------------------------------------------- */

/* The avatar disc: resting background, and the box the fill is clipped to.
   Grey with a hairline — on the white page, a lighter disc would vanish into it. */
.category__icon {
  position: relative;
  display: grid;
  place-items: center;
  width: var(--avatar-size);
  height: var(--avatar-size);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  /* Keeps the wipe a disc — it scales up past the avatar's own edge. */
  overflow: hidden;
  color: var(--text-secondary);
  font-size: var(--text-2xs);
  font-weight: var(--weight-semibold);
  transition:
    color var(--duration) var(--easing),
    opacity var(--duration) var(--easing),
    border-color var(--duration) var(--easing);
}

/*
 * The filter fill: its own layer over the resting disc and under the monogram,
 * so "selected" never has to borrow the ring's colour. Resting state is full
 * size and invisible — selecting animates the scale up, deselecting only fades,
 * which is why the outgoing avatar dissolves rather than collapsing to a point.
 */
.category__fill {
  position: absolute;
  inset: 0;
  background: var(--accent);
  border-radius: var(--radius-full);
  opacity: 0;
  transition: opacity var(--duration) var(--easing);
}

/* Positioned so it paints above the fill; both are z-index auto, so the only
   thing deciding the order is which comes second in the markup. */
.category__glyph {
  position: relative;
  display: grid;
  place-items: center;
}

/*
 * A crest in the disc (the Catch-Up tab's clubs and competitions). `.logo`'s
 * own sunken fill and hairline are stripped: the disc already has both, and a
 * second disc inside the first would read as a badge on a badge — and would
 * hide the filter fill, which has to show around the crest for "selected" to
 * read at all. The monogram fallback keeps the disc's text colour.
 */
.category__logo {
  background: transparent;
  border: 0;
  color: inherit;
}

.category[aria-pressed="true"] {
  color: var(--text);
}

/* The hairline joins the fill — a grey edge on a blue disc reads as a
   rendering artifact, not a border. */
.category[aria-pressed="true"] .category__icon {
  border-color: var(--accent);
}

.category[aria-pressed="true"] .category__fill {
  opacity: 1;
  animation: story-fill-wipe var(--spring-duration) var(--spring);
}

.category[aria-pressed="true"] .category__glyph {
  color: var(--accent-text);
}

/* A radial wipe, not a fade — the fill grows out of the middle of the avatar. */
@keyframes story-fill-wipe {
  from {
    transform: scale(0);
  }
}

/* --- Add favourite -------------------------------------------------------- */

/*
 * No ring to leave room for, so the box is the circle. Two things fall out of
 * that: the circle sits flush against the track's own --space-3 padding, which
 * is what lines it up with the app bar's left edge above; and there is no dead
 * space inside the box inflating the gap before the first story circle, so the
 * strip spaces evenly off the track's single gap.
 */
.category--action .category__bubble {
  width: var(--avatar-size);
}

/* Dashed outline, no ring, no fill — same diameter as the story avatars. */
.category--action .category__icon {
  background: transparent;
  border: 1px dashed var(--border-strong);
}

.category--action .category__fill {
  display: none;
}

@media (prefers-reduced-motion: reduce) {
  .story-ring__segment,
  .category[aria-pressed="true"] .category__fill {
    animation: none;
  }
}
