/**
 * VideoGrid v1.7.10 — Frontend
 *
 * BUG FIX: clicking an album tile showed videos from ALL albums.
 *
 * Root cause: query_videos used `tax_query field => 'slug'`. WordPress
 * silently ignores the entire tax_query if even one slug is misspelt or
 * the term has been renamed — and an ignored tax_query falls through to
 * the un-filtered "all videos" query.
 *
 * Fixes in v1.7.10:
 *   1. query_videos resolves slugs → term_ids first. If NO slugs match
 *      a real album, it returns an empty array instead of falling
 *      through.
 *   2. ajax_load_album validates the slug resolves to a real album
 *      BEFORE running the query (returns 404 if not).
 *   3. Empty albums now render a clear "No videos in this album yet"
 *      message instead of nothing.
 *   4. Settings → Shortcodes tab now documents `view="albums"` as the
 *      primary album drill-down pattern (this was missing before).
 *   5. Tax_query uses explicit `operator => 'IN'` and
 *      `include_children => false` to avoid hierarchy surprises.
 *
 * Inherits all bug fixes from v1.7.4–1.7.9.
 *
 * Awesome & simple. Defensive against theme conflicts.
 */

/* ============================================
   1. SCOPE + RESET
   ============================================ */
/**
 * VideoGrid v1.x — Frontend
 * ============================================
 * Builder-defensive: prevents bleed-over from
 * Elementor / Bricks / Beaver / Divi / Oxygen widgets
 * that sit above or below the plugin on the page.
 * ============================================
 */

/* ============================================
   1b. UNIVERSAL BUILDER ANCESTOR DEFENSE — v1.7.9
   ============================================
   When ANY page builder's parent column reports a smaller height than
   the videogrid needs, the page's NEXT section starts too early and
   visually clips the last card. We force every plausible ancestor
   container — across every major builder we know about — to
   `height: auto; overflow: visible` so the column genuinely expands
   to fit our content.

   Builders covered:
     - Elementor (classic + Container/Flexbox/Grid engine)
     - Beaver Builder
     - Bricks Builder
     - Divi
     - Oxygen Builder
     - Breakdance
     - Cwicly
     - WPBakery / Visual Composer
     - SiteOrigin Page Builder
     - Brizy
     - Thrive Architect / Thrive Theme Builder
     - Avia / Enfold builder
     - Themify Builder
     - Live Composer
     - Gutenberg (WP block editor)
     - Classic shortcode/HTML widgets

   `:has()` is supported in all modern browsers (Chrome 105+, Safari
   15.4+, Firefox 121+) covering ~95%+ of traffic. The plain
   descendant-selector block below the `:has()` block provides a
   universal fallback for older browsers — in those, the wrap's own
   `position: relative` / `z-index` / `padding-bottom` defenses still
   prevent bleed-out even without ancestor height correction.

   --- WIDGET / MODULE / ELEMENT WRAPPER LEVEL --------------------- */
.elementor-widget-shortcode:has(.vg-wrap),
.elementor-widget-videogrid:has(.vg-wrap),
.elementor-widget-text-editor:has(.vg-wrap),
.elementor-widget-html:has(.vg-wrap),
.elementor-widget:has(> .elementor-widget-container > .vg-wrap),
.elementor-element:has(> .elementor-widget-container > .vg-wrap),
.elementor-element:has(.vg-wrap),
.elementor-widget-container:has(.vg-wrap),
/* Beaver Builder */
.fl-module:has(.vg-wrap),
.fl-module-content:has(.vg-wrap),
.fl-rich-text:has(.vg-wrap),
.fl-module-rich-text:has(.vg-wrap),
.fl-html:has(.vg-wrap),
.fl-module-html:has(.vg-wrap),
/* Bricks Builder */
.brxe-shortcode:has(.vg-wrap),
.brxe-html:has(.vg-wrap),
.brxe-text:has(.vg-wrap),
.brxe-text-basic:has(.vg-wrap),
.brxe-block:has(.vg-wrap),
.brxe-div:has(.vg-wrap),
[class*="brxe-"]:has(> .vg-wrap),
/* Divi */
.et_pb_module:has(.vg-wrap),
.et_pb_text:has(.vg-wrap),
.et_pb_text_inner:has(.vg-wrap),
.et_pb_code:has(.vg-wrap),
.et_pb_code_inner:has(.vg-wrap),
.et_pb_with_background:has(.vg-wrap),
/* Oxygen Builder */
.ct-text-block:has(.vg-wrap),
.ct-shortcode:has(.vg-wrap),
.ct-code-block:has(.vg-wrap),
.ct-div-block:has(.vg-wrap),
.ct-headline:has(.vg-wrap),
[class*="ct-"]:has(> .vg-wrap),
/* Breakdance */
.bde-shortcode:has(.vg-wrap),
.bde-rich-text:has(.vg-wrap),
.bde-text:has(.vg-wrap),
.bde-code-block:has(.vg-wrap),
.breakdance-shortcode:has(.vg-wrap),
[class*="bde-"]:has(> .vg-wrap),
/* Cwicly */
.cwicly-shortcode:has(.vg-wrap),
.cwicly-block:has(.vg-wrap),
[class*="cwicly-"]:has(> .vg-wrap),
/* WPBakery / Visual Composer */
.vc_general:has(.vg-wrap),
.vc_raw_html:has(.vg-wrap),
.wpb_raw_code:has(.vg-wrap),
.vc_text_separator:has(.vg-wrap),
.wpb_text_column:has(.vg-wrap),
.wpb_wrapper:has(.vg-wrap),
/* SiteOrigin */
.so-widget-sow-editor:has(.vg-wrap),
.panel-widget-style:has(.vg-wrap),
.panel-widget-style-inside:has(.vg-wrap),
/* Brizy */
.brz-shortcode:has(.vg-wrap),
.brz-rich-text:has(.vg-wrap),
[class*="brz-"]:has(> .vg-wrap),
/* Thrive Architect */
.thrv_wrapper:has(.vg-wrap),
.tve_shortcode:has(.vg-wrap),
.tcb-flex-col:has(.vg-wrap),
.thrv_text_element:has(.vg-wrap),
/* Avia / Enfold */
.av_textblock_section:has(.vg-wrap),
.avia_textblock:has(.vg-wrap),
.av_codeblock_section:has(.vg-wrap),
/* Themify */
.themify_builder_module:has(.vg-wrap),
.module-text:has(.vg-wrap),
.module-plain-text:has(.vg-wrap),
/* Live Composer */
.dslc-text-module:has(.vg-wrap),
.dslc-html-module:has(.vg-wrap),
[class*="dslc-"]:has(> .vg-wrap),
/* WP Block Editor (Gutenberg) — the markup the editor outputs to the front-end */
.wp-block-shortcode:has(.vg-wrap),
.wp-block-html:has(.vg-wrap),
.wp-block-group:has(.vg-wrap),
.wp-block-group__inner-container:has(.vg-wrap),
.wp-block-column:has(.vg-wrap),
.wp-block-columns:has(.vg-wrap),
.wp-block-cover__inner-container:has(.vg-wrap),
[class*="wp-block-"]:has(> .vg-wrap) {
    height: auto !important;
    min-height: 0 !important;
    max-height: none !important;
    overflow: visible !important;
}

/* --- COLUMN / ROW / CONTAINER LEVEL ----------------------------- */
.elementor-column:has(.vg-wrap),
.elementor-column-wrap:has(.vg-wrap),
.elementor-element-populated:has(.vg-wrap),
.e-con:has(.vg-wrap),
.e-con-inner:has(.vg-wrap),
.e-flex:has(.vg-wrap),
.e-grid:has(.vg-wrap),
/* Beaver Builder */
.fl-col:has(.vg-wrap),
.fl-col-content:has(.vg-wrap),
.fl-col-group:has(.vg-wrap),
/* Bricks */
.brxe-section:has(.vg-wrap),
.brxe-container:has(.vg-wrap),
/* Divi */
.et_pb_column:has(.vg-wrap),
.et_pb_row:has(.vg-wrap),
.et_pb_row_inner:has(.vg-wrap),
.et_pb_section:has(.vg-wrap),
/* Oxygen */
.ct-section:has(.vg-wrap),
.ct-section-inner-wrap:has(.vg-wrap),
.ct-columns:has(.vg-wrap),
.ct-column:has(.vg-wrap),
/* Breakdance */
.bde-section:has(.vg-wrap),
.bde-column:has(.vg-wrap),
.bde-columns:has(.vg-wrap),
.bde-container:has(.vg-wrap),
/* Cwicly */
.cwicly-section:has(.vg-wrap),
.cwicly-container:has(.vg-wrap),
.cwicly-row:has(.vg-wrap),
.cwicly-column:has(.vg-wrap),
/* WPBakery */
.vc_row:has(.vg-wrap),
.vc_row-fluid:has(.vg-wrap),
.vc_column_container:has(.vg-wrap),
.vc_column-inner:has(.vg-wrap),
.vc_column_inner:has(.vg-wrap),
.vc_section:has(.vg-wrap),
/* SiteOrigin */
.so-panel:has(.vg-wrap),
.panel-grid:has(.vg-wrap),
.panel-grid-cell:has(.vg-wrap),
.panel-row-style:has(.vg-wrap),
/* Brizy */
.brz-section:has(.vg-wrap),
.brz-container:has(.vg-wrap),
.brz-row:has(.vg-wrap),
.brz-column:has(.vg-wrap),
/* Thrive */
.tve-row:has(.vg-wrap),
.tcb-flex-row:has(.vg-wrap),
.tve-section:has(.vg-wrap),
/* Avia / Enfold */
.av_one_full:has(.vg-wrap),
.av_one_half:has(.vg-wrap),
.av_one_third:has(.vg-wrap),
.av_one_fourth:has(.vg-wrap),
.av_section:has(.vg-wrap),
.flex_column:has(.vg-wrap),
/* Themify */
.themify_builder_row:has(.vg-wrap),
.themify_builder_col_4_1:has(.vg-wrap),
.themify_builder_col_3_1:has(.vg-wrap),
.themify_builder_col_2_1:has(.vg-wrap),
.tb_text_module:has(.vg-wrap),
/* Live Composer */
.dslc-row:has(.vg-wrap),
.dslc-modules-area:has(.vg-wrap),
.dslc-module-front:has(.vg-wrap) {
    min-height: 0 !important;
    max-height: none !important;
    overflow: visible !important;
}

/* --- UNIVERSAL FALLBACK — descendant selectors -------------------
   Browsers without :has() (older Edge, Safari < 15.4) get this. The
   wrap's own `position: relative; z-index: 0; padding-bottom: 24px`
   already provides bleed-out protection — these selectors add the
   `isolation: isolate` paint-layer hint that keeps neighbouring
   widget iframes (YouTube/Vimeo embeds in adjacent widgets) from
   painting into our card area. */
.elementor-widget-shortcode .vg-wrap,
.elementor-widget-videogrid .vg-wrap,
.elementor-widget-text-editor .vg-wrap,
.elementor-widget-html .vg-wrap,
.fl-module-content .vg-wrap,
.fl-rich-text .vg-wrap,
.brxe-shortcode .vg-wrap,
.brxe-html .vg-wrap,
.brxe-text .vg-wrap,
.et_pb_text_inner .vg-wrap,
.et_pb_code_inner .vg-wrap,
.ct-text-block .vg-wrap,
.ct-shortcode .vg-wrap,
.bde-shortcode .vg-wrap,
.bde-rich-text .vg-wrap,
.cwicly-shortcode .vg-wrap,
.wpb_text_column .vg-wrap,
.wpb_raw_code .vg-wrap,
.so-widget-sow-editor .vg-wrap,
.brz-shortcode .vg-wrap,
.brz-rich-text .vg-wrap,
.thrv_text_element .vg-wrap,
.tve_shortcode .vg-wrap,
.av_textblock_section .vg-wrap,
.themify_builder_module .vg-wrap,
.dslc-text-module .vg-wrap,
.dslc-html-module .vg-wrap,
.wp-block-shortcode .vg-wrap,
.wp-block-html .vg-wrap {
    isolation: isolate;
}


