/* ════════════════════════════════════════════════════════════════════════
 * dp-dreamjam.css — everything on /dreamjam BELOW the hero.
 *
 * The hero (the DREAM/JAM lockup, the countdown tiles, the aurora and the
 * chord toy) keeps its own inline <style> in views/dreamjam.ejs, because
 * it is a one-off illustration and nothing else will ever use it. THE
 * PAGE BACKGROUND is not in either place: it lives on <body> and is fixed
 * to the viewport, so the hero and everything under it stand on one
 * continuous field rather than on two gradients meeting at a seam.
 *
 * This file is the part of the page that is a PRODUCT SURFACE, and it is
 * deliberately small, because almost none of it is new:
 *
 *   the entry grid   → .dp-grid       (dp-attraction-feed.css)
 *   the entry tiles  → .dpc           (dp-attraction-card.css)
 *   the park cards   → .shr-park      (views/share/share-styles.ejs)
 *   buttons          → .shr-cta       (ditto)
 *
 * What is here is the connective tissue those four do not have: the
 * timeline, the podium marks, the vote button, the volunteer tile and its
 * picker. If a rule in this file restates something one of the four
 * already does, it is a bug — delete it and compose.
 * ════════════════════════════════════════════════════════════════════ */

.jamx {
  --jamx-gold: var(--mdp-ui-gold, #ffd166);
  --jamx-silver: #d7dde8;
  --jamx-bronze: #d79a63;

  /* ── Panels for a LIT ground ──────────────────────────────────────
   * The share components' surfaces are translucent WHITE, tuned for the
   * near-black share page. On this page the ground is bright violet, and
   * white-on-violet at 3% opacity is invisible — a park card would have
   * dissolved into the background.
   *
   * So the surfaces are inverted to translucent INK for this page only.
   * The gradient still reads through them, which is the point: the cards
   * sit ON the stage rather than covering it up. Overriding the four
   * --sh-* tokens is the whole change; not one .shr-* rule is touched.  */
  --sh-surface: rgba(24, 4, 48, 0.34);
  --sh-surface-2: rgba(24, 4, 48, 0.46);
  --sh-surface-hover: rgba(24, 4, 48, 0.52);
  --sh-border: rgba(255, 255, 255, 0.17);
  --sh-line: rgba(255, 255, 255, 0.22);

  position: relative;
  z-index: 1;
  color: #fff;
  padding-bottom: clamp(30px, 5vh, 56px);
}

/* One measure for the whole lower page, matching the share pages' column
   so a park card here is the same width as a park card there. */
.jamx-wrap {
  width: 100%;
  max-width: 1180px;
  margin: 0 auto;
  padding: 0 clamp(18px, 5vw, 40px);
}

/* Tighter than the share pages' 46px section rhythm. This page is a
   sequence of short sections rather than a long read, and at 46px the
   gaps were doing more work than the content. */
.jamx-sec { padding: clamp(22px, 4vh, 40px) 0 0; }

/* share-styles gives every .shr-section a 46px top margin for the share
   pages' rhythm. Inside a .jamx-sec that is a second gap paid twice. */
.jamx-sec > .shr-section:first-child { margin-top: 0; }

/* ── The scroll cue ────────────────────────────────────────────────────
 * The hero is most of a viewport, so without this the entries do not
 * exist for anyone who does not think to scroll. A quiet chevron, and a
 * real anchor so it works with a keyboard and without JS. */
.jam-cue {
  position: relative;
  z-index: 2;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  margin-top: clamp(14px, 2.6vh, 24px);
  padding: 8px 14px;
  border-radius: 999px;
  color: rgba(255, 255, 255, 0.82);
  font-family: var(--mdp-ui-display, 'Russo One', sans-serif);
  font-size: 10px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  text-decoration: none;
  transition: color 0.2s ease, transform 0.2s ease;
}
.jam-cue:hover { color: #fff; transform: translateY(2px); }
.jam-cue svg { animation: jam-cue-bob 2.4s ease-in-out infinite; }
@keyframes jam-cue-bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(4px); }
}

