/* =============================================================================
   THE PULSE — carousel beat (class "carousel")  ·  additive treatment
   -----------------------------------------------------------------------------
   A native, swipeable photo carousel folded into a feed card. The slides are a
   CSS scroll-snap track (real touch swipe, no JS needed to move); pulse.js only
   syncs the dots/counter and wires the desktop arrows + keyboard.

   GOVERNANCE (vault CLAUDE.md §31/§35): brand.css is THE KIT and is re-copied
   from world/brand.css every build — never edit it. This file is linked
   alongside it (like beat-burst.css / pulse-ui.css). Card CHROME (dots, counter,
   arrows, frame) uses kit tokens so it tracks the theme; the CAPTION text sits
   over a fixed-dark photo scrim, so it is hardcoded LIGHT on purpose — the kit's
   --linen flips to ink in light theme and would vanish on the photo (§35 trap).
   The kit hardcodes its font families (no --serif vars), so the families are
   named literally here to match: "DM Serif Display" / "Cormorant Garamond" /
   "Inter".
   ============================================================================= */

.pulse-stream .carousel-beat { margin: 2px 0 0; }

/* ---- stage: the viewport + the overlaid desktop arrows --------------------- */
.pulse-stream .carou-stage {
  position: relative;
  /* card corner = real-poker proportion (~5% of card width); the deck/oracle
     standard (vault card-ratio canon). ~28px reads poker at feed card widths. */
  border-radius: 28px;
  overflow: hidden;
  border: 1px solid var(--line);
  background: #0A0907;
}

/* ---- viewport: the scroll-snap rail --------------------------------------- */
.pulse-stream .carou-viewport {
  display: flex;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;          /* Firefox */
  overscroll-behavior-x: contain;
}
.pulse-stream .carou-viewport::-webkit-scrollbar { display: none; }   /* WebKit */
@media (prefers-reduced-motion: reduce) {
  .pulse-stream .carou-viewport { scroll-behavior: auto; }
}

/* ---- slide: native Pulse card, 5:7 default, ratio-per-slide ----------------
   THE PULSE IS THE RICH MEDIUM. Slides render content NATIVELY — a raw photo (or
   inline video) under REAL HTML text — not Instagram's baked-in flat cards. The
   default frame is 5:7 (the oracle/poker proportion, the world's card ratio), but
   each slide may override it via --ratio (e.g. a full-bleed 4:5 or a tall 9:16)
   when the content calls for it. Instagram is locked to 4:5; the Pulse is not. */
.pulse-stream .carou-slide {
  position: relative;
  flex: 0 0 100%;
  width: 100%;
  /* the slide is a <figure>; the UA default margin (1em 40px) would put an 80px
     gap between slides — that desyncs the clientWidth*i scroll math (drifting the
     dots/counter/active-video) AND leaks slivers of the neighbour. Zero it so each
     slide is exactly one viewport wide, edge to edge. */
  margin: 0;
  scroll-snap-align: center;
  scroll-snap-stop: always;
  aspect-ratio: var(--ratio, 5 / 7);
  background: #0A0907;
}
.pulse-stream .carou-slide img,
.pulse-stream .carou-slide video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--pos, center);
  display: block;
  user-select: none;
  -webkit-user-drag: none;
}

/* ---- caption: bottom scrim, fixed-light text (theme-independent) ----------- */
/* the caption is a defined frosted PLAQUE — uniform tint + blur so every line
   (kicker included) reads on any photo, with a bronze hairline top edge in the
   industrial register. Its OWN rounded corners clip the backdrop-filter correctly
   (an ancestor's border-radius does NOT clip a backdrop-filter in Chromium — that
   bug is what squared off the old frost's bottom corners). overflow:hidden clips
   the grid texture to the same rounding. Bottom corners match the stage (28px). */