.vg-wrap.vg-wrap {
    --vg-accent: #2563eb;
    --vg-accent-hover: #1d4ed8;
    --vg-bg: #ffffff;
    --vg-surface: #ffffff;
    --vg-surface-2: #f8fafc;
    --vg-surface-3: #f1f5f9;
    --vg-border: #e5e7eb;
    --vg-border-strong: #d1d5db;
    --vg-text: #0f172a;
    --vg-text-muted: #475569;
    --vg-text-soft: #94a3b8;
    --vg-shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.06);
    --vg-shadow-md: 0 4px 12px rgba(15, 23, 42, 0.08);
    --vg-shadow-lg: 0 12px 32px rgba(15, 23, 42, 0.12);
    --vg-radius: 12px;
    --vg-radius-sm: 8px;
    --vg-radius-lg: 16px;
    --vg-slider-bg: #f8fafc;
    --vg-slider-text: #0f172a;
    --vg-transition: 200ms cubic-bezier(0.4, 0, 0.2, 1);

    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    color: var(--vg-text);
    line-height: 1.5;

    /* WRAP — v1.7.5 fix
       ------------------------------------------------------------------
       SIMPLE BLOCK is the right answer here. Earlier versions tried
       `display: flex` and `contain: layout` to "isolate" the wrap from
       the page; those were the bug. Both prevent the wrap from reporting
       its real intrinsic height to its Elementor parent column, so the
       parent section's background ends a few pixels too high — clipping
       the bottom of the last card.

       Plain `display: block` lets the wrap's height equal the natural
       sum of its children (header + grid + spacer). `position: relative`
       + `z-index: 0` still gives us a stacking context (so external
       absolutely-positioned page elements can't paint over our cards)
       without the side effect of breaking height calc.

       What we removed and why:
         - `display: flex; flex-direction: column` → broke height
            measurement inside Elementor flex columns.
         - `contain: layout` → isolates layout, causing parent to see
            wrong intrinsic size.
         - `clear: both` → forced layout passes that conflicted with
            Elementor's own clearfix; user identified this directly. */
    position: relative;
    z-index: 0;
    display: block;
    box-sizing: border-box;
    width: 100%;
    max-width: 100%;
    height: auto !important;
    min-height: 0 !important;
    margin: 0 0 24px 0;
    /* Padding-bottom: real safety zone. If the parent column STILL
       mismeasures slightly (legacy Elementor versions), this padding
       absorbs the difference so the navy footer can't clip the last
       card's title bar. */
    padding: 0 0 24px 0;
    overflow: visible;
}

/* The grid itself MUST grow to contain its children. Some themes/builders
   apply `align-items: stretch` on flex parents that can squash a grid. */
.vg-wrap.vg-wrap .vg-grid,
.vg-wrap.vg-wrap .vg-slider,
.vg-wrap.vg-wrap .vg-albums {
    height: auto !important;
    min-height: 0 !important;
    max-height: none !important;
}

/* Bottom spacer — provides a real gap below the last card so a parent
   section that hugs its children tightly cannot visually crash into the
   next section. Height is 1px (not 0) which forces the spacer to actually
   participate in layout sizing in some buggy theme contexts where a
   zero-height pseudo gets dropped from the box model. */
.vg-wrap.vg-wrap::after {
    content: "";
    display: block;
    clear: both;
    height: 1px;
    width: 100%;
    margin-top: 8px;
    visibility: hidden;
}

.vg-wrap.vg-wrap *,
.vg-wrap.vg-wrap *::before,
.vg-wrap.vg-wrap *::after {
    box-sizing: border-box;
}

.vg-wrap.vg-wrap ul,
.vg-wrap.vg-wrap ol,
.vg-wrap.vg-wrap li {
    list-style: none !important;
    padding-left: 0 !important;
    margin: 0 !important;
}

.vg-wrap.vg-wrap ul::before,
.vg-wrap.vg-wrap ol::before,
.vg-wrap.vg-wrap li::before,
.vg-wrap.vg-wrap ul::marker,
.vg-wrap.vg-wrap ol::marker,
.vg-wrap.vg-wrap li::marker {
    content: none !important;
    display: none !important;
}

.vg-wrap.vg-wrap button {
    appearance: none;
    -webkit-appearance: none;
    background: transparent;
    border: 0;
    margin: 0;
    padding: 0;
    font: inherit;
    color: inherit;
    cursor: pointer;
    text-align: inherit;
    line-height: 1;
    text-transform: none;
    letter-spacing: normal;
    box-shadow: none;
}

.vg-wrap.vg-wrap button:hover,
.vg-wrap.vg-wrap button:focus {
    background: transparent;
    box-shadow: none;
    transform: none;
}

.vg-wrap.vg-wrap img {
    max-width: 100%;
    height: auto;
    display: block;
    border: 0;
}

.vg-wrap.vg-wrap h1,
.vg-wrap.vg-wrap h2,
.vg-wrap.vg-wrap h3,
.vg-wrap.vg-wrap h4,
.vg-wrap.vg-wrap p,
.vg-wrap.vg-wrap span {
    margin: 0;
    padding: 0;
    font-family: inherit;
    color: inherit;
}

/* Screen-reader-only utilities (CRITICAL — these were leaking visibly) */
.vg-wrap.vg-wrap .vg-sr-only,
.vg-wrap.vg-wrap .vg-sr-live {
    position: absolute !important;
    width: 1px !important;
    height: 1px !important;
    padding: 0 !important;
    margin: -1px !important;
    overflow: hidden !important;
    clip: rect(0, 0, 0, 0) !important;
    white-space: nowrap !important;
    border: 0 !important;
}

/* ============================================
   2. THEMES
   ============================================ */
.vg-wrap.vg-theme-dark {
    --vg-bg: #0f172a;
    --vg-surface: #1e293b;
    --vg-surface-2: #334155;
    --vg-surface-3: #475569;
    --vg-border: #334155;
    --vg-border-strong: #475569;
    --vg-text: #f1f5f9;
    --vg-text-muted: #cbd5e1;
    --vg-text-soft: #94a3b8;
    --vg-slider-bg: #1e293b;
    --vg-slider-text: #f1f5f9;
}

@media (prefers-color-scheme: dark) {
    .vg-wrap.vg-theme-auto {
        --vg-bg: #0f172a;
        --vg-surface: #1e293b;
        --vg-surface-2: #334155;
        --vg-border: #334155;
        --vg-text: #f1f5f9;
        --vg-text-muted: #cbd5e1;
        --vg-slider-bg: #1e293b;
        --vg-slider-text: #f1f5f9;
    }
}

/* ============================================
   3. HEADER
   ============================================ */
.vg-wrap.vg-wrap .vg-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 16px;
    margin-bottom: 24px;
}

.vg-wrap.vg-wrap .vg-title {
    font-size: 1.5rem;
    font-weight: 600;
    letter-spacing: -0.02em;
    color: var(--vg-text);
    line-height: 1.3;
}

/* ============================================
   4. VIEW TOGGLE (in header — Grid/Slider)
   ============================================ */
.vg-wrap.vg-wrap .vg-view-toggle {
    display: inline-flex;
    background: var(--vg-surface-2);
    border-radius: 999px;
    padding: 4px;
    gap: 2px;
}

.vg-wrap.vg-wrap .vg-toggle-btn {
    padding: 8px 16px;
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--vg-text-muted);
    border-radius: 999px;
    transition: var(--vg-transition);
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.vg-wrap.vg-wrap .vg-toggle-btn:hover { color: var(--vg-text); }

.vg-wrap.vg-wrap .vg-toggle-btn[aria-pressed="true"] {
    background: var(--vg-surface);
    color: var(--vg-accent);
    box-shadow: var(--vg-shadow-sm);
}

.vg-wrap.vg-wrap .vg-toggle-btn:focus-visible {
    outline: 2px solid var(--vg-accent);
    outline-offset: 2px;
}

/* ============================================
   5. GRID
   ============================================ */
.vg-wrap.vg-wrap .vg-grid {
    display: grid;
    gap: 24px;
    grid-template-columns: repeat(var(--vg-cols, 3), minmax(0, 1fr));
    /* `grid-auto-rows: max-content` makes each row exactly as tall as
       its tallest card (thumb + title), no taller. Without this, when
       the parent column has min-height (theme banner, hero), the grid
       stretches its rows and cards start overlapping the row below. */
    grid-auto-rows: max-content;
    width: 100%;
    /* Reset any theme-applied list/flex weirdness */
    align-items: start;
    justify-items: stretch;
    /* Establish a local stacking context so external positioned page
       elements cannot paint *between* our cards. */
    position: relative;
    z-index: 0;
}

/* Direct grid children must align to start, not stretch.
   Stretching forces every card to the height of the tallest one,
   which then leaves blank space at the bottom of shorter cards
   that following content can visually invade in narrow viewports. */
.vg-wrap.vg-wrap .vg-grid > * {
    align-self: start;
    min-width: 0;
    min-height: 0;
}

/* v1.7.8 — RESPONSIVE COLUMN COUNTS controlled per-instance.
   Each instance emits its own --vg-cols-tablet and --vg-cols-mobile
   custom properties from the inline <style> tag in the shortcode
   render. The default fallbacks here (2 and 1) match the old hard-
   coded behaviour for backwards compatibility. Admins can override
   per-shortcode via attributes, per-widget via Elementor controls,
   per-block via the Gutenberg sidebar, or globally from
   VideoGrid → Settings. */
@media (max-width: 900px) {
    .vg-wrap.vg-wrap .vg-grid {
        grid-template-columns: repeat(var(--vg-cols-tablet, 2), minmax(0, 1fr));
    }
}

@media (max-width: 560px) {
    .vg-wrap.vg-wrap .vg-grid {
        grid-template-columns: repeat(var(--vg-cols-mobile, 1), minmax(0, 1fr));
    }
}

/* ============================================
   5b. ALBUMS — tile grid (top-level "view=albums")
   ============================================ */
.vg-wrap.vg-wrap .vg-albums {
    display: grid;
    gap: 24px;
    grid-template-columns: repeat(var(--vg-cols, 3), minmax(0, 1fr));
    grid-auto-rows: max-content;
    width: 100%;
    align-items: start;
    justify-items: stretch;
    position: relative;
    z-index: 0;
}

.vg-wrap.vg-wrap .vg-albums > * {
    align-self: start;
    min-width: 0;
    min-height: 0;
}

@media (max-width: 900px) {
    .vg-wrap.vg-wrap .vg-albums {
        grid-template-columns: repeat(var(--vg-cols-tablet, 2), minmax(0, 1fr));
    }
}
@media (max-width: 560px) {
    .vg-wrap.vg-wrap .vg-albums {
        grid-template-columns: repeat(var(--vg-cols-mobile, 1), minmax(0, 1fr));
    }
}

.vg-wrap.vg-wrap .vg-album-card {
    position: relative;
    display: block;
    background: var(--vg-surface) !important;
    background-color: var(--vg-surface) !important;
    border: 1px solid var(--vg-border);
    border-radius: var(--vg-radius);
    overflow: hidden;
    width: 100%;
    margin: 0;
    padding: 0;
    transition: var(--vg-transition);
    z-index: 1;
    isolation: isolate;
    min-height: 1px;
    cursor: pointer;
}