.jam-theme {
  margin-top: clamp(8px, 1.5vh, 12px);
  max-width: 40ch;
  font-size: clamp(0.95rem, 2vw, 1.1rem);
  font-weight: 600;
  color: #fff;
}
.jam-theme em { font-style: normal; color: var(--jam-gold, #ffd166); }

/* ══════════════════════════════════════════════════════════════════════
 * THE TIMELINE
 *
 * THE DATE IS THE HEADING. That is the thing being looked up — "when do I
 * have to have this done by", "which Saturday" — so it is the largest
 * type in the node and everything else hangs under it as a sentence.
 *
 * Three equal facts, presented equally. The previous version highlighted
 * one row in gold and greyed another, which answered a question the
 * countdown in the hero already answers, and made three dates look like
 * one instruction and two errors.
 * ═════════════════════════════════════════════════════════════════════ */

.jam-tl {
  list-style: none;
  margin: 0;
  padding: 0;
  position: relative;
}

.jam-tl-node {
  position: relative;
  padding: 0 0 clamp(22px, 3.4vh, 34px) clamp(26px, 3.4vw, 38px);
}
.jam-tl-node:last-child { padding-bottom: 0; }

/* The rail, drawn per node rather than once down the list, so the last
   node's line stops at its own dot instead of running past it into
   whitespace. */
.jam-tl-node::before {
  content: '';
  position: absolute;
  left: 5px;
  top: 14px;
  bottom: 0;
  width: 2px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.24), rgba(255, 255, 255, 0.08));
}
.jam-tl-node:last-child::before { display: none; }

.jam-tl-node::after {
  content: '';
  position: absolute;
  left: 0;
  top: 7px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.16);
}

.jam-tl-date {
  margin: 0;
  font-family: 'Zalando Sans Expanded', var(--mdp-ui-heading, sans-serif);
  font-weight: 900;
  font-size: clamp(1.15rem, 2.9vw, 1.65rem);
  line-height: 1.15;
  letter-spacing: -0.01em;
}

