/* Small helpers not already covered by Bootstrap utilities. */

.bb-visually-hidden {
    position: absolute !important;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.bb-ratio-product { aspect-ratio: var(--ratio-product); object-fit: cover; }
.bb-ratio-hero { aspect-ratio: var(--ratio-hero-mobile); object-fit: cover; }
@media (min-width: 992px) {
    .bb-ratio-hero { aspect-ratio: var(--ratio-hero-desktop); }
}
.bb-ratio-category { aspect-ratio: var(--ratio-category); object-fit: cover; }

.bb-text-muted { color: var(--color-text-muted); }
.bb-bg-soft { background-color: var(--color-surface-soft); }

/* Scroll-in reveal — modules/scroll-reveal.js toggles .is-visible via
   IntersectionObserver. base.css already forces all transition-durations to
   0.001ms under prefers-reduced-motion, so this degrades to an instant
   appearance with no extra media query needed here. */
.bb-reveal {
    opacity: 0;
    transform: translateY(16px);
    transition: opacity var(--motion-slow) var(--motion-ease), transform var(--motion-slow) var(--motion-ease);
}
.bb-reveal.is-visible {
    opacity: 1;
    transform: none;
}

/* Fade-in-on-load for hero/collection imagery — pair with data-fade-in on
   an <img>; app.js adds .is-loaded once the image's load event fires (or
   immediately if it's already complete, e.g. served from cache). */
img[data-fade-in] {
    opacity: 0;
    transition: opacity var(--motion-slow) var(--motion-ease);
}
img[data-fade-in].is-loaded {
    opacity: 1;
}