.vg-wrap.vg-wrap .vg-album-card:hover {
    transform: translateY(-3px);
    z-index: 2;
    border-color: var(--vg-border-strong);
    box-shadow: var(--vg-shadow-lg);
}

/* Album trigger — invisible absolute overlay (same pattern as video card) */
.vg-wrap.vg-wrap .vg-album-trigger {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    background: transparent;
    border: 0;
    margin: 0;
    padding: 0;
    cursor: pointer;
    z-index: 4;
    color: transparent;
    font-size: 0;
    line-height: 0;
    text-indent: -9999px;
    -webkit-appearance: none;
    appearance: none;
}

.vg-wrap.vg-wrap .vg-album-trigger:focus-visible {
    outline: 2px solid var(--vg-accent);
    outline-offset: -2px;
    border-radius: var(--vg-radius);
}

.vg-wrap.vg-wrap .vg-album-trigger:focus-visible {
    outline: 2px solid var(--vg-accent);
    outline-offset: 2px;
}

.vg-wrap.vg-wrap .vg-album-cover {
    position: relative;
    display: block;
    width: 100%;
    background: var(--vg-surface-3);
    overflow: hidden;
    /* Aspect-ratio fallback: padding-bottom keeps the box 16:9 even
       without aspect-ratio support. */
    padding-bottom: 56.25%;
    height: 0;
    flex-shrink: 0;
    flex-grow: 0;
    isolation: isolate;
    contain: paint;
}

@supports (aspect-ratio: 16 / 9) {
    .vg-wrap.vg-wrap .vg-album-cover {
        aspect-ratio: 16 / 9;
        padding-bottom: 0;
        height: auto;
        min-height: 100px;
    }
}

@supports not (aspect-ratio: 16 / 9) {
    .vg-wrap.vg-wrap .vg-album-cover {
        padding-bottom: 56.25%;
        height: 0;
    }
}

.vg-wrap.vg-wrap .vg-album-cover img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 400ms cubic-bezier(0.4, 0, 0.2, 1);
}

.vg-wrap.vg-wrap .vg-album-card:hover .vg-album-cover img {
    transform: scale(1.04);
}

/* Subtle gradient overlay + arrow on hover */
.vg-wrap.vg-wrap .vg-album-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(180deg, rgba(15, 23, 42, 0) 50%, rgba(15, 23, 42, 0.55) 100%);
    color: #ffffff;
    transition: background 200ms;
    pointer-events: none;
}

.vg-wrap.vg-wrap .vg-album-card:hover .vg-album-overlay {
    background: linear-gradient(180deg, rgba(15, 23, 42, 0.1) 0%, rgba(15, 23, 42, 0.6) 100%);
}

.vg-wrap.vg-wrap .vg-album-overlay svg {
    background: rgba(255, 255, 255, 0.95);
    color: var(--vg-text);
    border-radius: 50%;
    padding: 12px;
    width: 56px;
    height: 56px;
    box-sizing: border-box;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
    transition: transform 200ms, color 200ms, background 200ms;
}

.vg-wrap.vg-wrap .vg-album-card:hover .vg-album-overlay svg {
    transform: scale(1.08);
    background: var(--vg-accent);
    color: #ffffff;
}

.vg-wrap.vg-wrap .vg-album-count {
    position: absolute;
    bottom: 10px;
    right: 10px;
    background: rgba(15, 23, 42, 0.85);
    color: #ffffff !important;
    padding: 4px 10px;
    border-radius: 6px;
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1;
    z-index: 1;
    backdrop-filter: blur(4px);
}

.vg-wrap.vg-wrap .vg-album-meta {
    display: block;
    padding: 14px 16px 16px;
    background: var(--vg-surface);
}

.vg-wrap.vg-wrap .vg-album-name {
    display: block;
    font-size: 1.0625rem;
    font-weight: 600;
    color: var(--vg-text);
    line-height: 1.3;
    letter-spacing: -0.01em;
}

.vg-wrap.vg-wrap .vg-album-desc {
    display: -webkit-box;
    margin-top: 6px;
    font-size: 0.8125rem;
    color: var(--vg-text-muted);
    line-height: 1.5;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* ============================================
   5c. ALBUM DETAIL — videos for the chosen album
   ============================================ */
.vg-wrap.vg-wrap .vg-album-detail[hidden] { display: none !important; }

.vg-wrap.vg-wrap .vg-album-detail-head {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 20px;
    padding-bottom: 16px;
    border-bottom: 1px solid var(--vg-border);
}

.vg-wrap.vg-wrap .vg-back-btn {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 6px 12px 6px 8px;
    background: var(--vg-surface-2);
    border: 1px solid var(--vg-border);
    border-radius: 999px;
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--vg-text-muted);
    cursor: pointer;
    transition: var(--vg-transition);
    line-height: 1;
}

.vg-wrap.vg-wrap .vg-back-btn:hover {
    background: var(--vg-surface);
    color: var(--vg-text);
    border-color: var(--vg-border-strong);
}

.vg-wrap.vg-wrap .vg-back-btn:focus-visible {
    outline: 2px solid var(--vg-accent);
    outline-offset: 2px;
}

.vg-wrap.vg-wrap .vg-album-detail-title {
    font-size: 1.25rem;
    font-weight: 600;
    color: var(--vg-text);
    letter-spacing: -0.02em;
    line-height: 1.3;
    margin: 0 !important;
    flex: 1;
    min-width: 0;
}

.vg-wrap.vg-wrap .vg-album-detail-count {
    font-size: 0.8125rem;
    color: var(--vg-text-soft);
    font-weight: 500;
}

/* Tiny dot loading indicator */
.vg-wrap.vg-wrap .vg-loading {
    display: flex;
    gap: 6px;
    justify-content: center;
    align-items: center;
    padding: 48px 0;
}

.vg-wrap.vg-wrap .vg-loading span {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--vg-accent);
    animation: vg-bounce 1.2s ease-in-out infinite both;
}

.vg-wrap.vg-wrap .vg-loading span:nth-child(2) { animation-delay: -0.16s; }
.vg-wrap.vg-wrap .vg-loading span:nth-child(3) { animation-delay: -0.32s; }

@keyframes vg-bounce {
    0%, 80%, 100% { transform: scale(0.6); opacity: 0.5; }
    40%           { transform: scale(1.0); opacity: 1; }
}

/* When in album-detail mode, hide the album tile grid */
.vg-wrap.vg-wrap[data-stage="detail"] [data-role="albums"] { display: none; }
.vg-wrap.vg-wrap[data-stage="albums"] [data-role="album-detail"] { display: none; }

/* Smooth fade between stages */
.vg-wrap.vg-wrap [data-role="albums"],
.vg-wrap.vg-wrap [data-role="album-detail"] {
    animation: vg-stage-fade 280ms ease;
}