.jam-tl-what {
  margin: 6px 0 0;
  max-width: 62ch;
  font-size: clamp(0.92rem, 1.9vw, 1rem);
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.78);
}
.jam-tl-what strong { color: #fff; font-weight: 700; }

/* The venue grid, inside the park-play node. .shr-parks supplies the
   columns; this only sets how far it sits off the sentence above it. */
.jam-tl-parks { margin-top: clamp(14px, 2.2vw, 20px); }


/* ── The volunteer tile ────────────────────────────────────────────────
 * Exactly a park card's footprint, dashed, so it reads as an empty slot
 * in the row of venues rather than as a button parked beside them. The
 * 16/10 block matches .shr-park .map; the label block matches .shr-park
 * .row, which is what keeps the tile the same height as its neighbours
 * without hardcoding one. */
.jam-host-add {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 100%;
  padding: clamp(18px, 3vw, 26px) 16px;
  border-radius: 18px;
  border: 1.5px dashed rgba(255, 255, 255, 0.32);
  background: rgba(255, 255, 255, 0.04);
  color: rgba(255, 255, 255, 0.86);
  font-family: inherit;
  cursor: pointer;
  text-align: center;
  transition: border-color 0.18s ease, background 0.18s ease, transform 0.18s ease, color 0.18s ease;
}
.jam-host-add:hover {
  border-color: rgba(255, 255, 255, 0.6);
  background: rgba(255, 255, 255, 0.09);
  color: #fff;
  transform: translateY(-2px);
}
.jam-host-add:focus-visible { outline: 2px solid var(--jamx-gold); outline-offset: 3px; }

.jam-host-add-plus {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  border: 1.5px dashed rgba(255, 255, 255, 0.34);
  margin-bottom: 2px;
}
.jam-host-add-label {
  font-family: var(--mdp-ui-heading, 'Open Sans', system-ui, sans-serif);
  font-size: 15px;
  font-weight: 800;
}
.jam-host-add-sub {
  font-size: 11.5px;
  color: rgba(255, 255, 255, 0.6);
}

/* ══════════════════════════════════════════════════════════════════════
 * THE VOLUNTEER PICKER
 * ═════════════════════════════════════════════════════════════════════ */

.jam-modal {
  position: fixed;
  inset: 0;
  z-index: 400;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: clamp(16px, 5vh, 56px) clamp(12px, 4vw, 32px);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.jam-modal[hidden] { display: none; }

.jam-modal-scrim {
  position: fixed;
  inset: 0;
  background: rgba(14, 2, 30, 0.72);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

.jam-modal-box {
  position: relative;
  width: 100%;
  max-width: 720px;
  margin: auto;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 22px;
  border: 1px solid rgba(255, 255, 255, 0.16);
  /* Opaque, unlike the panels on the page itself: a dialog has to sit in
     front of the stage, not on it. */
  background: linear-gradient(180deg, #2c0a55 0%, #1c0637 100%);
  box-shadow: 0 40px 90px -30px rgba(0, 0, 0, 0.8);
}

.jam-modal-x {
  position: absolute;
  top: 14px;
  right: 14px;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.16);
  background: rgba(255, 255, 255, 0.06);
  color: #fff;
  cursor: pointer;
}
.jam-modal-x:hover { background: rgba(255, 255, 255, 0.14); }

.jam-modal-title {
  margin: 0 40px 6px 0;
  font-family: 'Zalando Sans Expanded', var(--mdp-ui-heading, sans-serif);
  font-weight: 900;
  font-size: clamp(1.15rem, 3vw, 1.5rem);
}
.jam-modal-sub {
  margin: 0 0 18px;
  max-width: 58ch;
  font-size: 0.93rem;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.7);
}

.jam-modal-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 12px;
  max-height: 46vh;
  overflow-y: auto;
  padding: 2px;
}
.jam-modal-loading,
.jam-modal-none {
  grid-column: 1 / -1;
  margin: 0;
  padding: 26px 4px;
  text-align: center;
  font-size: 0.92rem;
  color: rgba(255, 255, 255, 0.6);
}

/* One selectable park. A real <button> with aria-pressed, not a div with
   a click handler, so it is reachable and its state is announced. */
.jam-pick {
  display: block;
  width: 100%;
  padding: 0;
  overflow: hidden;
  border-radius: 14px;
  border: 1.5px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.05);
  color: #fff;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  transition: border-color 0.16s ease, background 0.16s ease, transform 0.12s ease;
}
.jam-pick:hover:not(:disabled) { border-color: rgba(255, 255, 255, 0.4); background: rgba(255, 255, 255, 0.09); }
.jam-pick:focus-visible { outline: 2px solid var(--jamx-gold); outline-offset: 2px; }
.jam-pick[aria-pressed="true"] {
  border-color: var(--jamx-gold);
  background: rgba(255, 209, 102, 0.14);
}

