/*
 * Blog-Maker podcast episode player + video embed (P2, 2026-08-24).
 *
 * Blog-Maker pushes the player as raw HTML into post_content
 * (figure.bm-podcast-player / figure.bm-podcast-video, data-bm-podcast="2" /
 * data-bm-podcast-video="2"), the same markup on every WordPress target
 * (mylandingpage and plain WordPress alike, see the sender at
 * v11/src/lib/podcast-audio/player-html.ts). WordPress's own theme never
 * styled it, and with zero CSS the fallback "Play the episode..." link (an
 * inline <a>, wrapped in a <p> since v2) rendered next to the tiny native
 * <audio> control instead of below it (Olli, 2026-08-24, viewing a live
 * mylandingpage test page).
 *
 * Self-contained, no dependency on this theme's own CSS custom properties:
 * a customer site's palette varies (Elementor global colors differ per
 * install), so this uses fixed values matching the myLandingpage default
 * brand palette (~/.claude/rules/color-system.md) rather than assuming a
 * shared token system exists on every install.
 */

.bm-podcast-player {
  margin: 1.75rem 0;
  padding: 1rem 1.25rem;
  border: 1px solid rgba(10, 57, 78, 0.16);
  border-radius: 12px;
  /* #f7f9fa (2026-08-24) read as white-on-white against most WP page
     backgrounds (Olli, 2026-08-25, live screenshot comparison). One step
     further from white, still restrained, no visible page background is
     purely #fff to compare against so this is a deliberate minimum rather
     than a measured contrast ratio. */
  background: #eef1f3;
  /* Minimal lift off the page (Olli, 2026-08-26), tinted not black
     (web-design-quickstart.md rule 6: no pure-black shadows). */
  box-shadow: 0 1px 3px rgba(10, 57, 78, 0.08);
}

/* Video gets no card wrap (margin only): the Bunny iframe already brings
   its own modern controls, a bordered/padded/background box around it
   would just double up on chrome the iframe already has. Matches
   blog-maker/v11's globals.css .prose .bm-podcast-video, which never had
   the card properties -- this file's shared selector for both was an
   unintentional divergence (found in a full review pass, 2026-08-24). */
.bm-podcast-video {
  margin: 1.75rem 0;
}

.bm-podcast-player figcaption,
.bm-podcast-video figcaption {
  margin: 0 0 0.5rem;
  /* 13px read as too small to work as the section's own heading (Olli,
     2026-08-26). 16px still fits alongside the fallback link on one line
     at typical article widths. */
  font-size: 16px;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: #4a6363; /* WCAG AA contrast on #f7f9fa (code-reviewer finding, 2026-08-24) */
}

.bm-podcast-player audio {
  display: block;
  width: 100%;
  height: 40px;
}

.bm-podcast-video iframe {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  border: 0;
  border-radius: 8px;
}

/* Plyr+hls.js video Enhancer pilot (js/podcast-video-enhancer.js,
   2026-08-26). Bunny's own iframe skin is neutral/unbranded (Olli,
   live screenshot review), this replaces it with a branded control bar
   matching the audio player's own aesthetic. Click-to-load: the poster
   below is the ONLY thing shown before a click, no Bunny contact yet.
   Poster background is a self-hosted SVG (podcast-video-poster-bg.svg,
   soundwave motif baked in, own gradient included), never a Bunny
   thumbnail: fetching that would mean contacting Bunny before the click,
   defeating the whole click-to-load point (Olli, AskUserQuestion
   2026-08-26). ".bm-podcast-video " prefix is load-bearing, not
   decoration: a bare ".bm-podcast-video-poster" ties specificity (0,1,0)
   with the parent theme's global `[type="button"], button { display:
   inline-block; width: auto }` reset (style.min.css), which wins by
   source order and collapses the poster to a tiny content-sized box
   (found live, 2026-08-26: 96x87px instead of the full 16:9 width).
   Same fix pattern as ".bm-podcast-controls .bm-podcast-btn" below. */