@keyframes vg-stage-fade {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* View-switching: show only the active view (shortcode renders both) */
/* v1.7.17 — bulletproof view-switching. The HTML now only renders the
   inactive view at all when the toggle is on, but if it IS on the page
   for any reason (legacy cache, third-party caching plugin, builder
   preview races), these rules keep it suppressed. Triple-class
   specificity beats most builder !important rules without us needing
   our own !important war. */
.vg-wrap.vg-wrap.vg-wrap[data-view="grid"]   .vg-slider { display: none !important; height: 0 !important; visibility: hidden !important; }
.vg-wrap.vg-wrap.vg-wrap[data-view="slider"] .vg-grid   { display: none !important; height: 0 !important; visibility: hidden !important; }

/* ============================================
   6. CARD — v1.7.5 stretched-link pattern
   ============================================
   New markup:
     <article.vg-card>
       <div.vg-thumb>...</div>          ← block, 16:9 aspect-ratio
       <div.vg-card-title>...</div>     ← block, padded
       <button.vg-card-trigger></button> ← position: absolute, inset: 0
     </article>

   The card's height = thumb height + title height. PERIOD. No more
   button-as-flex-container ambiguity, no more inline-block button
   children collapsing. The button is an invisible overlay that
   captures clicks across the entire card surface.

   This is the "stretched link" pattern (Bootstrap calls it that, MDN
   documents it under "card layout patterns"). It is the right tool
   here because the card has multiple meaningful parts but one click
   action — exactly what an invisible overlay button is for. */
.vg-wrap.vg-wrap .vg-card {
    position: relative;
    display: block;
    background: var(--vg-surface) !important;
    background-color: var(--vg-surface) !important;
    border: 1px solid var(--vg-border);
    border-radius: var(--vg-radius);
    overflow: hidden;
    width: 100%;
    margin: 0;
    padding: 0;
    transition: var(--vg-transition);
    /* Stack above default page content so positioned page elements
       (sidebar widgets, decorative images, footer overlays) cannot
       paint over the card. */
    z-index: 1;
    isolation: isolate;
    /* Guarantees the card cannot collapse — even if every child fails
       to render, the card itself shows up. */
    min-height: 1px;
    cursor: pointer;
}

.vg-wrap.vg-wrap .vg-card:hover {
    transform: translateY(-3px);
    z-index: 2;
    border-color: var(--vg-border-strong);
    box-shadow: var(--vg-shadow-lg);
}

/* The trigger is now an invisible absolute overlay — no longer the
   container of the card content. It still exists as a real <button>
   for accessibility (keyboard, screen reader, focus management). */
.vg-wrap.vg-wrap .vg-card-trigger {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    background: transparent;
    border: 0;
    margin: 0;
    padding: 0;
    cursor: pointer;
    /* Above thumb children (image, play icon, duration badge), so the
       whole card surface is the click target. The play icon and
       duration badge sit visually on top because the trigger is
       fully transparent — no z-index war needed. */
    z-index: 4;
    /* Hide the aria-label text from sighted users without removing it
       from the accessibility tree. */
    color: transparent;
    font-size: 0;
    line-height: 0;
    text-indent: -9999px;
    -webkit-appearance: none;
    appearance: none;
}

.vg-wrap.vg-wrap .vg-card-trigger:focus-visible {
    outline: 2px solid var(--vg-accent);
    outline-offset: -2px;
    border-radius: var(--vg-radius);
}

.vg-wrap.vg-wrap .vg-card-trigger:focus-visible {
    outline: 2px solid var(--vg-accent);
    outline-offset: 2px;
}

/* Thumb — always has a guaranteed 16:9 aspect ratio so the card has
   a real height. Bug fix v1.7.4: `padding-bottom: 56.25%` is now ALWAYS
   applied (not just as @supports-not fallback) and `aspect-ratio` adds
   on top of it for modern browsers. This belt-and-suspenders approach
   means the card NEVER collapses to zero height even if a browser bug,
   theme reset, or `display: contents` ancestor breaks one method.
   `flex-shrink: 0` prevents the parent flex (.vg-card-trigger) from
   collapsing the thumb when the card title is long. */
.vg-wrap.vg-wrap .vg-thumb {
    position: relative;
    display: block;
    width: 100%;
    background: var(--vg-surface-3);
    overflow: hidden;
    /* v1.7.36 — `aspect-ratio` is now applied unconditionally (the
       @supports gate was dropped). aspect-ratio shipped in all
       evergreen browsers in 2021 and is supported by every browser
       version that this plugin's `Requires WP 5.8` baseline can
       coexist with. The previous `padding-bottom: 56.25%; height: 0`
       fallback was actually CAUSING some of the mobile overlap
       reports — when the Samsung Browser's `@supports` query
       returned false (a known bug, fixed in v23 but still in the
       wild), the padding-bottom path took over. padding-bottom on
       a flex-column child does NOT reserve height the same way
       aspect-ratio does, so the parent .vg-card was collapsing on
       those browsers and the title rendered ON TOP of the
       thumbnail. Aspect-ratio is universal now. */
    aspect-ratio: 16 / 9;
    /* Hard floor on min-height so the box can never collapse to 0,
       even mid-resize transition or while images are decoding. */
    min-height: 100px;
    /* Don't let flex-shrink the thumb below its computed height. */
    flex-shrink: 0;
    flex-grow: 0;
    /* `overflow: hidden` is the real guarantee that iframe previews
       (Wistia / Loom poster frames) cannot paint outside this box.
       `isolation` keeps z-index local. */
    isolation: isolate;
}

/* Padding-bottom fallback for ancient browsers that don't support
   `aspect-ratio`. Used only when the property is genuinely missing —
   modern browsers ignore this rule because aspect-ratio takes
   precedence in cascade order. We DON'T set `height: 0` anymore
   because that creates the flex-collapse bug described above; the
   padding-bottom alone gives the right shape without zeroing height. */
@supports not (aspect-ratio: 16 / 9) {
    .vg-wrap.vg-wrap .vg-thumb {
        aspect-ratio: auto;
        padding-bottom: 56.25%;
    }
}

.vg-wrap.vg-wrap .vg-thumb img,
.vg-wrap.vg-wrap .vg-thumb video,
.vg-wrap.vg-wrap .vg-thumb iframe {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 400ms cubic-bezier(0.4, 0, 0.2, 1);
    background: #000;
    pointer-events: none;
    border: 0;
}

/* iframe acts as a static visual preview only —
   pointer-events:none ensures clicks bubble to .vg-card-trigger.
   v1.7.36 — the previous `width: 102%; height: 102%; inset: -1%`
   oversize trick (used to crop YouTube/Wistia chrome) was making
   the iframe extend 1% outside the .vg-thumb's overflow box. With
   the v1.7.34 `overflow: clip` on the wrap, that overflow can get
   clipped at an unexpected moment during mobile scroll, which is
   one of the visual glitches the user reported. Drop the oversize;
   if the provider's chrome shows, that's a tiny visual nit
   compared to a layout glitch. */
.vg-wrap.vg-wrap .vg-thumb-iframe {
    /* v1.7.50 — slightly oversize the iframe so any provider branding
       (Wistia "powered by" footer, Loom share controls) is nudged
       outside the visible thumbnail area. The .vg-thumb has
       overflow: hidden, so the oversize is invisibly clipped.
       Smaller than v1.7.32's 102% to stay within mobile WebKit's
       safe paint boundary. */
    width: 101%;
    height: 101%;
    inset: -0.5% -0.5% -0.5% -0.5%;
    /* Iframe is decorative — clicks must reach .vg-card-trigger. */
    pointer-events: none;
}

.vg-wrap.vg-wrap .vg-card:hover .vg-thumb img,
.vg-wrap.vg-wrap .vg-card:hover .vg-thumb video {
    transform: scale(1.04);
}

/* Placeholder */
.vg-wrap.vg-wrap .vg-thumb-fallback {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(135deg, var(--vg-surface-2) 0%, var(--vg-surface-3) 100%);
}

.vg-wrap.vg-wrap .vg-thumb-fallback::before {
    content: "";
    width: 56px;
    height: 56px;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><polygon points='23 7 16 12 23 17 23 7'/><rect x='1' y='5' width='15' height='14' rx='2' ry='2'/></svg>");
    background-repeat: no-repeat;
    background-position: center;
    background-size: contain;
    opacity: 0.6;
}

/* Play button overlay — v1.7.13 size, colour, circle now configurable. */
.vg-wrap.vg-wrap .vg-play {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;
    transition: var(--vg-transition);
}

.vg-wrap.vg-wrap .vg-play svg {
    width: var(--vg-play-size, 88px);
    height: var(--vg-play-size, 88px);
    filter: drop-shadow(0 6px 20px rgba(0,0,0,0.35));
    transition: var(--vg-transition);
    /* The triangle is offset visually inside the circle so it appears
       optically centered. */
}

.vg-wrap.vg-wrap .vg-card:hover .vg-play svg {
    transform: scale(1.08);
    filter: drop-shadow(0 10px 28px rgba(0,0,0,0.45));
}

/* Duration badge — bottom right */
.vg-wrap.vg-wrap .vg-duration {
    position: absolute;
    bottom: 10px;
    right: 10px;
    background: rgba(15, 23, 42, 0.85);
    color: #ffffff !important;
    padding: 4px 8px;
    border-radius: 4px;
    font-size: 0.75rem;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    line-height: 1;
    z-index: 1;
    backdrop-filter: blur(4px);
}

/* Card title — block sibling of the thumb (NOT inside a flex button).
   Has its own padding and background so it visually completes the
   card. The card's overall height = thumb height + this title's
   height + the wrap's padding. Pure block flow, no surprises. */
.vg-wrap.vg-wrap .vg-card-title {
    /* v1.7.35 — outer container is flex so the inner clamped block
       can be vertically centred. The line-clamp itself still uses
       -webkit-box (applied via the inner span below). Without the
       inner-span split, declaring `display: flex` here would discard
       the `display: -webkit-box` it replaced and the title would
       overflow past 2 lines instead of clamping. */
    display: flex;
    align-items: center;
    padding: 14px 16px 16px;
    margin: 0;
    font-size: 0.9375rem;
    font-weight: 600;
    line-height: 1.4;
    color: var(--vg-text);
    letter-spacing: -0.01em;
    word-break: break-word;
    background: var(--vg-surface);
    /* Pin to EXACTLY 2 lines (min + max) so all cards on a row are the
       same height. */
    min-height: calc(1.4em * 2 + 30px);
    max-height: calc(1.4em * 2 + 30px);
    box-sizing: border-box;
    /* Hide overflow at the OUTER level too, so a long unbroken word
       can't punch through the centring envelope. */
    overflow: hidden;
}

/* The actual line-clamp lives on the inner span — `display: -webkit-box`
   is required for `-webkit-line-clamp` to apply, and it cannot
   co-exist with the outer `display: flex`. The renderer already
   wraps the title text in this span (see render_card). For
   backwards compatibility with markup that has a bare text node,
   the rule also targets the title element directly when it has no
   element children. */
.vg-wrap.vg-wrap .vg-card-title > span,
.vg-wrap.vg-wrap .vg-card-title:not(:has(> *)) {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    line-clamp: 2;
    overflow: hidden;
    width: 100%;
}

/* ============================================
   7. SLIDER — no box, just a clean slider
   ============================================ */
.vg-wrap.vg-wrap .vg-slider {
    position: relative;
    background: var(--vg-slider-bg, transparent);
    border: 0;
    border-radius: 0;
    padding: 0;
    color: var(--vg-text);
}

.vg-wrap.vg-wrap .vg-slider .vg-title {
    color: var(--vg-text);
}

.vg-wrap.vg-wrap .vg-slider-viewport {
    position: relative;
    overflow: hidden;
    /* v1.7.14 — clip aggressively so adjacent slides can never bleed
       past the rounded corners of cards. */
    contain: paint;
    width: 100%;
}

.vg-wrap.vg-wrap .vg-slider-track {
    display: flex;
    transition: transform var(--vg-transition-ms, 600ms) cubic-bezier(0.4, 0, 0.2, 1);
    gap: var(--vg-slide-gap, 20px);
    will-change: transform;
}

/* v1.7.14 — when slides_per_view is exactly 1, the user wants ONE
   video at a time with no part of any other slide visible. We force
   gap to 0 so adjacent slides can never peek through the viewport
   edges, and pin the slide to exactly 100% of the viewport. The track
   transition still works because translateX is pixel-based now. */
.vg-wrap.vg-wrap[data-spv="1"] .vg-slider-track { gap: 0 !important; }
.vg-wrap.vg-wrap[data-spv="1"] .vg-slide        { flex: 0 0 100% !important; }
@media (max-width: 900px) {
    .vg-wrap.vg-wrap[data-spv-tablet="1"] .vg-slider-track { gap: 0 !important; }
    .vg-wrap.vg-wrap[data-spv-tablet="1"] .vg-slide        { flex: 0 0 100% !important; }
}
@media (max-width: 560px) {
    .vg-wrap.vg-wrap[data-spv-mobile="1"] .vg-slider-track { gap: 0 !important; }
    .vg-wrap.vg-wrap[data-spv-mobile="1"] .vg-slide        { flex: 0 0 100% !important; }
}

/* v1.7.13 — slide width is now driven by --vg-spv (slides per view).
   The per-instance <style> block sets the precise calc(...) per
   breakpoint; this base rule is the safe single-slide fallback for
   instances that don't emit a per-instance style block (older code
   paths, AJAX-loaded album drilldowns). */
.vg-wrap.vg-wrap .vg-slide {
    flex: 0 0 100%;
    min-width: 0;
}

/* Arrows — v1.7.13 colour customisable via CSS vars */
.vg-wrap.vg-wrap .vg-arrow {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: var(--vg-arrow-bg, var(--vg-surface)) !important;
    border: 0 !important;
    color: var(--vg-arrow-color, var(--vg-text));
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 4px 12px rgba(0,0,0,0.18);
    transition: var(--vg-transition);
    z-index: 2;
    cursor: pointer;
}

.vg-wrap.vg-wrap .vg-arrow:hover:not(:disabled) {
    /* v1.7.54 — configurable hover colours.
       Defaults preserve the original behaviour:
         hover bg     = accent colour
         hover icon   = white
       The user can override either independently via the per-instance
       --vg-arrow-bg-hover / --vg-arrow-color-hover CSS variables,
       which are emitted from the gallery widget / shortcode atts
       below. */
    background: var(--vg-arrow-bg-hover, var(--vg-accent)) !important;
    color: var(--vg-arrow-color-hover, #ffffff) !important;
    transform: translateY(-50%) scale(1.08);
    box-shadow: 0 8px 24px rgba(0,0,0,0.28);
}

.vg-wrap.vg-wrap .vg-arrow:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

.vg-wrap.vg-wrap .vg-arrow:focus-visible {
    outline: 2px solid var(--vg-accent);
    outline-offset: 2px;
}

.vg-wrap.vg-wrap .vg-arrow-prev,
.vg-wrap.vg-wrap .vg-arrow--prev { left: 8px; }
.vg-wrap.vg-wrap .vg-arrow-next,
.vg-wrap.vg-wrap .vg-arrow--next { right: 8px; }

.vg-wrap.vg-wrap .vg-arrow svg {
    width: 22px;
    height: 22px;
    fill: currentColor;
    stroke: none;
}

/* Dots — v1.7.13 colours customisable
   v1.7.18 — wrapped in .vg-dots-container which can render as an
   optional pill (background + padding + radius) when the per-instance
   style block sets a background. `width: fit-content` shrink-wraps to
   the dot row width; `margin: ... auto` centers the pill horizontally
   inside the slider. Without a background colour set, the container
   is invisible — existing layouts unchanged. */
.vg-wrap.vg-wrap .vg-dots-container {
    display: block;
    width: -moz-fit-content;
    width: fit-content;
    max-width: 100%;
    margin: 28px auto 0;
    text-align: center;
}

.vg-wrap.vg-wrap .vg-dots {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 8px;
    margin: 0 !important;
    list-style: none;
    padding: 0;
}

.vg-wrap.vg-wrap .vg-dot {
    width: 10px;
    height: 10px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: var(--vg-dot-inactive, var(--vg-border-strong));
    transition: var(--vg-transition);
    flex-shrink: 0;
    line-height: 0;
    font-size: 0;
    cursor: pointer;
}

.vg-wrap.vg-wrap .vg-dot:hover { background: var(--vg-text-soft); }

.vg-wrap.vg-wrap .vg-dot[aria-selected="true"],
.vg-wrap.vg-wrap .vg-dot[aria-current="true"] {
    background: var(--vg-dot-active, var(--vg-accent));
    width: 28px;
    border-radius: 5px;
}

.vg-wrap.vg-wrap .vg-dot:focus-visible {
    outline: 2px solid var(--vg-accent);
    outline-offset: 2px;
}

/* ============================================
   8. DIALOG / MODAL
   ============================================ */
.vg-dialog {
    position: fixed;
    /* v1.7.45 — split viewport units by purpose:
         BACKDROP coverage (the dimmed/blurred layer behind the
         panel): uses LARGE viewport (100lvh) so when the URL bar
         collapses mid-scroll, the backdrop already extends to the
         full possible viewport — no white/uncovered strip flashes.
         PANEL positioning (the white card with title + video +
         close button): uses SMALL viewport (100svh) so even when
         the URL bar is fully showing, every interactive element —
         especially the close button — is always visible and
         tappable. The close button must NEVER go below the URL bar.

       The dialog container itself uses the LARGE viewport so its
       coordinate system matches the backdrop. The panel inside
       constrains itself to the SMALL viewport via max-height.

       lvh / svh / dvh are supported in Safari 15.4+, Chrome 108+,
       Firefox 101+. Fallback chain:
         1. inset: 0 — works everywhere, just sometimes mis-sized
         2. height: 100vh — explicit fallback
         3. height: 100lvh — modern, exact for the backdrop. */
    inset: 0;
    width: 100%;
    height: 100vh;
    height: 100lvh;
    z-index: 99999;
    /* Center the panel using flex; max constraints on the panel
       itself keep it within the safe (small) viewport. */
    display: flex;
    align-items: center;
    justify-content: center;
    /* Padding shrinks to the safe area so the panel can never push
       its edges into a notch or under the URL bar. */
    padding: 20px;
    padding-top:    max(20px, env(safe-area-inset-top));
    padding-bottom: max(20px, env(safe-area-inset-bottom));
    padding-left:   max(20px, env(safe-area-inset-left));
    padding-right:  max(20px, env(safe-area-inset-right));
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
    box-sizing: border-box;
    overscroll-behavior: contain;
    -webkit-text-size-adjust: 100%;
}

/* Reinforced hidden state. Some themes / minifiers strip the `[hidden]`
   attribute or override `display: none` with their own modal styles.
   We pin every possible vector: `[hidden]`, `[aria-hidden="true"]`, and
   the absence of `[data-vg-open]` (set by the JS when the dialog is
   actually shown). v1.7.4 also pins `visibility` and `pointer-events`
   so even if `display` is somehow forced visible by !important, the
   dialog remains effectively invisible until JS opens it. */
.vg-dialog:not([data-vg-open]) {
    display: none !important;
    visibility: hidden !important;
    pointer-events: none !important;
}

.vg-dialog[hidden] {
    display: none !important;
    visibility: hidden !important;
    pointer-events: none !important;
}

.vg-dialog * { box-sizing: border-box; }

.vg-dialog ul, .vg-dialog ol, .vg-dialog li {
    list-style: none !important;
    padding-left: 0 !important;
    margin: 0 !important;
}

.vg-dialog button {
    appearance: none;
    -webkit-appearance: none;
    border: 0;
    margin: 0;
    padding: 0;
    font: inherit;
    cursor: pointer;
    background: transparent;
}

.vg-dialog-backdrop {
    position: absolute;
    /* v1.7.45 — the backdrop must cover the LARGEST possible
       viewport, including the area the URL bar will expose if/when
       it collapses. Using `inset: 0` alone uses the dialog's own
       box (which is sized to lvh per the rule above) — that's
       correct on browsers that respect lvh. We also explicitly
       extend to lvh for browsers that may misinterpret position
       contexts under transformed ancestors. The result: when the
       user starts scrolling and the URL bar slides up, the
       backdrop is ALREADY painted underneath it — no white strip
       ever flashes between the dimmed layer and the screen edge. */
    inset: 0;
    height: 100%;
    min-height: 100vh;
    min-height: 100lvh;
    background: rgba(15, 23, 42, 0.78);
    backdrop-filter: blur(8px);
    animation: vg-fade 200ms ease-out;
}

@keyframes vg-fade {
    from { opacity: 0; }
    to { opacity: 1; }
}

@keyframes vg-slide-up {
    from { opacity: 0; transform: translateY(20px); }
    to { opacity: 1; transform: translateY(0); }
}

.vg-dialog-panel {
    position: relative;
    background: #ffffff !important;
    color: #0f172a !important;
    border-radius: 16px;
    max-width: 880px;
    width: 100%;
    /* v1.7.45 — Panel constrains itself to the SMALL viewport (svh).
       That's the viewport size when ALL browser chrome is showing
       (URL bar visible, search bar visible, etc.). Using svh
       guarantees the panel — and especially its close button at
       the top — is ALWAYS within the user-visible area. The dialog
       container sits over the LARGE viewport so the dimmed backdrop
       still extends edge-to-edge, but the interactive panel stays
       inside the safe rectangle.

       The user can resize the URL bar by scrolling and the panel's
       close button always stays tappable. */
    max-height: 92vh;
    max-height: 92svh;
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.4);
    animation: vg-slide-up 300ms cubic-bezier(0.4, 0, 0.2, 1);
}

/* Head */
.vg-dialog-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    padding: 20px 24px;
    border-bottom: 1px solid #e5e7eb;
    position: sticky;
    top: 0;
    background: #ffffff;
    z-index: 2;
}