.jam-pick-map {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 16 / 10;
  background:
    radial-gradient(60% 70% at 50% 45%, rgba(119, 0, 255, 0.3), transparent 72%),
    rgba(255, 255, 255, 0.04);
}
.jam-pick-map img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
.jam-pick-body { display: block; padding: 10px 12px 12px; }
.jam-pick-name {
  display: block;
  font-family: var(--mdp-ui-heading, 'Open Sans', system-ui, sans-serif);
  font-size: 14px;
  font-weight: 800;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.jam-pick-loc { display: block; margin-top: 2px; font-size: 11.5px; color: rgba(255, 255, 255, 0.58); }

/* ── Not eligible ──────────────────────────────────────────────────────
 * Dimmed and unclickable, but still SHOWN and still legible enough to
 * read the reason. A park that vanished from this list would look like a
 * bug in our software; one that says "needs 2 more subscribers" is a
 * to-do. That is the whole reason these are rendered at all. */
.jam-pick:disabled { cursor: default; }
.jam-pick--blocked { border-style: dashed; border-color: rgba(255, 255, 255, 0.12); background: transparent; }
.jam-pick--blocked .jam-pick-map { filter: grayscale(1); opacity: 0.34; }
.jam-pick--blocked .jam-pick-name { color: rgba(255, 255, 255, 0.5); }
.jam-pick--blocked .jam-pick-loc { color: rgba(255, 255, 255, 0.34); }

.jam-pick-why {
  display: block;
  margin-top: 6px;
  font-size: 11px;
  line-height: 1.45;
  color: var(--mdp-ui-gold, #ffd166);
  opacity: 0.85;
}
.jam-pick-tag {
  display: inline-block;
  margin-top: 6px;
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.2);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.62);
}
.jam-pick-tag--live { border-color: rgba(0, 245, 160, 0.5); color: var(--mdp-ui-xp, #00f5a0); }

.jam-modal-rule {
  margin: 16px 0 0;
  padding: 12px 14px;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.05);
  font-size: 0.85rem;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.66);
}
.jam-modal-rule strong { color: #fff; font-weight: 700; }

.jam-modal-foot {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  margin-top: 16px;
}
.jam-modal-foot input[type="text"] {
  flex: 1 1 220px;
  min-width: 0;
  padding: 12px 14px;
  border-radius: 12px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  background: rgba(0, 0, 0, 0.28);
  color: #fff;
  font-family: inherit;
  font-size: 0.95rem;
}
.jam-modal-foot input:focus-visible { outline: 2px solid var(--jamx-gold); outline-offset: 1px; }
.jam-modal-foot .shr-cta:disabled { opacity: 0.45; cursor: default; }
.jam-modal-msg {
  flex-basis: 100%;
  margin: 0;
  font-size: 0.9rem;
  color: var(--mdp-ui-xp, #00f5a0);
}
.jam-modal-msg.is-error { color: #ff8f8f; }

body.jam-modal-open { overflow: hidden; }

/* ══════════════════════════════════════════════════════════════════════
 * ENTRIES
 * ═════════════════════════════════════════════════════════════════════ */

/* The grid comes from dp-attraction-feed.css untouched. .jam-entry is a
 * grid item wrapping one card so the medal and the heart have somewhere
 * to live that is not INSIDE the card's single hit target — see the note
 * at the top of views/partials/jam-entries.ejs. */
.jam-entry {
  position: relative;
  min-width: 0;
  display: flex;
  flex-direction: column;
}
.jam-entry > .dpc { flex: 1 1 auto; }

/* The podium ring.
 *
 * An outline and not a border: .dpc is a container-query container whose
 * every dimension is a percentage of its own width, so adding 3px of
 * border to three cards out of twenty would render those three at a
 * different scale than the rest of the grid. An outline is drawn outside
 * the box and costs no layout, so a medallist is the same card as
 * everything else with a ring around it. */
.jam-entry--gold > .dpc,
.jam-entry--silver > .dpc,
.jam-entry--bronze > .dpc {
  outline: 2.5px solid var(--ring, transparent);
  outline-offset: 3px;
  border-radius: clamp(14px, 7cqw, 26px);
}
.jam-entry--gold   { --ring: var(--jamx-gold, #ffd166); }
.jam-entry--silver { --ring: var(--jamx-silver, #d7dde8); }
.jam-entry--bronze { --ring: var(--jamx-bronze, #d79a63); }

.jam-entry--gold > .dpc   { box-shadow: 0 0 38px -6px rgba(255, 209, 102, 0.45); }
.jam-entry--silver > .dpc { box-shadow: 0 0 30px -8px rgba(215, 221, 232, 0.32); }
.jam-entry--bronze > .dpc { box-shadow: 0 0 30px -8px rgba(215, 154, 99, 0.32); }

/* THE CROWN SITS ON TOP OF THE CARD, half above its edge, so it reads as
 * something placed on the object rather than a badge printed on it. That
 * overhang is why .dp-grid's row-gap is the bigger of its two gaps — the
 * mark has somewhere to hang into. */
.jam-medal {
  position: absolute;
  top: -13px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 3;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  color: #241004;
  font-family: var(--mdp-ui-display, 'Russo One', sans-serif);
  font-size: 13px;
  line-height: 1;
  pointer-events: none;
  box-shadow: 0 6px 18px -6px rgba(0, 0, 0, 0.7), inset 0 1px 0 rgba(255, 255, 255, 0.55);
}
.jam-medal--gold   { background: linear-gradient(180deg, #ffe6a3, #ffd166 60%, #e0a92f); }
.jam-medal--silver { background: linear-gradient(180deg, #ffffff, #d7dde8 60%, #a7b0bf); }
.jam-medal--bronze { background: linear-gradient(180deg, #f0c39a, #d79a63 60%, #a86f3c); }
.jam-medal--gold   { width: 38px; height: 38px; top: -16px; }
.jam-medal-n { transform: translateY(0.5px); }

/* ── The heart ─────────────────────────────────────────────────────────
 * Under the card, full width, and a real button. Under rather than over
 * because everything drawn ON a tile in this design system belongs to the
 * preview rect (see the note in dp-attraction-card.js), and a floating
 * heart over the footage would be the start of the chip strip that file
 * exists to have deleted. */
.jam-vote {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  width: 100%;
  margin-top: 8px;
  padding: 8px 10px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  background: rgba(24, 4, 48, 0.34);
  color: rgba(255, 255, 255, 0.9);
  font-family: var(--mdp-ui-body, 'Outfit', system-ui, sans-serif);
  font-size: 0.86rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background 0.18s ease, border-color 0.18s ease, color 0.18s ease, transform 0.12s ease;
}
.jam-vote:hover:not(:disabled) {
  background: rgba(24, 4, 48, 0.5);
  border-color: rgba(255, 255, 255, 0.34);
  color: #fff;
}
.jam-vote:active:not(:disabled) { transform: scale(0.97); }
.jam-vote:focus-visible { outline: 2px solid var(--jamx-gold); outline-offset: 2px; }

.jam-vote.is-voted {
  border-color: rgba(255, 62, 181, 0.6);
  background: rgba(255, 62, 181, 0.24);
  color: #fff;
}
.jam-vote.is-voted .jam-vote-heart { fill: var(--mdp-ui-pink, #ff3eb5); stroke: var(--mdp-ui-pink, #ff3eb5); }

/* Disabled is a SETTLED result, not a broken button, so it keeps its
   colour and only loses the pointer. A greyed-out final count reads as
   an error state. */
.jam-vote:disabled { cursor: default; opacity: 0.85; }
.jam-vote.is-busy { opacity: 0.6; pointer-events: none; }

/* The one-line refusal that replaces the count when the server says no
   (a self-vote, or a jam that closed while the page was open).
   The heart goes with it — a refusal is not a heart state, and dropping
   it buys the ~17px the sentence needs to fit across a card in a 2-up
   phone grid without ellipsising itself. */
.jam-vote.is-refused {
  border-color: rgba(255, 255, 255, 0.14);
  background: transparent;
  color: rgba(255, 255, 255, 0.55);
  font-size: 0.74rem;
  font-weight: 600;
  letter-spacing: -0.005em;
}
.jam-vote.is-refused .jam-vote-heart { display: none; }
.jam-vote.is-refused .jam-vote-n {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Under a heart animation the pop is the feedback, so it is short and it
   is the only thing that moves. */
@keyframes jam-heart-pop {
  0%   { transform: scale(1); }
  38%  { transform: scale(1.32); }
  100% { transform: scale(1); }
}
.jam-vote.is-just-voted .jam-vote-heart { animation: jam-heart-pop 0.36s cubic-bezier(0.34, 1.56, 0.64, 1); }

.jam-empty {
  margin: clamp(14px, 2.4vw, 22px) 0 0;
  padding: clamp(22px, 4vw, 36px) clamp(18px, 4vw, 32px);
  border-radius: 18px;
  border: 1px dashed rgba(255, 255, 255, 0.2);
  background: rgba(24, 4, 48, 0.24);
  text-align: center;
  color: rgba(255, 255, 255, 0.72);
  font-size: 0.98rem;
  line-height: 1.6;
}

/* ══════════════════════════════════════════════════════════════════════
 * A JAM BLOCK
 *
 * ONE SHAPE, REPEATED. The live jam, the one being voted on and every
 * archived jam use this exact header — name, deadline, entry count,
 * chevron — because they are the same kind of object and styling the
 * current one differently made a reader work out why.
 *
 * ALL OPEN BY DEFAULT. The chevron is an affordance for folding a jam
 * away, not a wall in front of one: what got made is the whole reason to
 * scroll down here, and hiding the archive behind a tap made it read as a
 * lesser kind of thing than the jam above it.
 * ═════════════════════════════════════════════════════════════════════ */

.jam-block + .jam-block { margin-top: clamp(14px, 2.4vw, 22px); }

.jam-block > details > summary { list-style: none; cursor: pointer; }
.jam-block > details > summary::-webkit-details-marker { display: none; }
.jam-block > details > summary:focus-visible {
  outline: 2px solid var(--jamx-gold);
  outline-offset: 3px;
  border-radius: 12px;
}

.jam-block-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 14px;
  padding: 12px 2px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.16);
  transition: border-color 0.18s ease;
}
.jam-block > details > summary:hover .jam-block-head { border-bottom-color: rgba(255, 255, 255, 0.4); }

.jam-block-name {
  margin: 0;
  font-family: 'Zalando Sans Expanded', var(--mdp-ui-heading, sans-serif);
  font-weight: 900;
  font-size: clamp(1.1rem, 2.6vw, 1.45rem);
  letter-spacing: -0.01em;
}
/* ── The state badge ───────────────────────────────────────────────────
 * Every block is deliberately the same shape, which is what makes the
 * list readable — and is exactly why one of them needs to say out loud
 * that it is the one you can still enter. Three states, three weights of
 * attention: LIVE pulses, VOTING is lit but still, PAST is a label.
 *
 * Sized off the header's own text so it sits on the name's baseline
 * rather than floating beside it. */
.jam-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px;
  border-radius: 999px;
  border: 1px solid currentColor;
  font-family: var(--mdp-ui-display, 'Russo One', sans-serif);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  line-height: 1.5;
  white-space: nowrap;
  align-self: center;
}
.jam-badge--live {
  color: var(--mdp-ui-xp, #00f5a0);
  background: rgba(0, 245, 160, 0.12);
}
.jam-badge--voting {
  color: var(--jamx-gold, #ffd166);
  background: rgba(255, 209, 102, 0.14);
}
/* Past is the quiet one: currentColor gives it a hairline of the same
   muted grey as its text, so it labels without competing. */
.jam-badge--past {
  color: rgba(255, 255, 255, 0.42);
  background: transparent;
}

.jam-badge-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
  animation: jam-badge-pulse 2s ease-out infinite;
}
@keyframes jam-badge-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(0, 245, 160, 0.7); }
  70%  { box-shadow: 0 0 0 8px rgba(0, 245, 160, 0); }
  100% { box-shadow: 0 0 0 0 rgba(0, 245, 160, 0); }
}

.jam-block-when { font-size: 0.86rem; color: rgba(255, 255, 255, 0.6); }
.jam-block-note { font-size: 0.86rem; color: var(--jamx-gold); }
.jam-block-count {
  margin-left: auto;
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
}
.jam-block-chev {
  flex-shrink: 0;
  align-self: center;
  color: rgba(255, 255, 255, 0.55);
  transition: transform 0.2s ease;
}
.jam-block > details[open] .jam-block-chev { transform: rotate(180deg); }

/* On a phone the count would wrap to its own line and drag the chevron
   with it; both are secondary, so they share a row under the name. */
@media (max-width: 560px) {
  .jam-block-count { margin-left: 0; }
}

/* ── Foot ─────────────────────────────────────────────────────────────── */
.jamx-foot {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 8px;
  margin-top: clamp(26px, 5vh, 52px);
  padding-top: clamp(18px, 2.6vh, 26px);
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  font-size: 0.76rem;
  color: rgba(255, 255, 255, 0.62);
  text-align: center;
}
.jamx-foot a { color: rgba(255, 255, 255, 0.8); text-decoration: none; padding: 6px 4px; }
.jamx-foot a:hover { color: #fff; }
.jamx-foot .sep { opacity: 0.4; }

@media (prefers-reduced-motion: reduce) {
  .jam-cue svg,
  .jam-badge-dot,
  .jam-vote.is-just-voted .jam-vote-heart { animation: none !important; }
  /* The dot still has to READ as live with the pulse gone, so it keeps a
     static ring rather than becoming an anonymous green circle. */
  .jam-badge-dot { box-shadow: 0 0 0 3px rgba(0, 245, 160, 0.25); }
  .jam-vote:active:not(:disabled),
  .jam-host-add:hover { transform: none; }
}