.pulse-stream .carou-cap {
  position: absolute;
  left: 16px; right: 16px; bottom: 16px;
  padding: 22px 22px 22px;
  background: rgba(8,7,5,.58);
  -webkit-backdrop-filter: blur(16px) saturate(.92);
  backdrop-filter: blur(16px) saturate(.92);
  border: 1px solid rgba(176,128,48,.24);
  border-radius: 18px;
  box-shadow: 0 10px 34px rgba(0,0,0,.4);
  overflow: hidden;
  pointer-events: none;
}
/* faint bronze industrial grid — the "deliciously luxurious" register, as
   seasoning not wallpaper. Strongest at the bottom (where the scrim is darkest),
   masked to nothing toward the top so it never touches the photo. */
.pulse-stream .carou-cap::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    repeating-linear-gradient(0deg,  rgba(176,128,48,.05) 0 1px, transparent 1px 27px),
    repeating-linear-gradient(90deg, rgba(176,128,48,.05) 0 1px, transparent 1px 27px);
  -webkit-mask-image: linear-gradient(to top, #000 0%, #000 34%, transparent 80%);
  mask-image: linear-gradient(to top, #000 0%, #000 34%, transparent 80%);
  z-index: 0;
}
.pulse-stream .carou-cap > * { position: relative; z-index: 1; }
.pulse-stream .carou-kicker {
  font-family: "Inter", sans-serif;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: #E7C07A;                 /* warm gold — brighter than --bronze for photo legibility */
  margin: 0 0 10px;
}
.pulse-stream .carou-title {
  font-family: "DM Serif Display", Georgia, serif;
  font-size: clamp(25px, 6.4vw, 33px);
  line-height: 1.12;
  color: #F8F4EC;
  margin: 0;
  text-wrap: balance;
  text-shadow: 0 1px 24px rgba(0,0,0,.45);
}
.pulse-stream .carou-text {
  font-family: "Cormorant Garamond", Georgia, serif;
  font-size: clamp(17px, 4.4vw, 20px);
  line-height: 1.5;
  color: rgba(248,244,236,.93);
  margin: 12px 0 0;
  text-wrap: pretty;
  text-shadow: 0 1px 18px rgba(0,0,0,.4);
}

/* ---- mobile: tighten the caption plaque so the photo stays the hero --------
   The caption is bottom-anchored and grows with its text. On a narrow phone slide
   the same copy wraps tall: measured at a 358px slide it was covering 55-81% of the
   photo (slides 0 and 8 almost entirely). Below 540px, tighten the padding, fonts
   and line-height — this drops coverage to ~29-47% (photo back to the majority) while
   staying legible (title 22px, body 15.5px). Desktop (wider slide, fewer wraps) is
   untouched; it already sits at ~28-41%. ------------------------------------- */
@media (max-width: 540px) {
  .pulse-stream .carou-cap {
    left: 12px; right: 12px; bottom: 12px;
    padding: 13px 15px;
    border-radius: 15px;
  }
  .pulse-stream .carou-kicker { font-size: 10px; margin: 0 0 7px; }
  .pulse-stream .carou-title  { font-size: 22px; line-height: 1.08; }
  .pulse-stream .carou-text   { font-size: 15.5px; line-height: 1.4; margin: 8px 0 0; }
}

/* ---- desktop arrows (overlaid; hidden where there is no hover) ------------- */
.pulse-stream .carou-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 40px; height: 40px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: rgba(8,7,5,.5);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  color: #F5F0E8;
  cursor: pointer;
  opacity: 0;
  transition: opacity .22s, background .2s, transform .2s;
  /* above ALL slide-internal layers (embed tap-layer z3, controls z4, mute/handle
     z5) — otherwise an interactive exhibit steals the arrow click (the card-8
     "arrow sends me to the world" bug). The arrows are controls; they win. */
  z-index: 12;
  -webkit-tap-highlight-color: transparent;
}
.pulse-stream .carou-nav.prev { left: 12px; }
.pulse-stream .carou-nav.next { right: 12px; }
.pulse-stream .carou-nav svg { width: 18px; height: 18px; display: block; }
.pulse-stream .carou-stage:hover .carou-nav { opacity: 1; }
.pulse-stream .carou-nav:hover { background: rgba(8,7,5,.78); }
.pulse-stream .carou-nav:focus-visible { opacity: 1; outline: 1px solid var(--bronze); outline-offset: 2px; }
.pulse-stream .carou-nav[disabled] { opacity: 0 !important; pointer-events: none; }
/* touch / no-hover: lean on swipe, never show the arrows */
@media (hover: none) {
  .pulse-stream .carou-stage:hover .carou-nav { opacity: 0; }
}