.vg-dialog-title {
    margin: 0 !important;
    padding: 0 !important;
    font-size: 1.125rem;
    font-weight: 600;
    line-height: 1.4;
    color: #0f172a !important;
    letter-spacing: -0.01em;
    flex: 1;
}

.vg-close {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: #f1f5f9 !important;
    color: #0f172a !important;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: 200ms;
    flex-shrink: 0;
}

.vg-close:hover {
    background: #e2e8f0 !important;
    transform: rotate(90deg);
}

.vg-close:focus-visible {
    outline: 2px solid #2563eb;
    outline-offset: 2px;
}

.vg-close svg {
    width: 16px;
    height: 16px;
    display: block;
}

/* Body — stacked: player → controls → side */
.vg-dialog-body {
    display: flex;
    flex-direction: column;
}

/* Player Area */
.vg-player-area {
    background: #000;
    position: relative;
}

.vg-player {
    width: 100%;
    aspect-ratio: 16 / 9;
    background: #000;
}

@supports not (aspect-ratio: 16 / 9) {
    .vg-player {
        padding-bottom: 56.25%;
        height: 0;
        position: relative;
    }
    .vg-player > * { position: absolute; inset: 0; }
}

.vg-player iframe,
.vg-player video {
    width: 100%;
    height: 100%;
    border: 0;
    display: block;
}

.vg-player[hidden] { display: none !important; }

