/* ============================================================================
   Live audio panel beside the home page map.

   Loaded only by the page that has the map, next to leaflet.css, for the same
   reason that file exists separately: no other page pays for it.

   The panel lists the newest public, human-confirmed audio detection for each
   of ten unique bird species, and every card is injected by
   assets/js/audio-preview.js — so
   nothing here may assume a card is present. With JavaScript off, or with the
   API down, the panel collapses to nothing and the map keeps the full width it
   had before this feature existed.
   ========================================================================= */

/* ---- Map + panel row -----------------------------------------------------
   The map decides how tall the row is and the panel matches it, scrolling
   internally rather than stretching the row, so adding a fifth card can never
   push the map taller than the viewport.

   Single column below 1200px, and that number moved up from 992px when the map
   became a picture. A fixed-height map did not care how wide its column was;
   this one is a fixed ratio, so every pixel the 21rem panel takes comes off the
   map's height as well as its width. At a 992px viewport the pair left the map
   576 x 303 — half the height it used to have, beside a panel almost as wide as
   it was tall. Full width and 550px tall is the better use of that screen.
   Panel goes second when stacked: the map is the thing people came for.
   ------------------------------------------------------------------------ */
.ep-map-row {
  /* Declared here, on the ancestor both maps share, because either can be the
     one in the row: the static <figure> uses it as the frame's ground, and
     leaflet.css paints .leaflet-container with it when interactiveMap is on.
     One definition rather than one per file — it is a colour sampled from the
     tiles, and two copies of a sampled value drift.

     It is the one colour on the site that is not a brand token, and it does not
     belong in ecopi-tokens.css: its only job is to match the tiles. If the tile
     source changes, resample it — measure a pixel of open ocean in a
     screenshot, do not guess. MapTiler's Voyager style fills the ocean flat, so
     a single value matches everywhere. */
  --ep-map-water: #cae0e4;

  display: grid;
  grid-template-columns: minmax(0, 1fr) 21rem;
  gap: var(--ep-space-5);
  align-items: stretch;
}

/* ---- The static map ------------------------------------------------------
   The map is a picture rendered by tools/render-map.js, not Leaflet. See the
   interactiveMap switch in src/index.njk for why.

   The frame takes its shape from the image itself: index.njk sets --map-ratio
   and --map-ratio-narrow from src/_data/mapImage.json, which the render run
   writes. That indirection is the whole trick. Sizing the box independently
   meant choosing between object-fit: cover, which crops — and the outermost
   pins sit 6% from the edge, so cropping means losing Hawaii or Australia —
   and object-fit: contain, which letterboxes: the render's top edge crosses
   Greenland, and a band of water above it does not read as sea. Matched to
   the file's own ratio, neither happens, and re-rendering at a different size
   cannot leave the stylesheet behind.

   The frame's ground is --ep-map-water, declared on .ep-map-row above, so the
   box reads as ocean in the moment before the image decodes.
   ------------------------------------------------------------------------ */
.ep-map-static {
  position: relative;
  margin: 0;
  aspect-ratio: var(--map-ratio);
  /* Both of these are about being a grid item next to the live panel.

     min-width: 0 because a grid item's automatic minimum is its min-content
     width, and aspect-ratio feeds a definite height back into that: stretched
     to the panel's height, the figure claimed 849 x 1.9 = 1613px of a 756px
     column and dragged the document 457px wider than the viewport.

     align-self: start so the figure keeps the height its own ratio gives it
     instead of being stretched to the row. Together with the panel's height: 0
     below, that makes the picture the thing that decides how tall the row is —
     which is right, because it is the thing whose proportions are fixed. */
  min-width: 0;
  align-self: start;
  overflow: hidden;
  background: var(--ep-map-water);
  border: 1px solid var(--ep-border);
  border-radius: var(--ep-radius-lg);
  box-shadow: var(--ep-shadow-md);
}

/* <picture> is an inline wrapper with no box of its own, so it shrink-to-fits
   its content — and its content is an image asked to be width: 100% of it.
   That circularity resolves to the file's intrinsic 1994px, which pushed the
   grid column, the container and the whole document wider than the viewport.
   Giving the wrapper the frame's box breaks the loop. */