/* ---- control bar: dots + counter, below the frame (kit-tokened) ----------- */
.pulse-stream .carou-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin: 11px 2px 0;
}
.pulse-stream .carou-dots { display: flex; gap: 7px; align-items: center; }
.pulse-stream .carou-dot {
  width: 6px; height: 6px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--line);
  cursor: pointer;
  transition: background .2s, transform .2s, width .2s;
  -webkit-tap-highlight-color: transparent;
}
.pulse-stream .carou-dot:hover { background: var(--stone); }
.pulse-stream .carou-dot.on { background: var(--bronze); width: 18px; border-radius: 3px; }
.pulse-stream .carou-dot:focus-visible { outline: 1px solid var(--bronze); outline-offset: 2px; }
.pulse-stream .carou-count {
  font-family: "Inter", sans-serif;
  font-size: 10px;
  letter-spacing: .14em;
  color: var(--stone);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.pulse-stream .carou-count b { color: var(--bronze); font-weight: 600; }

/* a beat-level overline for the carousel (optional "label" in posts.json) */
.pulse-stream .carou-over {
  font-family: "Inter", sans-serif;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--bronze);
  margin: 0 0 11px;
}

/* =============================================================================
   NATIVE INLINE TRACK PLAYER — a Pulse-only exhibit (carousel card).
   The real audio plays on a LIVE, audio-reactive waveform (Web Audio API).
   Instagram can only bake a flat looping video with a dead "tap to unmute"
   sticker; here the music actually PLAYS and the spectrum dances to it.
   ============================================================================= */
.pulse-stream .carou-track .ct-cover { z-index: 0; }
.pulse-stream .carou-track .ct-veil {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background:
    radial-gradient(120% 72% at 50% 44%, rgba(8,7,5,.30) 0%, rgba(8,7,5,.64) 100%),
    linear-gradient(to top, rgba(8,7,5,.45) 0%, rgba(8,7,5,0) 36%);
}
/* the live spectrum — a band PUSHED UP into the clear upper paper so it never
   covers the handwriting or the caption (Lee: "the waveform should not block the
   main image/text"). Sits above the play control. */
