/* ===========================================================================
   Frame strip — shared by the watch page and the admin video-edit page.
   Fixed-px media boxes + sprite-region crops have no Bootstrap equivalent
   (styling.md sanctions custom CSS here). What BOTH pages need lives in this
   sheet (loaded on both): the tile box the sprite crops into, with a fixed
   height that also reserves the row (no layout shift when frame-strip.js fills
   the tiles in), and the LOADING STATE — the per-tile Bootstrap .placeholder
   laid over each tile, the knocked-out logo it carries, its fade on paint, and
   the reduced-motion guard Bootstrap's glow lacks. The scrollbar cosmetics, the
   drag-cursor states and the .scroll-nav pager arrows stay in theme.css, which
   BOTH layouts load: the bar is hidden on both pages, and core/scrollers.js (on
   both layouts too) gives the row its arrows and mouse drag-scrolling instead.
   =========================================================================== */

/* ONE tile height for the whole strip: the tile box, the strip's own box (which
   is the pre-load skeleton) and theme.css's watch-page override all read this,
   so the two sheets cannot disagree about how tall a row is. A tile's WIDTH
   follows from it through the inline aspect-ratio frame-strip.js sets per cue,
   and the sprite crop (SpriteCues.paint) is in percentages of that box, so
   changing this value needs nothing else.
   Below lg the tiles are deliberately shorter (and therefore narrower): a phone
   row is ~360px wide, so a shorter tile is how more of the timeline fits the
   space that exists. */
:root {
    --frame-tile-h: 68px;
}

@media (min-width: 992px) {
    :root {
        --frame-tile-h: 96px;
    }
}

.frame-strip {
    height: var(--frame-tile-h);
}

/* Desktop: grow by ~a scrollbar's height so the tiles keep their size and a
   native scrollbar sits below them (no tile shrink). This is the ADMIN preview's
   box — the watch page has no bar to make room for and takes theme.css's
   tile-height override back. */
@media (min-width: 768px) {
    .frame-strip {
        height: calc(var(--frame-tile-h) + 16px);
    }
}

/* One tile: a button cropping a region of the shared sprite via background
   position/size (set inline, in percentages, by SpriteCues.paint from the cue's
   own #xywh). Its width comes from the inline aspect-ratio against this height.
   Also the scenes gallery's tile (partials/videos/frame-gallery), which overrides
   the fixed height to fill its grid column. */
.frame-tile {
    position: relative;
    flex: 0 0 auto;
    height: var(--frame-tile-h);
    border: 0;
    padding: 0;
    background-color: var(--bs-tertiary-bg);
    background-repeat: no-repeat;
}

/* The loading face over a built-but-unpainted tile: Bootstrap's own .placeholder
   (glowing while the strip carries .placeholder-glow), stretched over the whole
   tile. `inset` is custom because Bootstrap 5.3 has no inset utility, and the
   start-0/end-0 pair would compile MIRRORED in the RTL build inside this
   dir="ltr" island. When frame-strip.js paints the frame it adds .is-painted and
   the placeholder fades out over the crop, then is removed. When the sheet
   FAILS the placeholders are removed outright, so the tile falls back to its own
   flat background above and a failed strip never looks like one still loading. */
.frame-tile > .placeholder {
    position: absolute;
    inset: 0;
    transition: opacity 0.25s ease-out;
}

/* The BABES wordmark centred in every TILE placeholder built by frame-strip.js
   (never the partial's row-wide one), KNOCKED OUT: painted in the
   strip's own surface colour, so it reads as cut out of the pulsing slot and
   pulses with it. Custom because theme.css's .brand-mark sizing is not loaded on
   the admin page, and the size must follow --frame-tile-h rather than a font
   size. Width = height x the #brand-wordmark viewBox ratio (74.99/24).
   Colour enters the <use> shadow tree only by inheritance: `color` feeds the
   letters' fill="currentColor", and --bm-accent the accent "ES" (flattened to the
   same tone, the brand-mark .bm-mono idea). No aria: the placeholder span that
   holds it is aria-hidden. */
.frame-strip-logo {
    --bm-accent: currentColor;
    flex: 0 0 auto;
    height: calc(var(--frame-tile-h) * 0.23);
    width: calc(var(--frame-tile-h) * 0.23 * 74.99 / 24);
    color: var(--bs-tertiary-bg);
}

/* animation:none — .placeholder-glow's keyframes drive opacity, and a running
   animation wins over this declaration, so the fade would never start. */
.frame-tile.is-painted > .placeholder {
    opacity: 0;
    animation: none;
}

/* Bootstrap ships placeholder-glow with NO reduced-motion guard (checked in the
   vendored bootstrap.min.css), so it is added here: a static slot instead of a
   pulse, and the frame replaces it without a fade. frame-strip.js removes the
   placeholder on a timer, since transitionend never fires without a transition.
   Specificity (0,3,0) beats Bootstrap's `.placeholder-glow .placeholder`. */
@media (prefers-reduced-motion: reduce) {
    .frame-strip.placeholder-glow .placeholder,
    .frame-gallery-grid.placeholder-glow .placeholder {
        animation: none;
    }

    .frame-tile > .placeholder {
        transition: none;
    }
}

/* The scenes gallery (partials/videos/frame-gallery): the same .frame-tile, but
   FLUID — it fills its grid column, and its height follows from the inline
   aspect-ratio frame-gallery.js sets per cue, so the strip's fixed height is
   released here. The crop needs nothing: SpriteCues.paint is in percentages. */
.frame-gallery-tile {
    height: auto;
}

/* A tile's corner download button: a fixed SQUARE box, so the button's pill
   radius renders as a circle (Bootstrap has no fixed-size utility — the
   .scroll-nav-arrow precedent in theme.css). */
.frame-gallery-dl {
    width: 32px;
    height: 32px;
}

/* The gallery's loading row before the cues arrive: one tile-high slot. */
.frame-gallery-skeleton {
    height: 8rem;
}

/* The watch page's strip ROW (partials/videos/frame-strip with an `aside`): the
   scrolling wrap shares its line with the Scenes button. min-width:0 lets the
   wrap shrink below its tiles' min-content, which a flex item otherwise refuses
   (Bootstrap has no min-width utility), so the row scrolls instead of pushing
   the button off the page. */
.frame-strip-row > .frame-strip-wrap {
    min-width: 0;
}

/* The Scenes button at the strip's end: a SQUARE exactly one tile high, so the
   house pill radius (ui_btn_class) renders it as a circle — the shape of the
   pager arrows beside it — and it never makes the row taller. Tracks
   --frame-tile-h, so the phone row's shorter tiles shrink it too. */
.frame-strip-scenes {
    width: var(--frame-tile-h);
    height: var(--frame-tile-h);
}