/* Audio-only mode — replaces player */
.vg-audio-only {
    position: relative;
    width: 100%;
    aspect-ratio: 16 / 9;
    background: linear-gradient(135deg, #1e293b 0%, #0f172a 100%);
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 48px 32px;
    gap: 24px;
    color: #fff;
    overflow: hidden;
    isolation: isolate;
}

.vg-audio-only[hidden] { display: none !important; }

/* Dark overlay over poster image for legibility */
.vg-audio-only--has-poster::before {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(135deg, rgba(15, 23, 42, 0.82) 0%, rgba(15, 23, 42, 0.92) 100%);
    z-index: 1;
}

/* All audio-only children sit above the overlay */
.vg-audio-only > * {
    position: relative;
    z-index: 2;
}

.vg-audio-art {
    display: flex;
    gap: 5px;
    align-items: flex-end;
    height: 56px;
    padding: 0 8px;
}

.vg-audio-art span {
    width: 6px;
    background: #60a5fa;
    border-radius: 3px;
    animation: vg-pulse 1.2s ease-in-out infinite;
}

.vg-audio-art span:nth-child(1) { height: 30%; animation-delay: 0s; }
.vg-audio-art span:nth-child(2) { height: 80%; animation-delay: 0.15s; }
.vg-audio-art span:nth-child(3) { height: 50%; animation-delay: 0.3s; }
.vg-audio-art span:nth-child(4) { height: 100%; animation-delay: 0.45s; }
.vg-audio-art span:nth-child(5) { height: 60%; animation-delay: 0.6s; }

@keyframes vg-pulse {
    0%, 100% { transform: scaleY(0.4); }
    50% { transform: scaleY(1); }
}

.vg-audio-label {
    font-size: 0.8125rem;
    font-weight: 600;
    color: #cbd5e1;
    margin: 0 !important;
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

.vg-audio-only audio {
    width: 100%;
    max-width: 480px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.95);
    padding: 4px 0;
}

/* Controls Bar — sits below player */
.vg-controls {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    padding: 16px 24px;
    background: #f8fafc;
    border-bottom: 1px solid #e5e7eb;
}

.vg-action {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 10px 24px;
    background: #ffffff !important;
    border: 1px solid #e2e8f0 !important;
    border-radius: 8px;
    font-size: 0.8125rem;
    font-weight: 500;
    color: #334155 !important;
    transition: 200ms;
    line-height: 1;
}

.vg-action:hover {
    background: #f1f5f9 !important;
    border-color: #cbd5e1 !important;
    color: #0f172a !important;
}

.vg-action[aria-pressed="true"],
.vg-action[aria-expanded="true"] {
    background: #2563eb !important;
    border-color: #2563eb !important;
    color: #ffffff !important;
}

.vg-action[aria-pressed="true"] svg path,
.vg-action[aria-expanded="true"] svg path {
    fill: #ffffff !important;
}

.vg-action:focus-visible {
    outline: 2px solid #2563eb;
    outline-offset: 2px;
}

.vg-action svg {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
}

/* Side — description and accessibility content */
.vg-side {
    padding: 20px 24px 24px;
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.vg-side:empty,
.vg-side > *:empty:not(.vg-desc) { display: none; }

.vg-side-h {
    margin: 0 !important;
    padding: 0 !important;
    font-size: 0.75rem;
    font-weight: 600;
    color: #64748b;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.vg-desc {
    color: #334155;
    line-height: 1.65;
    font-size: 0.9375rem;
}

.vg-desc:empty { display: none; }

/* Audio description section */
.vg-ad-section {
    background: #eff6ff;
    border-left: 3px solid #2563eb;
    padding: 14px 18px;
    border-radius: 0 8px 8px 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.vg-ad-section[hidden] { display: none !important; }

.vg-ad-section .vg-side-h { color: #1e40af; }

.vg-ad-text {
    font-size: 0.875rem;
    line-height: 1.65;
    color: #1e293b;
}

/* Transcript section */
.vg-dialog .vg-transcript {
    background: #f8fafc;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    padding: 14px 18px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.vg-dialog .vg-transcript[hidden] { display: none !important; }

.vg-transcript-text {
    font-size: 0.875rem;
    line-height: 1.7;
    color: #334155;
    max-height: 280px;
    overflow-y: auto;
    white-space: pre-wrap;
}

/* ============================================
   9. ACCESSIBILITY
   ============================================ */
@media (prefers-reduced-motion: reduce) {
    .vg-wrap.vg-wrap *,
    .vg-dialog * {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

@media (prefers-contrast: more) {
    .vg-wrap.vg-wrap {
        --vg-border: #000;
        --vg-border-strong: #000;
    }
    .vg-wrap.vg-wrap .vg-card { border-width: 2px; }
    .vg-dialog-panel { border: 2px solid #000; }
}

/* Mobile dialog */
@media (max-width: 600px) {
    .vg-dialog { padding: 0; }
    .vg-dialog-panel {
        max-width: 100%;
        max-height: 100vh;
        height: 100vh;
        border-radius: 0;
    }
    .vg-controls { padding: 12px 16px; }
    .vg-side { padding: 16px; }
    .vg-dialog-head { padding: 16px; }
    .vg-action span { display: none; } /* Show only icons on tiny screens */
    .vg-action { padding: 8px 10px; }
}

/* ============================================
   10. MOBILE BLEED-OUT HARDENING — v1.7.6
   ============================================
   Mobile is where bleed-out happens worst because:
     1. Single-column grid → cards stack vertically and any height
        miscalculation cascades down the entire stack.
     2. Iframe thumbs (Wistia, Loom previews) load asynchronously and
        the parent column reflows after first paint, so the page's
        next section ends up at the wrong scroll position briefly.
     3. Elementor's mobile-specific CSS often re-applies a min-height
        on columns that desktop overrides don't catch.

   Fix strategy: hard-lock card heights, force every plausible
   ancestor on mobile to `height: auto`, and reserve real space for
   thumbnails BEFORE their content loads. */

@media (max-width: 768px) {

    /* The wrap and ALL its known ancestors must report a real height
       on mobile. `min-height: fit-content` (where supported) makes
       containers grow to fit their actual content even when a theme
       has applied a smaller fixed min-height. */
    .vg-wrap.vg-wrap {
        min-height: -webkit-fit-content !important;
        min-height: -moz-fit-content !important;
        min-height: fit-content !important;
        height: auto !important;
        /* More aggressive bottom padding on mobile — small screens get
           tight margins from themes, so we add 32px of breathing room
           that the next section physically cannot encroach on. */
        padding-bottom: 32px !important;
        margin-bottom: 32px !important;
    }

    /* Force every Elementor mobile container to honour our height.
       Mobile-specific Elementor classes like `.elementor-mobile-…`
       are also caught by these selectors via inheritance. */
    .elementor-section:has(.vg-wrap),
    .elementor-container:has(.vg-wrap),
    .elementor-row:has(.vg-wrap),
    .elementor-column:has(.vg-wrap),
    .elementor-column-wrap:has(.vg-wrap),
    .elementor-element-populated:has(.vg-wrap),
    .elementor-widget-wrap:has(.vg-wrap),
    .elementor-widget-container:has(.vg-wrap),
    .elementor-widget:has(.vg-wrap),
    .elementor-element:has(.vg-wrap),
    .e-con:has(.vg-wrap),
    .e-con-inner:has(.vg-wrap),
    .e-flex:has(.vg-wrap),
    .e-grid:has(.vg-wrap) {
        height: auto !important;
        min-height: -webkit-fit-content !important;
        min-height: -moz-fit-content !important;
        min-height: fit-content !important;
        max-height: none !important;
        overflow: visible !important;
        /* Cancel mobile-specific transforms / clipping that some themes
           apply via media queries. */
        clip-path: none !important;
        -webkit-clip-path: none !important;
    }

    /* HARD-LOCKED CARD HEIGHTS on mobile.
       Each card must reserve enough space for its thumb (16:9) + title
       (≈48px including padding) BEFORE any image or iframe loads.
       Using min-height in CSS pixels — calculated from a typical
       mobile column width of ~360px → thumb ~202px + title ~48px =
       ~260px minimum. We use `min-height: 260px` as a hard floor.
       The card may grow taller if the title wraps to two lines, but
       it can never shrink below this floor — which means its position
       in the page flow is locked, and the next section can never
       start before the card actually ends. */
    .vg-wrap.vg-wrap .vg-card,
    .vg-wrap.vg-wrap .vg-album-card {
        min-height: 260px !important;
        /* CRITICAL: `contain: none` cancels any inherited containment
           that could break height propagation on mobile. */
        contain: none !important;
    }

    /* The thumb itself must hold its 16:9 ratio with a hard min-height
       floor. If aspect-ratio fails for any reason (very old mobile
       browser, broken polyfill), the min-height keeps the box visible
       and prevents the card from collapsing to just its title. */
    .vg-wrap.vg-wrap .vg-thumb,
    .vg-wrap.vg-wrap .vg-album-cover {
        min-height: 200px !important;
    }

    /* Reserve title space too — a single-line title is ~48px including
       padding. `min-height: 48px` ensures the card always shows the
       title bar even before fonts load (preventing FOUT-related shift). */
    .vg-wrap.vg-wrap .vg-card-title,
    .vg-wrap.vg-wrap .vg-album-meta {
        min-height: 48px !important;
    }

    /* Grid gap is bigger on mobile so neighbouring cards have visible
       breathing room — also acts as a buffer if any single card
       miscalculates by a few pixels. */
    .vg-wrap.vg-wrap .vg-grid,
    .vg-wrap.vg-wrap .vg-albums {
        gap: 20px !important;
        /* Predictable rows */
        grid-auto-rows: max-content !important;
    }
}

/* Very narrow phones — 360px and below. Even more aggressive padding
   so the next section can never visually crash into the last card. */
@media (max-width: 480px) {
    .vg-wrap.vg-wrap {
        padding-bottom: 40px !important;
        margin-bottom: 40px !important;
    }
    .vg-wrap.vg-wrap .vg-card,
    .vg-wrap.vg-wrap .vg-album-card {
        /* Slightly shorter floor on narrow phones to match the smaller
           thumb size, but still enough to be hit-target-friendly. */
        min-height: 230px !important;
    }
    .vg-wrap.vg-wrap .vg-thumb,
    .vg-wrap.vg-wrap .vg-album-cover {
        min-height: 180px !important;
    }
}

/* ============================================
   11. PRELOAD HINTING — pair with width/height
   ============================================
   The shortcode now emits `width="640" height="360"` and
   `fetchpriority="high"` on every thumb image, plus removes
   `loading="lazy"` from images and iframes. Browsers use the
   width/height attribute pair to reserve correct aspect-ratio space
   in CSS pixels BEFORE the image bytes arrive — eliminating layout
   shift, which is the underlying cause of mobile bleed-out.

   These rules complement the HTML attributes by letting the reserved
   space scale fluidly with the column width. */
.vg-wrap.vg-wrap .vg-thumb img,
.vg-wrap.vg-wrap .vg-album-cover img {
    /* width/height attrs in HTML give the browser the intrinsic ratio.
       These CSS rules then size the rendered box to fill the thumb
       container without altering the reserved aspect ratio. */
    width: 100% !important;
    height: 100% !important;
    max-width: 100%;
    object-fit: cover;
}

.vg-wrap.vg-wrap .vg-thumb iframe,
.vg-wrap.vg-wrap .vg-thumb video {
    width: 100% !important;
    height: 100% !important;
    max-width: 100%;
}

/* ============================================
   12. EDITOR / PREVIEW FRIENDLINESS — v1.7.7
   ============================================
   Make the plugin render correctly inside the Elementor editor iframe,
   the Gutenberg block editor, and the WordPress preview iframe. These
   environments inject their own CSS and JS that fight with our layout.

   Three goals here:
     1. Force the grid to actually render as a grid (editors sometimes
        downgrade `display: grid` to block via author CSS resets).
     2. Hide the dialog/modal completely — it should never appear in
        the editor canvas, even if its `[hidden]` attribute is dropped.
     3. Style the empty-state placeholder so it's clearly visible and
        usable in editor mode.
*/

/* Hide the modal dialog in any editor context. The dialog is rendered
   inline alongside each .vg-wrap and is normally `[hidden]`; when an
   editor strips that attribute (rare but happens with some content
   filters), the dialog can paint over the canvas. */
body.elementor-editor-active .vg-dialog,
body.elementor-edit-mode .vg-dialog,
.elementor-editor-active .vg-dialog,
html[data-elementor-edit-mode] .vg-dialog,
body.block-editor-page .vg-dialog,
body.wp-admin .vg-dialog,
/* Beaver Builder editor */
body.fl-builder-edit .vg-dialog,
.fl-builder-edit .vg-dialog,
/* Bricks Builder editor */
body.bricks-is-builder .vg-dialog,
html.bricks-is-builder .vg-dialog,
/* Divi Visual Builder */
body.et-fb .vg-dialog,
.et-fb .vg-dialog,
body.et_fb_thumbnail .vg-dialog,
/* Oxygen */
body.ct-builder .vg-dialog,
html.ct-builder .vg-dialog,
/* Breakdance */
body.breakdance-builder .vg-dialog,
.breakdance-doc .vg-dialog,
/* Cwicly */
body.cwicly-builder .vg-dialog,
/* WPBakery / Visual Composer */
body.vc_editor .vg-dialog,
body.vc_inline_editor .vg-dialog,
.vc_editor .vg-dialog,
/* Brizy */
body.brz-ed .vg-dialog,
.brz-ed .vg-dialog,
/* Thrive */
body.tve_editor_page .vg-dialog,
body.tcb-edit .vg-dialog,
/* Avia */
body.avia_layout_builder .vg-dialog,
/* SiteOrigin */
body.so-panels-default-disabled .vg-dialog,
.siteorigin-panels-builder .vg-dialog,
/* Live Composer */
body.dslc-edit-mode-active .vg-dialog,
.dslc-editing-section .vg-dialog,
/* Themify */
body.themify-builder-active .vg-dialog,
.themify-builder-mode .vg-dialog {
    display: none !important;
    visibility: hidden !important;
    pointer-events: none !important;
}

/* Force grid layout in editor mode. Some editor themes apply
   `display: block` resets to grid containers, breaking the layout. */
body.elementor-editor-active .vg-wrap.vg-wrap .vg-grid,
body.elementor-edit-mode .vg-wrap.vg-wrap .vg-grid,
.elementor-element-edit-mode .vg-wrap.vg-wrap .vg-grid,
.elementor-element-editable .vg-wrap.vg-wrap .vg-grid,
body.block-editor-page .vg-wrap.vg-wrap .vg-grid,
body.fl-builder-edit .vg-wrap.vg-wrap .vg-grid,
body.bricks-is-builder .vg-wrap.vg-wrap .vg-grid,
body.et-fb .vg-wrap.vg-wrap .vg-grid,
body.ct-builder .vg-wrap.vg-wrap .vg-grid,
body.breakdance-builder .vg-wrap.vg-wrap .vg-grid,
body.cwicly-builder .vg-wrap.vg-wrap .vg-grid,
body.vc_editor .vg-wrap.vg-wrap .vg-grid,
body.brz-ed .vg-wrap.vg-wrap .vg-grid,
body.tve_editor_page .vg-wrap.vg-wrap .vg-grid,
body.tcb-edit .vg-wrap.vg-wrap .vg-grid,
body.avia_layout_builder .vg-wrap.vg-wrap .vg-grid,
body.themify-builder-active .vg-wrap.vg-wrap .vg-grid,
body.dslc-edit-mode-active .vg-wrap.vg-wrap .vg-grid,
body.elementor-editor-active .vg-wrap.vg-wrap .vg-albums,
body.elementor-edit-mode .vg-wrap.vg-wrap .vg-albums,
.elementor-element-edit-mode .vg-wrap.vg-wrap .vg-albums,
body.block-editor-page .vg-wrap.vg-wrap .vg-albums,
body.fl-builder-edit .vg-wrap.vg-wrap .vg-albums,
body.bricks-is-builder .vg-wrap.vg-wrap .vg-albums,
body.et-fb .vg-wrap.vg-wrap .vg-albums,
body.ct-builder .vg-wrap.vg-wrap .vg-albums,
body.breakdance-builder .vg-wrap.vg-wrap .vg-albums,
body.cwicly-builder .vg-wrap.vg-wrap .vg-albums,
body.vc_editor .vg-wrap.vg-wrap .vg-albums,
body.brz-ed .vg-wrap.vg-wrap .vg-albums,
body.tve_editor_page .vg-wrap.vg-wrap .vg-albums,
body.tcb-edit .vg-wrap.vg-wrap .vg-albums,
body.avia_layout_builder .vg-wrap.vg-wrap .vg-albums,
body.themify-builder-active .vg-wrap.vg-wrap .vg-albums,
body.dslc-edit-mode-active .vg-wrap.vg-wrap .vg-albums {
    display: grid !important;
    grid-template-columns: repeat(var(--vg-cols, 3), minmax(0, 1fr)) !important;
    grid-auto-rows: max-content !important;
    gap: 24px !important;
}

/* Editor responsive previews — when the editor's Tablet/Mobile preview
   shrinks the canvas, our grid still respects the per-instance tablet
   and mobile column counts via the same --vg-cols-tablet/-mobile vars. */
@media (max-width: 900px) {
    body.elementor-editor-active .vg-wrap.vg-wrap .vg-grid,
    body.elementor-edit-mode .vg-wrap.vg-wrap .vg-grid,
    .elementor-element-edit-mode .vg-wrap.vg-wrap .vg-grid,
    body.block-editor-page .vg-wrap.vg-wrap .vg-grid,
    body.fl-builder-edit .vg-wrap.vg-wrap .vg-grid,
    body.bricks-is-builder .vg-wrap.vg-wrap .vg-grid,
    body.et-fb .vg-wrap.vg-wrap .vg-grid,
    body.ct-builder .vg-wrap.vg-wrap .vg-grid,
    body.breakdance-builder .vg-wrap.vg-wrap .vg-grid,
    body.cwicly-builder .vg-wrap.vg-wrap .vg-grid,
    body.elementor-editor-active .vg-wrap.vg-wrap .vg-albums,
    body.fl-builder-edit .vg-wrap.vg-wrap .vg-albums,
    body.bricks-is-builder .vg-wrap.vg-wrap .vg-albums,
    body.et-fb .vg-wrap.vg-wrap .vg-albums,
    body.ct-builder .vg-wrap.vg-wrap .vg-albums,
    body.breakdance-builder .vg-wrap.vg-wrap .vg-albums,
    body.cwicly-builder .vg-wrap.vg-wrap .vg-albums {
        grid-template-columns: repeat(var(--vg-cols-tablet, 2), minmax(0, 1fr)) !important;
    }
}
@media (max-width: 560px) {
    body.elementor-editor-active .vg-wrap.vg-wrap .vg-grid,
    body.elementor-edit-mode .vg-wrap.vg-wrap .vg-grid,
    .elementor-element-edit-mode .vg-wrap.vg-wrap .vg-grid,
    body.block-editor-page .vg-wrap.vg-wrap .vg-grid,
    body.fl-builder-edit .vg-wrap.vg-wrap .vg-grid,
    body.bricks-is-builder .vg-wrap.vg-wrap .vg-grid,
    body.et-fb .vg-wrap.vg-wrap .vg-grid,
    body.ct-builder .vg-wrap.vg-wrap .vg-grid,
    body.breakdance-builder .vg-wrap.vg-wrap .vg-grid,
    body.cwicly-builder .vg-wrap.vg-wrap .vg-grid,
    body.elementor-editor-active .vg-wrap.vg-wrap .vg-albums,
    body.fl-builder-edit .vg-wrap.vg-wrap .vg-albums,
    body.bricks-is-builder .vg-wrap.vg-wrap .vg-albums,
    body.et-fb .vg-wrap.vg-wrap .vg-albums,
    body.ct-builder .vg-wrap.vg-wrap .vg-albums,
    body.breakdance-builder .vg-wrap.vg-wrap .vg-albums,
    body.cwicly-builder .vg-wrap.vg-wrap .vg-albums {
        grid-template-columns: repeat(var(--vg-cols-mobile, 1), minmax(0, 1fr)) !important;
    }
}

/* In the editor, disable hover transforms — they cause widgets to
   "jump" while the user is trying to click them in the canvas. */
body.elementor-editor-active .vg-wrap.vg-wrap .vg-card:hover,
body.elementor-edit-mode .vg-wrap.vg-wrap .vg-card:hover,
.elementor-element-edit-mode .vg-wrap.vg-wrap .vg-card:hover,
body.block-editor-page .vg-wrap.vg-wrap .vg-card:hover,
body.fl-builder-edit .vg-wrap.vg-wrap .vg-card:hover,
body.bricks-is-builder .vg-wrap.vg-wrap .vg-card:hover,
body.et-fb .vg-wrap.vg-wrap .vg-card:hover,
body.ct-builder .vg-wrap.vg-wrap .vg-card:hover,
body.breakdance-builder .vg-wrap.vg-wrap .vg-card:hover,
body.cwicly-builder .vg-wrap.vg-wrap .vg-card:hover,
body.vc_editor .vg-wrap.vg-wrap .vg-card:hover,
body.brz-ed .vg-wrap.vg-wrap .vg-card:hover,
body.tve_editor_page .vg-wrap.vg-wrap .vg-card:hover,
body.tcb-edit .vg-wrap.vg-wrap .vg-card:hover,
body.avia_layout_builder .vg-wrap.vg-wrap .vg-card:hover,
body.themify-builder-active .vg-wrap.vg-wrap .vg-card:hover,
body.dslc-edit-mode-active .vg-wrap.vg-wrap .vg-card:hover {
    transform: none !important;
    box-shadow: none !important;
}

/* Editor card-trigger should still be clickable for previewing, but
   not steal focus from the editor's own UI controls. */
body.elementor-editor-active .vg-wrap.vg-wrap .vg-card-trigger,
body.elementor-edit-mode .vg-wrap.vg-wrap .vg-card-trigger,
.elementor-element-edit-mode .vg-wrap.vg-wrap .vg-card-trigger,
body.fl-builder-edit .vg-wrap.vg-wrap .vg-card-trigger,
body.bricks-is-builder .vg-wrap.vg-wrap .vg-card-trigger,
body.et-fb .vg-wrap.vg-wrap .vg-card-trigger,
body.ct-builder .vg-wrap.vg-wrap .vg-card-trigger,
body.breakdance-builder .vg-wrap.vg-wrap .vg-card-trigger,
body.cwicly-builder .vg-wrap.vg-wrap .vg-card-trigger,
body.vc_editor .vg-wrap.vg-wrap .vg-card-trigger,
body.brz-ed .vg-wrap.vg-wrap .vg-card-trigger,
body.tve_editor_page .vg-wrap.vg-wrap .vg-card-trigger,
body.tcb-edit .vg-wrap.vg-wrap .vg-card-trigger,
body.avia_layout_builder .vg-wrap.vg-wrap .vg-card-trigger,
body.themify-builder-active .vg-wrap.vg-wrap .vg-card-trigger,
body.dslc-edit-mode-active .vg-wrap.vg-wrap .vg-card-trigger {
    pointer-events: none;
}

/* Force wrap to be width:100% in any editor — widgets sometimes
   shrink-fit their content, making the grid render at minimum width. */
body.elementor-editor-active .vg-wrap.vg-wrap,
body.elementor-edit-mode .vg-wrap.vg-wrap,
.elementor-element-edit-mode .vg-wrap.vg-wrap,
body.block-editor-page .vg-wrap.vg-wrap,
body.fl-builder-edit .vg-wrap.vg-wrap,
body.bricks-is-builder .vg-wrap.vg-wrap,
body.et-fb .vg-wrap.vg-wrap,
body.ct-builder .vg-wrap.vg-wrap,
body.breakdance-builder .vg-wrap.vg-wrap,
body.cwicly-builder .vg-wrap.vg-wrap,
body.vc_editor .vg-wrap.vg-wrap,
body.brz-ed .vg-wrap.vg-wrap,
body.tve_editor_page .vg-wrap.vg-wrap,
body.tcb-edit .vg-wrap.vg-wrap,
body.avia_layout_builder .vg-wrap.vg-wrap,
body.themify-builder-active .vg-wrap.vg-wrap,
body.dslc-edit-mode-active .vg-wrap.vg-wrap {
    width: 100% !important;
    min-width: 0 !important;
    max-width: 100% !important;
    box-sizing: border-box !important;
}

/* ============================================
   12b. EMPTY-STATE PLACEHOLDER (editor only)
   ============================================
   Friendly card shown in the editor when the gallery has no videos
   yet. Keeps editors oriented instead of staring at blank space and
   wondering why the widget isn't working. */

.vg-wrap--placeholder {
    width: 100%;
    margin: 0 0 24px 0;
    padding: 0;
}

.vg-placeholder-card {
    box-sizing: border-box;
    width: 100%;
    max-width: 480px;
    margin: 0 auto;
    padding: 32px 24px;
    background: linear-gradient(135deg, #f8fafc 0%, #eff6ff 100%);
    border: 2px dashed #cbd5e1;
    border-radius: 12px;
    text-align: center;
    color: #0f172a;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
}

.vg-placeholder-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 64px;
    height: 64px;
    margin: 0 auto 12px;
    background: #ffffff;
    border-radius: 50%;
    color: #2563eb;
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.06);
}

.vg-placeholder-title {
    font-size: 1.125rem;
    font-weight: 600;
    color: #0f172a;
    margin-bottom: 4px;
}

.vg-placeholder-msg {
    font-size: 0.875rem;
    color: #475569;
    margin-bottom: 16px;
    line-height: 1.5;
}

.vg-placeholder-cta {
    display: inline-block;
    padding: 8px 20px;
    background: #2563eb;
    color: #ffffff !important;
    text-decoration: none !important;
    border-radius: 999px;
    font-size: 0.8125rem;
    font-weight: 500;
    transition: background 200ms;
}

.vg-placeholder-cta:hover,
.vg-placeholder-cta:focus {
    background: #1d4ed8;
    color: #ffffff !important;
}

/* The plain front-end empty notice (when not in editor). */
.vg-empty {
    padding: 24px;
    margin: 0 0 24px 0;
    background: #f8fafc;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    color: #475569;
    font-size: 0.875rem;
    text-align: center;
}

/* ============================================
   13. SKINS — v1.7.11
   ============================================
   Per-album visual variants. The wrap gets a `.vg-skin-{name}` class
   from the shortcode/admin selector, and these rules apply on top of
   the default skin.
*/

/* --- DEFAULT skin: no overrides; the base styles are the default. */

/* --- CUBE skin: single big card per row, dramatic shadow, larger
   play button, gradient overlay on hover. Best for hero galleries. */
.vg-wrap.vg-skin-cube .vg-grid {
    grid-template-columns: 1fr !important;
    max-width: 980px;
    margin: 0 auto;
    gap: 32px;
}
@media (min-width: 901px) {
    .vg-wrap.vg-skin-cube .vg-grid { gap: 32px; }
    .vg-wrap.vg-skin-cube .vg-card { box-shadow: 0 20px 50px rgba(15, 23, 42, 0.18); }
}
.vg-wrap.vg-skin-cube .vg-card {
    border-radius: 20px;
    border: 0;
}
.vg-wrap.vg-skin-cube .vg-thumb { border-radius: 20px 20px 0 0; }
.vg-wrap.vg-skin-cube .vg-card-title {
    padding: 20px 28px 24px;
    font-size: 1.125rem;
    background: linear-gradient(180deg, #ffffff 0%, #f8fafc 100%);
}
.vg-wrap.vg-skin-cube .vg-play svg { width: 80px; height: 80px; }
.vg-wrap.vg-skin-cube .vg-card:hover {
    transform: translateY(-6px) scale(1.01);
    box-shadow: 0 30px 70px rgba(15, 23, 42, 0.28);
}

/* --- CAROUSEL skin: single-column-feel with side-peek cards. Best
   used inside view="slider" but also styled for grid mode. */
.vg-wrap.vg-skin-carousel .vg-grid {
    grid-template-columns: 1fr !important;
    max-width: 720px;
    margin: 0 auto;
    gap: 16px;
}
.vg-wrap.vg-skin-carousel .vg-card {
    border-radius: 16px;
    box-shadow: 0 12px 32px rgba(15, 23, 42, 0.10);
}
.vg-wrap.vg-skin-carousel .vg-card:hover { transform: scale(1.02); }
.vg-wrap.vg-skin-carousel .vg-thumb { border-radius: 16px 16px 0 0; }
.vg-wrap.vg-skin-carousel .vg-card-title {
    padding: 18px 22px 22px;
    font-size: 1rem;
    text-align: center;
}
.vg-wrap.vg-skin-carousel .vg-play svg { width: 72px; height: 72px; }

/* --- MINIMAL skin: compact tiles, no shadow, no hover lift, smaller
   gaps. Fastest, lightest. */
.vg-wrap.vg-skin-minimal .vg-grid {
    gap: 12px !important;
}
.vg-wrap.vg-skin-minimal .vg-card {
    border-radius: 4px;
    border: 1px solid #e5e7eb;
    box-shadow: none !important;
}
.vg-wrap.vg-skin-minimal .vg-card:hover {
    transform: none;
    box-shadow: none !important;
    border-color: #2563eb;
}
.vg-wrap.vg-skin-minimal .vg-thumb { border-radius: 4px 4px 0 0; }
.vg-wrap.vg-skin-minimal .vg-card-title {
    padding: 8px 10px 10px;
    font-size: 0.8125rem;
    font-weight: 500;
}
.vg-wrap.vg-skin-minimal .vg-play svg { width: 40px; height: 40px; opacity: 0.85; }
.vg-wrap.vg-skin-minimal .vg-duration { font-size: 0.6875rem; padding: 2px 6px; }

/* Hide UI elements when their data-show-* is "0". */
.vg-wrap[data-show-arrows="0"] .vg-arrow { display: none !important; }
.vg-wrap[data-show-dots="0"]   .vg-dots  { display: none !important; }
.vg-wrap[data-show-title="0"]  .vg-card-title { display: none !important; }
.vg-wrap[data-show-duration="0"] .vg-duration { display: none !important; }

/* ============================================
   Slider-context card tweak — v1.7.23
   ============================================
   In a slider the cards are large and visually float on the page —
   a 1px border looks fussy and clashes with the rounded thumbnail
   inside. Drop the border in slider context and add a subtle drop
   shadow at the bottom so the card still has weight on a light page
   background. Grid-view cards are unaffected: the border still helps
   separate adjacent tiles in a tight grid.

   Hover keeps the existing larger lift (--vg-shadow-lg) so the user
   still gets feedback when pointing at a slide. */
.vg-wrap.vg-wrap .vg-slider .vg-card {
    border: 0 !important;
    box-shadow: 0 8px 24px -6px rgba(15, 23, 42, 0.15),
                0 4px 8px  -2px rgba(15, 23, 42, 0.06);
}
.vg-wrap.vg-wrap .vg-slider .vg-card:hover {
    box-shadow: 0 18px 36px -8px rgba(15, 23, 42, 0.22),
                0 6px 12px  -3px rgba(15, 23, 42, 0.10);
}

/* ============================================
   Layout stability — v1.7.37 (clean rewrite)
   ============================================
   Lessons from v1.7.26 → v1.7.36:
     - `contain: paint` and `overflow: clip` look like they should
       isolate paint, but on iOS Safari / mobile WebKit they promote
       the element to a compositor layer and that layer occasionally
       renders with stale positions during scroll, producing the
       overlap the user reported in the screen recording.
     - `content-visibility: auto` causes scroll-time jitter as cells
       flip in and out of layout.
     - `transform: translateZ(0)` does the same.
     - `min-height: <px>` floors paint empty dark bands when titles
       are short.
     - `aspect-ratio + padding-bottom fallback with height:0` collapses
       on Samsung Browser when @supports lies.

   What works reliably across every browser since 2021:
     1. `display: grid` on the parent. Defines the row track heights
        from the natural content of the children.
     2. `display: flex; flex-direction: column` on the card. Stacks
        thumb above title.
     3. `aspect-ratio: 16/9` on .vg-thumb (already in place from
        the main thumb rule earlier in this file). Reserves the
        thumb's height from the column width without measurement.
     4. Pinned 2-line title (already in place earlier).
     5. NO containment, NO clipping, NO compositor promotion, NO
        @supports gates, NO content-visibility — just normal flow.

   The ONE intervention that's still needed: a hard margin between
   adjacent gallery wraps on the same page, because two gallery
   plugins on the same page (file-gallery + Wistia/Wonderplugin
   gallery) need vertical separation that no plugin owns. We add
   it on OUR side because we can. */

/* Card is a flex column. Stacks thumb on top, title below. */
.vg-wrap.vg-wrap .vg-card {
    display: flex;
    flex-direction: column;
    /* contain: layout is safe — only `style` and `paint` are the
       compositor-promotion offenders. `layout` just isolates the
       child's layout from siblings, no compositor side effect. */
    contain: layout;
}

/* Hover lift only on real pointers — touch devices' :hover sticks. */
@media (hover: none), (pointer: coarse) {
    .vg-wrap.vg-wrap .vg-card:hover,
    .vg-wrap.vg-wrap .vg-card:focus,
    .vg-wrap.vg-wrap .vg-card:active {
        transform: none !important;
    }
}

/* Wrap-level layout. The wrap is the outer <section> that contains
   the title heading + grid/slider + sr-live region. Three rules: */
.vg-wrap.vg-wrap {
    /* (a) Establish stacking context so internal z-indexes don't leak
       up to interfere with page-level positioned elements like
       fixed headers and accessibility widgets. */
    position: relative;
    /* (b) Reserve clearance below the last card. Prevents the next
       page section sitting flush against the last card's bottom edge,
       which on tight scrolls reads as overlap.
       v1.7.43 — moved to a `:not(.vg-wrap--single)` selector below
       so single-video wraps have ZERO bottom gap. The clearance
       only matters for galleries (where cards stack and where the
       page section below might be a different plugin). For one
       video sitting in a builder column or grid cell, the cell's
       own padding handles the spacing — the wrap just hugs the
       card. */
    /* Belt-and-suspenders min-height so the wrap is never zero-
       height during first paint. One pixel is enough — actual height
       comes from children. */
    min-height: 1px;
}

/* Bottom clearance — galleries only, not single-video wraps. */
.vg-wrap.vg-wrap:not(.vg-wrap--single) {
    padding-bottom: 32px;
}

/* Wrap-to-wrap separation when two galleries are stacked.
   v1.7.43 — same `:not(--single)` exclusion so a Single Video block
   followed by another widget doesn't get a 32px push-down. */
.vg-wrap.vg-wrap:not(.vg-wrap--single) + .vg-wrap.vg-wrap:not(.vg-wrap--single) {
    margin-top: 32px;
}

/* The .vg-title heading. Its margin gives breathing room above; the
   grid below starts a row gap below. */
.vg-wrap.vg-wrap .vg-title {
    display: block;
    margin: 0 0 16px;
    /* Stacking context so title z-index doesn't compete with the
       gallery below. */
    position: relative;
    z-index: 1;
}

/* The grid. Uses CSS grid; row heights derive from children. */
.vg-wrap.vg-wrap .vg-grid {
    /* min-content min-height ensures the grid container is at least
       as tall as the sum of its row heights, even during transitions.
       Safe — supported everywhere, no compositor side effect. */
    min-height: min-content;
}

/* ============================================
   Pages with stacked plugins — extra vertical guard
   ============================================
   On pages like /video-gallery/ where two video gallery plugins are
   stacked (mine + a Wistia/Wonderplugin gallery below), the next
   plugin's first card sometimes paints with negative-y in mobile
   Safari due to a known iOS WebKit bug with stacked CSS grids that
   contain media elements.

   Workaround: add bottom margin to the LAST CHILD of the wrap so
   there's always positive vertical space between us and whatever
   follows, regardless of what that next thing is.

   v1.7.43 — galleries only. Single-video wraps don't need this
   guard because they're not CSS grids and don't contain stacked
   children — the bug doesn't apply. */
.vg-wrap.vg-wrap:not(.vg-wrap--single) > *:last-child {
    margin-bottom: 16px;
}

/* On mobile (single column), the spacing matters more because each
   card is a full row and there's no horizontal companion to share
   space with. v1.7.43 — same single-mode exemption. */
@media (max-width: 560px) {
    .vg-wrap.vg-wrap:not(.vg-wrap--single) {
        padding-bottom: 48px;
    }
    .vg-wrap.vg-wrap:not(.vg-wrap--single) + .vg-wrap.vg-wrap:not(.vg-wrap--single) {
        margin-top: 48px;
    }
}

/* ============================================
   Single-video wrap — zero outer chrome — v1.7.43
   ============================================
   A standalone video dropped into a builder column should hug its
   card with no plugin-side margins or padding. The builder column
   already provides its own spacing context (Elementor's gap, Bricks's
   container padding, etc.) — adding our own makes the video look
   misaligned in flex/grid layouts. */
.vg-wrap.vg-wrap--single {
    padding: 0;
    margin: 0;
}

/* The single-mode "grid" container is just one card — kill its
   internal grid-gap padding too. */
.vg-wrap.vg-wrap--single .vg-grid {
    margin: 0;
    gap: 0;
    padding: 0;
}

/* The card itself takes its full natural height. No min-height
   floor needed since there's no neighboring card to align to. */
.vg-wrap.vg-wrap--single .vg-card {
    margin: 0;
}

/* v1.7.53 — title is NOT pinned to 2 lines in single mode.
   The 2-line pin (min-height == max-height == ~75px) exists in
   gallery mode so all cards in a row align. There's no row in
   single mode — pinning just reserves dead space below short
   titles. Especially noticeable on mobile where the card is
   full-width (so 1-line titles are common) and the empty 37px
   below the text reads as awkward padding.

   Free the title to take its natural height; preserve the line-clamp
   at 2 (so a runaway 3-line title still clamps). */
.vg-wrap.vg-wrap--single .vg-card-title {
    min-height: 0;
    max-height: none;
    /* Keep the inner padding tight on mobile too. */
    padding: 12px 16px;
}

/* v1.7.53 — also tighten card-body breathing room in single mode.
   Gallery cards have generous internal padding so titles + meta
   read clearly even at small thumbnail sizes. Single-video cards
   are bigger by default (full column width) so the same padding
   ratios feel oversized. Reduce slightly for a more compact feel. */
@media (max-width: 560px) {
    .vg-wrap.vg-wrap--single .vg-card-title {
        padding: 10px 12px;
        font-size: 0.9rem;
    }
}