.pulse-stream .carou-track .ct-viz {
  position: absolute; z-index: 2; pointer-events: none;
  left: 9%; width: 82%; top: 17%; transform: translateY(-50%);
  height: 74px; opacity: .92;
}
.pulse-stream .carou-track .ct-play {
  position: absolute; z-index: 4; left: 50%; top: 43%;
  transform: translate(-50%, -50%);
  width: 66px; height: 66px; border-radius: 50%;
  display: grid; place-items: center; cursor: pointer;
  color: var(--linen);
  background: rgba(10, 9, 7, .42);
  border: 1.5px solid rgba(245, 240, 232, .55);
  -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px);
  box-shadow: 0 6px 26px rgba(0, 0, 0, .42);
  transition: transform .15s ease, border-color .2s ease, background .2s ease;
}
.pulse-stream .carou-track .ct-play:hover {
  transform: translate(-50%, -50%) scale(1.06); border-color: var(--linen);
}
.pulse-stream .carou-track .ct-ico { width: 26px; height: 26px; fill: currentColor; }
.pulse-stream .carou-track .ct-ico-play { margin-left: 3px; }   /* optical centre */
.pulse-stream .carou-track .ct-ico-pause { display: none; }
.pulse-stream .carou-track.playing .ct-ico-play { display: none; }
.pulse-stream .carou-track.playing .ct-ico-pause { display: block; }
/* mute toggle — top-right; appears once the track is playing */
.pulse-stream .carou-track .ct-mute {
  position: absolute; z-index: 5; top: 14px; right: 14px;
  width: 36px; height: 36px; border-radius: 50%; display: none; place-items: center;
  cursor: pointer; color: var(--linen);
  background: rgba(10, 9, 7, .42); border: 1px solid rgba(245, 240, 232, .4);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.pulse-stream .carou-track.playing .ct-mute { display: grid; }
.pulse-stream .carou-track .ct-mute .ct-ico { width: 20px; height: 20px; }
.pulse-stream .carou-track .ct-ico-mut { display: none; }
.pulse-stream .carou-track.muted .ct-ico-spk { display: none; }
.pulse-stream .carou-track.muted .ct-ico-mut { display: block; }
/* scrubber row — sits above the caption plaque */
.pulse-stream .carou-track .ct-bar {
  position: absolute; z-index: 4; left: 24px; right: 24px; top: 62%;
  display: flex; align-items: center; gap: 11px;
}
.pulse-stream .carou-track .ct-scrub {
  position: relative; flex: 1; height: 4px; border-radius: 3px;
  background: rgba(245, 240, 232, .26); cursor: pointer; touch-action: none;
}
.pulse-stream .carou-track .ct-fill {
  position: absolute; left: 0; top: 0; height: 100%; width: 0%;
  border-radius: 3px;
  background: var(--spectrum, linear-gradient(90deg, #E2631F, #E8D21A, #46B14E, #2E78C4, #A02E9E));
}
.pulse-stream .carou-track .ct-time {
  font-family: "Inter", sans-serif; font-size: 10.5px; letter-spacing: .04em;
  color: rgba(245, 240, 232, .86); font-variant-numeric: tabular-nums; white-space: nowrap;
}

/* =============================================================================
   BEFORE/AFTER SLIDER (carousel exhibit) — drag the handle to wipe between two
   images (hand sketch → the live thing). A real interaction; Instagram can only
   stack two flat pictures. The "after" sits underneath full-bleed; the "before"
   is clipped to --split; the handle drags --split.
   ============================================================================= */
.pulse-stream .carou-slider .cs-after,
.pulse-stream .carou-slider .cs-before img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover;
}
/* per-image pan + zoom so the two compositions can be aligned (the wipe only reads
   when the focal subject overlaps). Tuned in _align.html. */
.pulse-stream .carou-slider .cs-after { object-position: var(--apos, center); transform: scale(var(--az, 1)); }
.pulse-stream .carou-slider .cs-before img { object-position: var(--bpos, center); transform: scale(var(--bz, 1)); }
.pulse-stream .carou-slider .cs-before {
  position: absolute; inset: 0; z-index: 1; overflow: hidden;
  clip-path: inset(0 calc(100% - var(--split, 50%)) 0 0);
}
/* keep the caption + its CTA above both images (the before-image would otherwise
   cover the caption on the clipped side) */
.pulse-stream .carou-slider .carou-cap { z-index: 4; }
.pulse-stream .carou-slider .cs-handle {
  position: absolute; top: 0; bottom: 0; left: var(--split, 50%);
  width: 2px; margin-left: -1px; z-index: 5;
  background: rgba(245, 240, 232, .92); cursor: ew-resize; touch-action: none;
  box-shadow: 0 0 14px rgba(0, 0, 0, .55);
}
.pulse-stream .carou-slider .cs-grip {
  position: absolute; top: 42%; left: 50%; transform: translate(-50%, -50%);
  width: 40px; height: 40px; border-radius: 50%; display: grid; place-items: center;
  color: #0E0D09; background: rgba(245, 240, 232, .95);
  box-shadow: 0 4px 16px rgba(0, 0, 0, .45); cursor: ew-resize;
}
.pulse-stream .carou-slider .cs-handle:focus-visible { outline: none; }
.pulse-stream .carou-slider .cs-handle:focus-visible .cs-grip { box-shadow: 0 0 0 3px rgba(231, 192, 122, .8); }
.pulse-stream .carou-slider .cs-grip svg { width: 21px; height: 21px; }
.pulse-stream .carou-slider .cs-tag {
  position: absolute; top: 15px; z-index: 4;
  font-family: "Inter", sans-serif; font-size: 9px; font-weight: 600;
  letter-spacing: .16em; text-transform: uppercase; color: #F5F0E8;
  background: rgba(8, 7, 5, .52); padding: 4px 10px; border-radius: 20px;
  -webkit-backdrop-filter: blur(5px); backdrop-filter: blur(5px);
}
.pulse-stream .carou-slider .cs-tag-l { left: 14px; }
.pulse-stream .carou-slider .cs-tag-r { right: 14px; }
/* inline CTA inside the caption — replaces IG's dead "LINK IN BIO" */
.pulse-stream .carou-slider .cs-open {
  display: inline-block; margin-top: 11px;
  font-family: "Inter", sans-serif; font-size: 11px; font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase; color: #E7C07A;
  text-decoration: none; border-bottom: 1px solid rgba(231, 192, 122, .4);
  padding-bottom: 2px; pointer-events: auto;
}
.pulse-stream .carou-slider .cs-open .arr { transition: transform .2s ease; display: inline-block; }
.pulse-stream .carou-slider .cs-open:hover .arr { transform: translateX(3px); }

/* =============================================================================
   FLIP card (carousel exhibit) — an oracle card you turn over. Front = the art;
   tap to flip in 3D and read the card's "reading" on the back. IG shows one side.
   ============================================================================= */
.pulse-stream .carou-flip { perspective: 1400px; background: #0E0D09; cursor: pointer; }
.pulse-stream .carou-flip .cf-inner {
  position: absolute; inset: 0; transform-style: preserve-3d;
  transition: transform .75s cubic-bezier(.4, 0, .2, 1);
}
.pulse-stream .carou-flip.flipped .cf-inner { transform: rotateY(180deg); }
.pulse-stream .carou-flip .cf-face {
  position: absolute; inset: 0; overflow: hidden;
  -webkit-backface-visibility: hidden; backface-visibility: hidden;
}
.pulse-stream .carou-flip .cf-front img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: var(--pos, center);
}
.pulse-stream .carou-flip .cf-back {
  transform: rotateY(180deg);
  background:
    repeating-linear-gradient(0deg, rgba(176, 128, 48, .055) 0 1px, transparent 1px 30px),
    repeating-linear-gradient(90deg, rgba(176, 128, 48, .055) 0 1px, transparent 1px 30px),
    radial-gradient(125% 90% at 50% 28%, #1a160f 0%, #0E0D09 72%);
  display: grid; place-items: center; padding: 32px 28px;
}
.pulse-stream .carou-flip .cf-back-in { text-align: center; max-width: 90%; }
.pulse-stream .carou-flip .cf-kicker {
  font-family: "Inter", sans-serif; font-size: 10px; font-weight: 600; letter-spacing: .24em;
  text-transform: uppercase; color: #E7C07A; margin: 0 0 15px;
}
.pulse-stream .carou-flip .cf-heading {
  font-family: "DM Serif Display", Georgia, serif; font-weight: 400; font-size: 28px;
  line-height: 1.08; color: var(--linen); margin: 0 0 16px;
}
.pulse-stream .carou-flip .cf-body {
  font-family: "Cormorant Garamond", Georgia, serif; font-size: 18.5px; line-height: 1.5;
  color: rgba(245, 240, 232, .82); margin: 0 0 18px;
}
.pulse-stream .carou-flip .cf-invite {
  font-family: "DM Serif Display", Georgia, serif; font-style: italic; font-size: 19px;
  line-height: 1.3; color: var(--linen); margin: 0 0 22px;
}
.pulse-stream .carou-flip .cf-open {
  display: inline-block; font-family: "Inter", sans-serif; font-size: 11px; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase; color: #0E0D09; background: #E7C07A;
  padding: 9px 18px; border-radius: 22px; text-decoration: none;
}
.pulse-stream .carou-flip .cf-open .arr { display: inline-block; transition: transform .2s ease; }
.pulse-stream .carou-flip .cf-open:hover .arr { transform: translateX(3px); }
.pulse-stream .carou-flip .cf-hint {
  position: absolute; left: 50%; bottom: 16px; transform: translateX(-50%); z-index: 3;
  font-family: "Inter", sans-serif; font-size: 9.5px; letter-spacing: .14em; text-transform: uppercase;
  color: rgba(245, 240, 232, .62); white-space: nowrap; pointer-events: none;
  background: rgba(8, 7, 5, .42); padding: 4px 11px; border-radius: 20px;
  -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px); transition: opacity .3s ease;
}
.pulse-stream .carou-flip.flipped .cf-front .cf-hint { opacity: 0; }
.pulse-stream .carou-flip .cf-rot { display: inline-block; }

/* =============================================================================
   LIVE EMBED (carousel exhibit) — the actual site breathing inside the card, not
   a screenshot. The iframe fills the frame; a transparent tap-layer links out and
   blocks interaction; a "Live" pulse marks it real. IG can only show a picture.
   ============================================================================= */
.pulse-stream .carou-embed .ce-stage {
  position: absolute; inset: 0; z-index: 0; overflow: hidden; background: #0E0D09;
}
.pulse-stream .carou-embed .ce-frame { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.pulse-stream .carou-embed .ce-veil {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(to top, rgba(8, 7, 5, .55) 0%, rgba(8, 7, 5, 0) 32%);
}
.pulse-stream .carou-embed .ce-tap { position: absolute; inset: 0; z-index: 3; display: block; }
.pulse-stream .carou-embed .ce-live {
  position: absolute; top: 14px; left: 14px; z-index: 4;
  display: inline-flex; align-items: center; gap: 6px;
  font-family: "Inter", sans-serif; font-size: 9px; font-weight: 600;
  letter-spacing: .16em; text-transform: uppercase; color: #F5F0E8;
  background: rgba(8, 7, 5, .5); padding: 4px 10px; border-radius: 20px;
  -webkit-backdrop-filter: blur(5px); backdrop-filter: blur(5px);
}
.pulse-stream .carou-embed .ce-dot {
  width: 6px; height: 6px; border-radius: 50%; background: #46B14E;
  box-shadow: 0 0 7px #46B14E; animation: ce-pulse 1.8s ease-in-out infinite;
}
@keyframes ce-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }
.pulse-stream .carou-embed .carou-cap { z-index: 5; }
/* "spin again" — a circular control at the TOP of the card, ABOVE the tap-layer
   (z3). The tap-layer blocks the iframe, so this button lives in the parent card
   and pulse.js postMessages the embedded deck to draw a new self. Glassy, kit-toned;
   below the nav arrows (z12) so it never steals a carousel arrow click. */
.pulse-stream .carou-embed .ce-spin {
  position: absolute; z-index: 6; top: 14px; left: 50%; transform: translateX(-50%);
  width: 40px; height: 40px; border-radius: 50%;
  display: grid; place-items: center; cursor: pointer; color: var(--linen);
  background: rgba(10, 9, 7, .46); border: 1px solid rgba(245, 240, 232, .42);
  -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px);
  box-shadow: 0 4px 18px rgba(0, 0, 0, .4);
  transition: transform .18s ease, border-color .2s ease, background .2s ease;
  -webkit-tap-highlight-color: transparent;
}
.pulse-stream .carou-embed .ce-spin:hover { transform: translateX(-50%) scale(1.08); border-color: var(--linen); background: rgba(10, 9, 7, .62); }
.pulse-stream .carou-embed .ce-spin:active { transform: translateX(-50%) scale(.96); }
.pulse-stream .carou-embed .ce-spin svg { width: 19px; height: 19px; display: block; }
.pulse-stream .carou-embed .ce-spin:focus-visible { outline: 1px solid var(--bronze); outline-offset: 2px; }
/* tap feedback — the icon spins once (the drawn-self change happens in the iframe,
   so confirm the tap registered here). pulse.js toggles .spinning. */
.pulse-stream .carou-embed .ce-spin.spinning svg { animation: ce-spin-rot .7s cubic-bezier(.4, 0, .2, 1); }
@keyframes ce-spin-rot { from { transform: rotate(0); } to { transform: rotate(360deg); } }