.bm-podcast-video .bm-podcast-video-poster {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  aspect-ratio: 16 / 9;
  border: 0;
  border-radius: 8px;
  padding: 0;
  cursor: pointer;
  overflow: hidden;
  background-size: cover;
  background-position: center;
  /* No background-image HERE on purpose: WP Rocket's "LazyLoad for CSS
     background images" rewrites any background-image in a static CSS
     file into a --wpr-bg-<hash> custom property, swapped in only by
     Rocket's own lazy-load script when the matched element scrolls into
     view. That scan runs once on page load; this poster button is
     created by podcast-video-enhancer.js AFTER that scan, so it never
     gets found and the image never loads (found live, 2026-08-26:
     computed backgroundImage stayed "none" even though the SVG itself
     served 200 and rendered fine standalone). The enhancer sets
     poster.style.backgroundImage inline at creation time instead, which
     Rocket's static-file rewriter never touches. */
}
.bm-podcast-video .bm-podcast-video-poster:hover {
  filter: brightness(1.08);
}
.bm-podcast-video .bm-podcast-video-poster:focus-visible {
  outline: 2px solid #c2410c;
  outline-offset: 2px;
}
.bm-podcast-video-icon-play {
  width: 64px;
  height: 64px;
  padding: 18px;
  border-radius: 999px;
  background: linear-gradient(to bottom right, #c2410c, #9a3412);
  color: #ffffff;
}
.bm-podcast-video-poster-disclaimer {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 6px 10px;
  font-size: 11px;
  line-height: 1.3;
  color: rgba(255, 255, 255, 0.8);
  background: linear-gradient(to top, rgba(10, 57, 78, 0.85), rgba(10, 57, 78, 0));
  text-align: center;
}
.bm-podcast-video video {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: 8px;
}
/* Plyr theming via its own CSS custom properties (plyr.css already loaded),
   matching the audio player's orange accent instead of Plyr's default. */
.bm-podcast-video .plyr {
  --plyr-color-main: #c2410c;
  --plyr-video-control-color: #ffffff;
  --plyr-video-control-color-hover: #ffffff;
  --plyr-video-control-background-hover: #c2410c;
  border-radius: 8px;
  overflow: hidden;
}

.bm-podcast-player p,
.bm-podcast-video p {
  margin: 0.625rem 0 0;
}

.bm-podcast-player p a,
.bm-podcast-video p a {
  font-size: 14px;
  font-weight: 500;
  /* #ea580c on #f7f9fa is ~3.37:1, fails WCAG AA (4.5:1) for normal-size
     text (code-reviewer finding, 2026-08-24). #c2410c (the old hover value)
     clears it, so it becomes the default; hover/focus step darker again. */
  color: #c2410c;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}

.bm-podcast-player p a:hover,
.bm-podcast-video p a:hover {
  color: #9a3412;
}

.bm-podcast-player p a:focus-visible,
.bm-podcast-video p a:focus-visible {
  outline: 2px solid #c2410c;
  outline-offset: 2px;
  border-radius: 4px;
}

/* Podcast player Enhancer (P3, js/podcast-enhancer.js): once the script
   runs it removes the native `controls` attribute and appends
   .bm-podcast-controls as a sibling of the <audio> -- ported verbatim from
   blog-maker/v11's globals.css, fixed colours instead of CSS custom
   properties (same reasoning as the base rules above: no shared token
   system across customer installs). 132px min-height (not 92): covers the
   Enhancer's appended control row too, not just the plain native-audio
   state. */
.bm-podcast-player {
  min-height: 132px;
}
@media (max-width: 640px) {
  /* 132px was measured against the desktop (single-row) control bar. At
     mobile widths the 6-item control bar wraps to two rows: live-measured
     215px at 375px AND 320px viewport width on the equivalent Blog-Maker
     component (design-reviewer finding, 2026-08-24). 240px, not 220px:
     that measurement predated the .bm-podcast-mute touch-target fix in
     this same commit, which grows the wrapped row by another 8px -- two
     independent re-reviews both live-measured the combined real height
     at 223px on the Blog-Maker equivalent. */
  .bm-podcast-player {
    min-height: 240px;
  }
}
.bm-podcast-player audio[data-bm-enhanced] {
  display: none;
}
.bm-podcast-controls {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 4px;
  flex-wrap: wrap;
}
/* .bm-podcast-controls prefix (not bare .bm-podcast-btn) is load-bearing:
   this theme enqueues its own parent stylesheet twice, and the second copy
   lands AFTER this file in the cascade. Its generic `[type="button"],
   [type="submit"], button { color: #cc3366; background: transparent }`
   reset ties specificity (0,1,0) with a bare `.bm-podcast-btn`, so it wins
   by source order and stomps the button colours regardless of what this
   file sets. Scoping under the parent container raises specificity to
   (0,2,0), which wins outright no matter which stylesheet loads last
   (same fix pattern as blog-maker/v11's .prose-prefixed focus-ring rules,
   2026-08-25). */
.bm-podcast-controls .bm-podcast-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  padding: 0;
  border: none;
  border-radius: 999px;
  background: #e8edf0;
  color: #0a394e;
  cursor: pointer;
}
.bm-podcast-controls .bm-podcast-btn:hover,
.bm-podcast-controls .bm-podcast-btn:focus {
  /* [type="button"]:focus, [type="button"]:hover { color: #fff } is an
     ATTRIBUTE selector, not an element selector -- it counts in the
     specificity B-component same as a class, so it ties this rule's
     (0,2,0) exactly and wins on source order (found live, 2026-08-26,
     Olli: skip/mute icons turned invisible-white on hover). Declaring
     color here matches both states that rule covers. */
  color: #0a394e;
}
.bm-podcast-controls .bm-podcast-btn:hover {
  background: #dde4e8;
}
.bm-podcast-controls .bm-podcast-btn:active {
  background: #ccd6db;
}
.bm-podcast-controls .bm-podcast-btn:disabled {
  /* 0.4 read as "washed out / barely visible" before the audio has
     loaded (Olli, 2026-08-26) -- the skip buttons stay disabled until
     loadedmetadata, so they sit at this opacity from first paint, not
     just briefly. Still visibly muted vs. the enabled state, just not
     near-invisible. */
  opacity: 0.7;
  cursor: default;
}
.bm-podcast-controls .bm-podcast-btn:focus-visible {
  outline: 2px solid #c2410c;
  outline-offset: 2px;
}
/* Repeated class (not a typo): Elementor's own "Lazy Load Background
   Images" feature ships a site-wide rule
   (`.e-con.e-parent:nth-of-type(n+4):not(.e-lazyloaded):not(.e-no-lazyload)
   *`) that sets background-image:none !important on every descendant of a
   below-the-fold container that never got marked lazyloaded -- a section
   with no background image of its own never triggers Elementor's own
   IntersectionObserver, so the rule never lifts. Found live, 2026-08-25:
   the play button rendered with no gradient once it happened to sit inside
   such a section. That selector's specificity is ~(0,5,0) (2 classes +
   nth-of-type + 2 :not() arguments), so matching !important alone still
   lost on specificity -- verified via getPropertyPriority() before
   reaching for this. Repeating .bm-podcast-play raises this rule to
   (0,6,0), comfortably above it, without an ID hack or inline style. */
.bm-podcast-controls .bm-podcast-play.bm-podcast-play.bm-podcast-play.bm-podcast-play.bm-podcast-play {
  width: 44px;
  height: 44px;
  background: linear-gradient(to bottom right, #c2410c, #9a3412) !important;
  color: #ffffff;
}
.bm-podcast-controls .bm-podcast-play.bm-podcast-play.bm-podcast-play.bm-podcast-play.bm-podcast-play:hover {
  /* Same two problems as the base rule above stacked together: the
     generic .bm-podcast-btn:hover background needs beating on source
     order at tied specificity, and Elementor's lazy-load !important
     needs beating on raw specificity. Repeated class + !important,
     same reasoning as above. */
  background: linear-gradient(to bottom right, #c2410c, #9a3412) !important;
  filter: brightness(0.93);
}
.bm-podcast-icon {
  width: 20px;
  height: 20px;
  fill: currentColor;
}
.bm-podcast-play .bm-podcast-icon-pause {
  display: none;
}
.bm-podcast-play.is-playing .bm-podcast-icon-play {
  display: none;
}
.bm-podcast-play.is-playing .bm-podcast-icon-pause {
  display: block;
}
.bm-podcast-mute .bm-podcast-icon-muted {
  display: none;
}
.bm-podcast-mute.is-muted .bm-podcast-icon-vol {
  display: none;
}
.bm-podcast-mute.is-muted .bm-podcast-icon-muted {
  display: block;
}
.bm-podcast-skip {
  width: auto;
  min-height: 44px; /* touch-target floor */
  padding: 0 10px;
  gap: 2px;
}
.bm-podcast-skip .bm-podcast-icon {
  width: 18px;
  height: 18px;
}
.bm-podcast-skip-n {
  font-size: 10px;
  font-weight: 700;
}
.bm-podcast-time {
  flex: 0 0 auto;
  min-width: 32px;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  /* #5c7a7a on #f7f9fa is 4.40:1, under WCAG AA's 4.5:1 floor for this
     12px text (design-reviewer finding, 2026-08-24). #4a6363 (already used
     for figcaption in this file) clears it. */
  color: #4a6363;
}
.bm-podcast-seek {
  flex: 1 1 auto;
  min-width: 60px;
  height: 4px;
  accent-color: #c2410c;
  cursor: pointer;
}
/* `accent-color` only colours the filled portion + thumb; the unfilled
   track relies on the browser's own default (transparent in some
   engines), so before loadedmetadata (value=0, max=0, the whole track is
   "unfilled") it could render as no visible line at all against the card
   (Olli, 2026-08-26: "Zeitleiste erst nach Play sichtbar" on kato-paphos,
   same root cause). Explicit track colour makes the bar visible from the
   first paint, not just once it has something to fill. */
.bm-podcast-seek::-webkit-slider-runnable-track {
  background: rgba(10, 57, 78, 0.18);
  border-radius: 2px;
  height: 4px;
}
.bm-podcast-seek::-moz-range-track {
  background: rgba(10, 57, 78, 0.18);
  border-radius: 2px;
  height: 4px;
}
/* Styling ANY -webkit-slider-* pseudo-element (the track above) switches
   Chrome/Safari out of the automatic accent-color-themed rendering, so
   the thumb fell back to a bare unstyled white circle instead of the
   coloured one accent-color alone used to produce (Olli, 2026-08-26,
   live screenshot: a plain white dot on the seek bar). Once the track is
   custom, the thumb needs to be styled explicitly too -- accent-color
   alone no longer reaches it. -webkit-appearance:none is required for
   Chrome/Safari to accept the custom thumb rules at all. */
.bm-podcast-seek::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: #c2410c;
  cursor: pointer;
  margin-top: -5px; /* centers a 14px thumb on the 4px track */
}
.bm-podcast-seek::-moz-range-thumb {
  width: 14px;
  height: 14px;
  border: none;
  border-radius: 50%;
  background: #c2410c;
  cursor: pointer;
}
.bm-podcast-seek:disabled {
  cursor: default;
  /* 0.5 combined with an already-subtle base contrast (icon/track color
     against the card's near-white background) read as "barely visible /
     washed out" before the audio has loaded (Olli, 2026-08-26, both here
     and on the disabled skip buttons below). Still visibly muted, not
     gone. */
  opacity: 0.7;
}
.bm-podcast-seek:focus-visible {
  outline: 2px solid #c2410c;
  outline-offset: 2px;
}
.bm-podcast-mute {
  margin-left: 4px;
  /* .bm-podcast-btn's base 36x36 is under the 44px touch-target floor;
     .bm-podcast-play and .bm-podcast-skip both got an explicit override
     for it, this sibling was missed (design-reviewer finding, 2026-08-24). */
  min-width: 44px;
  min-height: 44px;
}