.ep-map-static > picture {
  display: block;
  width: 100%;
  height: 100%;
}

.ep-map-static__img {
  display: block;
  width: 100%;
  height: 100%;
  /* Box and image share one ratio, so this crops and letterboxes nothing. It
     is here for the case where they ever disagree: better a few pixels of the
     ocean margin lost than the frame's proportions bent. */
  object-fit: cover;
}

/* MapTiler and OpenStreetMap have to be credited. Kept as real text in the
   corner rather than flattened into the pixels, so it stays sharp at any
   display size and the links still work — the same pill treatment leaflet.css
   gives the live map's attribution control. */
.ep-map-static__attrib {
  position: absolute;
  right: var(--ep-space-3);
  bottom: var(--ep-space-3);
  padding: 2px var(--ep-space-3);
  border-radius: var(--ep-radius-pill);
  background: var(--ep-bg-card);
  color: var(--ep-text-secondary);       /* 7.19:1 on card */
  font-size: var(--ep-text-xs);
  line-height: var(--ep-leading-snug);
}

.ep-map-static__attrib a {
  color: var(--ep-primary);              /* 6.41:1 on card */
}

@media (max-width: 575.98px) {
  .ep-map-static {
    aspect-ratio: var(--map-ratio-narrow);
  }
}

@media (max-width: 1199.98px) {
  .ep-map-row {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* The panel ships `hidden` and stays that way with JavaScript off or when the
   endpoint has nothing to return. A `display: none` grid item still leaves its
   explicit column in the template, so without this the map kept its narrowed
   width and sat beside 21rem of nothing — the one case where this feature must
   be invisible was the one where it left a hole. Same :has() approach the card
   component already uses in ecopi-components.css. */
.ep-map-row:has(> .ep-live-panel[hidden]) {
  grid-template-columns: minmax(0, 1fr);
}

.ep-section-heading--dashboard {
  margin-bottom: var(--ep-space-4);
}

.ep-section-heading > .ep-worldwide-heading {
  max-width: none;
}

.ep-worldwide-heading {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 0;
}

.ep-worldwide-heading__title {
  text-align: center;
}

.ep-worldwide-heading .ep-live-status {
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  white-space: nowrap;
}

/* Below 992px the "Live" badge sits below the title (stacked), not overlaid
   beside it. The absolute-positioned badge needs roughly 230px of its own
   space on the right, and the centred title needs room too — below 992px the
   two collide, with the badge overlapping the title's last word. */
@media (max-width: 991.98px) {
  .ep-worldwide-heading {
    flex-direction: column;
    gap: var(--ep-space-2);
  }
  .ep-worldwide-heading .ep-live-status {
    position: static;
    transform: none;
  }
}

.ep-live-status,
.ep-refresh-time {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
}

.ep-live-status {
  gap: var(--ep-space-3);
}

.ep-refresh-time {
  gap: var(--ep-space-1);
  color: var(--ep-text-muted);
  font-size: var(--ep-text-xs);
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  white-space: nowrap;
}

.ep-refresh-time svg {
  width: 0.9rem;
  height: 0.9rem;
}

/* ---- Active + cumulative dashboard -------------------------------------
   The active footprint spans the row above the map/audio pair. Cumulative
   history is a separate full-width panel below it, so the two scopes remain
   clear without competing for the same narrow two-column area. */
.ep-monitoring-group {
  display: flex;
  min-width: 0;
  flex-direction: column;
  margin-bottom: var(--ep-space-5);
}

.ep-monitoring-group--active {
  margin-bottom: var(--ep-space-5);
}

.ep-monitoring-group--cumulative {
  margin-top: var(--ep-space-7);
}

.ep-monitoring-group__head {
  margin-bottom: var(--ep-space-4);
}

.ep-monitoring-group__head h3 {
  margin: 0;
  font-size: var(--ep-h4);
}

.ep-dashboard-stats {
  display: grid;
  gap: var(--ep-space-3);
  margin: 0;
}

.ep-dashboard-stats--active {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  align-items: stretch;
}

/* On small screens the three stat cards are too narrow to read: the value
   font shrinks past legibility and the taxonomy chips inside the third card
   overflow off-screen. Stack them full-width instead, with the taxonomy chips
   wrapping into a 2×2 grid below. The breakpoint is 992px, not 576px, because
   the three-card row needs roughly 300px per card to keep the value legible
   and the chips from overflowing — below that the stack is the better layout. */
@media (max-width: 991.98px) {
  .ep-dashboard-stats--active {
    grid-template-columns: 1fr;
  }

  .ep-dashboard-stats--active .ep-dashboard-stat {
    min-height: 5rem;
    flex-direction: row;
    justify-content: flex-start;
    gap: var(--ep-space-4);
    text-align: left;
  }

  .ep-dashboard-stats--active .ep-dashboard-stat dt {
    flex-direction: row;
    gap: var(--ep-space-3);
  }

  /* Two classes, because the row-direction rule above is also two and would
     otherwise win. It used to be one: the taxonomy card was a bare <dd> that
     never matched .ep-dashboard-stat at all, so a single class was enough.
     Now that it is a proper card, the same-name selector lost the cascade and
     the card turned sideways — chips beside the label, refusing to shrink,
     184px out past the frame. */
  .ep-dashboard-stats--active .ep-dashboard-stat--taxonomy {
    flex-direction: column;
    align-items: stretch;
  }

  .ep-dashboard-stat--taxonomy .ep-taxonomy-chips {
    gap: var(--ep-space-2);
  }
}
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* Taxonomy chips in the third stat-card slot. The card look, the dt/dd order
   and the label type all come from .ep-dashboard-stat, which this card now
   carries like its two siblings — it used to be a bare <dd> that redeclared
   the lot with !important. What is left here is only what is specific to
   holding chips instead of a single number. */
.ep-dashboard-stat--taxonomy dd {
  width: 100%;
  min-width: 0;
}

.ep-dashboard-stat--taxonomy .ep-taxonomy-chips {
  display: grid;
  /* One equal column per visible chip, rather than four fixed tracks. A group
     with no confirmed species ships `hidden`, so it is not a grid item at all,
     and the fixed four left a whole track empty while "Amphibians" overflowed
     its 62px chip in the 992-1200px band. Today three groups have confirmed
     species, so three chips each take a third.

     Not repeat(auto-fit, minmax(…)): auto-fit needs a definite container
     width to work out its repeat count, and inside this card it does not have
     one — it resolved to a single column and stacked the chips three rows
     deep, doubling the height of all three cards in the row. auto-columns
     needs no such thing.

     grid-template-columns: none is required, not tidiness: the base
     .ep-taxonomy-chips rule further down still declares four explicit tracks,
     and while those stand the auto-columns below are never consulted. */
  grid-template-columns: none;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  align-items: center;
  justify-content: center;
  gap: var(--ep-space-2);
  margin: 0;
  flex-wrap: nowrap;
}

/* Below 480px even a full-width card is too narrow for four chips in a row
   — the icon, count and label in each chip need at least ~80px each, and
   4 × 80 = 320px before gaps. Switch to 2×2 only on the smallest screens. */
@media (max-width: 479.98px) {
  .ep-dashboard-stat--taxonomy .ep-taxonomy-chips {
    /* Back to explicit tracks, and back to row flow with them — column flow
       would keep adding columns past the two rather than wrapping. */
    grid-auto-flow: row;
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.ep-dashboard-stat {
  display: flex;
  min-width: 0;
  align-items: center;
  flex-direction: column;
  justify-content: center;
  padding: var(--ep-space-4);
  border: 1px solid var(--ep-border);
  border-radius: var(--ep-radius-lg);
  background: var(--ep-bg-card);
  box-shadow: var(--ep-shadow-sm);
  text-align: center;
  min-height: 7rem;
}

.ep-dashboard-stat dt {
  display: flex;
  flex: 0 0 auto;
  order: 1;
  align-items: center;
  flex-direction: column;
  gap: var(--ep-space-2);
  margin: 0;
  color: var(--ep-text-secondary);
  font-size: var(--ep-text-sm);
  font-weight: 600;
  line-height: var(--ep-leading-snug);
}

.ep-dashboard-stat dd {
  display: block;
  flex: 0 0 auto;
  order: 2;
  margin: var(--ep-space-2) 0 0;
}

.ep-dashboard-icon {
  display: grid;
  width: 2.65rem;
  height: 2.65rem;
  flex: 0 0 auto;
  place-items: center;
  border-radius: var(--ep-radius-md);
  background: var(--ep-primary-faint);
  color: var(--ep-primary);
}

.ep-dashboard-icon svg,
.ep-taxonomy-chip__icon svg {
  width: 1.45rem;
  height: 1.45rem;
}

.ep-dashboard-stat__value {
  font-family: var(--ep-font-body);
  font-size: clamp(2rem, 3vw, 2.75rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: var(--ep-leading-tight);
}

.ep-dashboard-stats--active .ep-dashboard-stat {
  min-height: 9rem;
}

.ep-dashboard-stat__label {
  min-width: 0;
}

.ep-dashboard-stats--active .ep-dashboard-stat__value {
  font-size: clamp(1.9rem, 3vw, 2.45rem);
}

.ep-cumulative-card {
  min-width: 0;
}

.ep-dashboard-stats--cumulative {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.ep-dashboard-stat--large {
  min-height: 9rem;
}

.ep-dashboard-stat--large .ep-dashboard-stat__value {
  font-size: clamp(1.9rem, 3vw, 2.55rem);
}

.ep-monitoring-taxonomy {
  margin-top: var(--ep-space-5);
}

.ep-monitoring-taxonomy__label {
  margin: 0;
  color: var(--ep-text);
  font-size: var(--ep-text-sm);
  font-weight: 700;
}

.ep-taxonomy-chips {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--ep-space-3);
  margin-top: var(--ep-space-3);
}

.ep-taxonomy-chip {
  display: flex;
  min-width: 0;
  align-items: center;
  flex-direction: column;
  justify-content: center;
  gap: var(--ep-space-2);
  min-height: 7.5rem;
  padding: var(--ep-space-3);
  border: 1px solid var(--ep-border);
  border-radius: var(--ep-radius-lg);
  background: var(--ep-bg-card);
  box-shadow: var(--ep-shadow-sm);
  color: var(--ep-text-secondary);
  font-size: var(--ep-text-xs);
  line-height: var(--ep-leading-snug);
  text-align: center;
}

.ep-taxonomy-chip__icon {
  display: grid;
  width: 2.65rem;
  height: 2.65rem;
  flex: 0 0 auto;
  place-items: center;
  border-radius: var(--ep-radius-md);
  background: var(--ep-primary-faint);
  color: var(--ep-primary);
}

.ep-taxonomy-chip__copy,
.ep-taxonomy-chip__count {
  display: block;
  min-width: 0;
}

.ep-taxonomy-chip__count {
  color: var(--ep-text);
  font-family: var(--ep-font-body);
  font-size: clamp(1.45rem, 2.5vw, 2rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: var(--ep-leading-tight);
}

@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .ep-dashboard-stat,
  .ep-taxonomy-chip {
    transition: border-color var(--ep-duration-base) var(--ep-ease),
                box-shadow var(--ep-duration-base) var(--ep-ease);
  }

  .ep-dashboard-stat:hover,
  .ep-taxonomy-chip:hover {
    border-color: var(--ep-border-strong);
    box-shadow: var(--ep-shadow-md);
  }
}

@media (max-width: 575.98px) {
  .ep-worldwide-heading {
    gap: var(--ep-space-2);
  }

  .ep-live-status {
    gap: var(--ep-space-2);
  }

  .ep-refresh-time__label {
    position: absolute;
    overflow: hidden;
    width: 1px;
    height: 1px;
    padding: 0;
    border: 0;
    margin: -1px;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
  }

  .ep-dashboard-stats {
    gap: var(--ep-space-2);
  }

  .ep-dashboard-stat {
    padding: var(--ep-space-3);
  }

  .ep-dashboard-stat dt {
    font-size: var(--ep-text-xs);
  }

  .ep-dashboard-stat__value {
    font-size: clamp(1.65rem, 8vw, 2.1rem);
  }

  .ep-dashboard-icon {
    width: 2.15rem;
    height: 2.15rem;
  }

  .ep-dashboard-icon svg {
    width: 1.2rem;
    height: 1.2rem;
  }

  .ep-dashboard-stat--large {
    min-height: 7.5rem;
  }

  .ep-dashboard-stat--large .ep-dashboard-stat__value {
    font-size: clamp(1.75rem, 9vw, 2.25rem);
  }

  .ep-taxonomy-chips {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .ep-taxonomy-chip {
    min-height: 7rem;
  }

  .ep-taxonomy-chip__icon {
    width: 2.15rem;
    height: 2.15rem;
  }
}

/* ---- The panel ----------------------------------------------------------
   display: flex does not fight the `hidden` attribute this element ships with:
   Bootstrap's reboot carries `[hidden] { display: none !important }` and loads
   before this file, so the attribute always wins. Verified in the browser
   rather than assumed, because an author `display` normally does beat the
   user-agent rule for [hidden].
   ------------------------------------------------------------------------ */
.ep-live-panel {
  display: flex;
  flex-direction: column;
  min-width: 0;
  padding: var(--ep-space-4);
  border: 1px solid var(--ep-border);
  border-radius: var(--ep-radius-lg);
  background: var(--ep-bg-card);
  box-shadow: var(--ep-shadow-md);
}

.ep-live-panel__head {
  margin-bottom: var(--ep-space-3);
}

.ep-live-panel__title {
  margin: 0;
  font-family: var(--ep-font-body);
  font-size: var(--ep-text-base);
  font-weight: 700;
  line-height: var(--ep-leading-snug);
}

/* Matches the map's height on desktop so the row reads as two panes of one
   element. On narrow screens the panel is stacked and can simply be as tall as
   its content — capping it there would produce a scroll area inside a page
   that already scrolls. */
.ep-live-panel__list {
  display: flex;
  flex: 1;
  min-height: 0;
  flex-direction: column;
  gap: var(--ep-space-2);
  margin: 0;
  padding: 0;
  list-style: none;
  overflow-y: auto;
}

@media (min-width: 1200px) {
  /* 600px used to be here, because the map was 600px tall. The static map sets
     its own height from its aspect ratio, so a fixed number would drift out of
     step with the image on the next render.

     height: 0 with min-height: 100% is how the panel follows it. A grid item's
     content height feeds row sizing, and ten cards are taller than the map, so
     the panel would otherwise set the row height and leave the picture short in
     a tall box. At height: 0 it contributes nothing, the map sizes the row, and
     min-height: 100% then stretches the panel back to exactly that. The list
     already scrolls (flex: 1, min-height: 0, overflow-y), which is what makes
     the panel safe to shrink. */
  .ep-live-panel {
    height: 0;
    min-height: 100%;
  }

  .ep-live-panel__list {
    max-height: none;
  }

  /* is-scrollable is set by audio-preview.js only when the content actually
     overflows. It has to be measured rather than assumed: applied
     unconditionally, the fade would dim the last card of a list that fits
     perfectly well, inventing the very "something is cut off" impression it
     exists to explain. */
  .ep-live-panel__list.is-scrollable {
    mask-image: linear-gradient(to bottom, #000 calc(100% - 1.25rem), transparent 100%);
  }
}

/* ---- One recording ------------------------------------------------------
   Deliberately not .ep-card: that component is a 16/10 media card built for a
   three-across grid, and every one of its parts (aspect-ratio media box,
   space-5 body padding, h4 title) would have to be overridden to fit a 21rem
   column. This is the same visual language — border, radius, card background,
   hover lift — at the size this column actually has.
   ------------------------------------------------------------------------ */
/* Vertical padding stays compact because the panel now carries ten cards. The
   desktop list scrolls inside the fixed-height map row; stacked layouts show
   the full list in normal page flow. */
.ep-live-item {
  display: flex;
  gap: var(--ep-space-3);
  align-items: center;
  padding: var(--ep-space-1) var(--ep-space-3);
  border: 1px solid var(--ep-border);
  border-radius: var(--ep-radius-md);
  background: var(--ep-bg-page);
  transition: border-color var(--ep-duration-base) var(--ep-ease),
              background-color var(--ep-duration-base) var(--ep-ease);
}

.ep-live-item:hover {
  border-color: var(--ep-border-strong);
}

/* The card whose clip is currently playing. */
.ep-live-item.is-playing {
  border-color: var(--ep-primary);
  background: var(--ep-primary-faint);
}

/* ---- Play button --------------------------------------------------------
   A real <button>, so it is reachable by keyboard and announced as a control.
   The glyph is a CSS triangle/pause pair rather than an icon font or SVG file:
   two shapes at one size, and no extra request.
   ------------------------------------------------------------------------ */
.ep-live-item__play {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  padding: 0;
  border: none;
  border-radius: var(--ep-radius-pill);
  background: var(--ep-primary);
  color: var(--ep-text-inverse);
  cursor: pointer;
  transition: background-color var(--ep-duration-fast) var(--ep-ease),
              transform var(--ep-duration-fast) var(--ep-ease);
}

.ep-live-item__play:hover {
  background: var(--ep-primary-hover);
}

.ep-live-item__play:active {
  transform: scale(0.94);
}

.ep-live-item__play:focus-visible {
  outline: 3px solid var(--ep-primary);
  outline-offset: 2px;
}

/* Play triangle. Sits 1px right of centre because a triangle's optical centre
   is left of its bounding box. */
.ep-live-item__play::before {
  content: "";
  width: 0;
  height: 0;
  margin-left: 2px;
  border-style: solid;
  border-width: 0.4rem 0 0.4rem 0.65rem;
  border-color: transparent transparent transparent currentColor;
}

/* Pause bars, for the one card that is playing. */
.is-playing .ep-live-item__play::before {
  width: 0.6rem;
  height: 0.8rem;
  margin-left: 0;
  border: none;
  background: currentColor;
  /* Two bars from one box: a centre gap cut out of a solid block. */
  clip-path: polygon(0 0, 36% 0, 36% 100%, 0 100%,
                     0 0, 64% 0, 100% 0, 100% 100%, 64% 100%, 64% 0);
}

/* While the clip is loading, before it starts playing. */
.ep-live-item.is-loading .ep-live-item__play {
  background: var(--ep-text-muted);
}

/* ---- Card text ---------------------------------------------------------- */
.ep-live-item__body {
  min-width: 0; /* lets long species names ellipsize instead of widening the grid */
  flex: 1;
}

.ep-live-item__species {
  display: block;
  font-weight: 700;
  font-size: var(--ep-text-sm);
  line-height: var(--ep-leading-snug);
  color: var(--ep-text);
}

.ep-live-item__scientific {
  display: block;
  font-size: var(--ep-text-xs);
  font-style: italic;
  color: var(--ep-text-muted);
}

.ep-live-item__meta {
  display: block;
  font-size: var(--ep-text-xs);
  color: var(--ep-text-secondary);
}

/* ---- Live badge --------------------------------------------------------
   Sits next to the section heading. "Live" describes the data feed — the panel
   re-polls without a reload — not the age of the clip: confirmation is a manual
   step, so the newest confirmed recording is usually a day or two old.
   ------------------------------------------------------------------------ */
.ep-live-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--ep-space-2);
  transform: none;
  padding: 0.15rem var(--ep-space-3) 0.15rem var(--ep-space-2);
  border-radius: var(--ep-radius-pill);
  background: var(--ep-danger);
  color: #fff;
  font-size: var(--ep-text-xs);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  vertical-align: middle;
}

.ep-live-badge__dot {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: currentColor;
}

@media (max-width: 575.98px) {
  .ep-worldwide-heading .ep-live-badge {
    gap: var(--ep-space-1);
    padding: 0.12rem var(--ep-space-2);
    font-size: 0.68rem;
  }

  .ep-live-badge__dot {
    width: 0.4rem;
    height: 0.4rem;
  }
}

/* Opt in to the pulse rather than out of it, so reduced-motion users get a
   plain steady dot — same approach as the flow icons in pages/journey.css. */
@media (prefers-reduced-motion: no-preference) {
  .ep-live-badge__dot {
    animation: ep-live-pulse 2s var(--ep-ease) infinite;
  }
}

@keyframes ep-live-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.35; transform: scale(0.8); }
}
