@charset "UTF-8";
/**
 * Inner Hero Block Styles
 * Three layout options: Split, Text Only, Full Image
 * Uses ARTBID Design Tokens (CSS Variables)
 * Applied to both frontend and editor
 *
 * POSITIONING (AB-42, Chunk 0.5b): vertical + horizontal placement is ONE
 * model for all three layouts — the shared `hero-positioning` mixin, driven by
 * data-valign / data-halign (+ mobile overrides), data-underlap, data-content-fit.
 * There is no per-layout align-items system any more (construction review F1).
 * Layout now only decides where the MEDIA sits relative to the content region.
 */
/**
 * Shared Styles Index
 * Main entry point for all shared styles
 *
 * Usage in block styles:
 * @use '../_shared' as shared;
 *
 * .my-block {
 *   @include shared.block-container();
 * }
 */
/**
 * Token Index
 * Forwards all design tokens
 *
 * Usage in other files:
 * @use '../shared/tokens' as tokens;
 *
 * color: tokens.$color-base-black;
 */
/**
 * Color Tokens
 * Pure CSS variables - no mixins, just values
 * Can be safely imported anywhere
 */
/**
 * Spacing Tokens
 * Pure CSS variables - no mixins, just values
 * Can be safely imported anywhere
 */
/**
 * Typography Tokens
 * Pure CSS variables - no mixins, just values
 * Can be safely imported anywhere
 */
/**
 * Breakpoint Tokens
 * Pure values - no mixins, just variables
 * Can be safely imported anywhere
 */
/**
 * Transition & Animation Tokens
 * Pure CSS variables - no mixins, just values
 * Can be safely imported anywhere
 */
/**
 * Mixins Index
 * Forwards all mixins for use in components
 *
 * Usage:
 * @use '../shared/mixins' as mix;
 *
 * .container { @include mix.container(); }
 * .heading { @include mix.heading-lg(); }
 */
/**
 * Shared Styles Index
 * Main entry point for all shared styles
 *
 * Usage in block styles:
 * @use '../_shared' as shared;
 *
 * .my-block {
 *   @include shared.block-container();
 * }
 */
/**
 * Container Mixins
 * Reusable container patterns
 *
 * Usage:
 * @use '../shared/mixins' as mix;
 * .my-class { @include mix.container(); }
 */
/**
 * Responsive Mixins
 * Media query helpers using modern SASS
 *
 * Usage:
 * @use '../shared/mixins' as mix;
 * @include mix.media-md { ... }
 */
/**
 * Shared Styles Index
 * Main entry point for all shared styles
 *
 * Usage in block styles:
 * @use '../_shared' as shared;
 *
 * .my-block {
 *   @include shared.block-container();
 * }
 */
/**
 * Typography Mixins
 * Reusable text styles
 *
 * Usage:
 * @use '../shared/mixins' as mix;
 * h1 { @include mix.heading-lg(); }
 */
/**
 * Background Mixins
 * Consistent background and text color combinations
 *
 * Usage:
 * @use '../shared/mixins' as mix;
 * .block { @include mix.block-backgrounds('block-name'); }
 */
/**
 * Shared Styles Index
 * Main entry point for all shared styles
 *
 * Usage in block styles:
 * @use '../_shared' as shared;
 *
 * .my-block {
 *   @include shared.block-container();
 * }
 */
/**
 * Height System Mixins
 * Reusable height constraints for images and media blocks
 */
/**
 * Apply height variants for images
 * Works with both cover and contain object-fit modes
 * - Cover mode: Fixed height (crops to fill)
 * - Contain mode: Max height (scales down proportionally)
 *
 * @param {String} $selector - The image selector to apply heights to
 * @param {String} $block-class - The block class for data attributes
 */
/**
 * Apply object-fit modes for images
 *
 * @param {String} $selector - The image selector
 * @param {String} $block-class - The block class for data attributes
 */
/**
 * Apply height variants for block containers (not images)
 * For hero/banner blocks that need full container height control
 *
 * @param {String} $block-class - The block class for data attributes
 */
/**
 * Card-specific height system with aspect-ratio on mobile
 * Hybrid approach: aspect-ratio on mobile, vh-driven on desktop
 *
 * Mobile: Content-aware (aspect ratio) with max-height constraint
 * Desktop: Viewport-driven (vh) with min-height fallback (existing behavior)
 *
 * This solves mobile scroll issues while preserving desktop impact.
 *
 * @param {String} $selector - The image selector to apply heights to
 * @param {String} $block-class - The block class for data attributes
 */
/**
 * Shared Styles Index
 * Main entry point for all shared styles
 *
 * Usage in block styles:
 * @use '../_shared' as shared;
 *
 * .my-block {
 *   @include shared.block-container();
 * }
 */
/**
 * Hero Positioning Mixin (AB-42, Chunk 0.5b)
 * ONE positioning model for all hero layouts. Replaces the three per-layout
 * `align-items` systems (construction review F1) with a single band-relative
 * placement that is header-aware (F4) and content-fit-aware (F3).
 *
 * The model: the "positioning region" is a flex COLUMN with a top safe-zone
 * inset. Content is placed within the band (safe-zone top → region bottom) via
 * `justify-content: safe <valign>`; halign via `align-items`. `safe` means the
 * placement degrades to start (top) when content exceeds the band, so content
 * NEVER overflows upward under a fixed nav. Proven in the harness
 * (blocks/inner-hero/__harness__/probe-safe.mjs): clearance >= 0 for every
 * valign × content-length at an 88px underlap nav.
 *
 * data-* contract (emitted by render.php + edit.js, identical):
 *   data-valign         : start | center | end          (base, all widths)
 *   data-valign-mobile   : "" | start | center | end     ("" = inherit base)
 *   data-halign          : start | center | end          (base)
 *   data-halign-mobile   : "" | start | center | end     ("" = inherit)
 *   data-underlap        : true | false                  (render-computed)
 *   data-content-fit     : flow | clip                   (flow = default)
 *
 * The safe-zone value: JS publishes --header-height (the real nav height); we
 * provide a per-breakpoint CSS fallback so the reserve is correct BEFORE JS runs
 * (architecture §4 option c — no first-paint jump dependent on JS). Only applied
 * when data-underlap="true"; standard pages reserve nav space on <main> already.
 *
 * IMPORTANT: call this at the TOP LEVEL (not nested inside a selector) and pass
 * fully-qualified selector STRINGS — the mixin builds its own rules. `&` does
 * not compose across a root/region split, so we never rely on it here.
 */
/**
 * Apply the positioning model.
 *
 * @param {String} $root   - the block-root selector the data-* attrs live on,
 *                           e.g. '.inner-hero[data-layout="full-image"]'.
 * @param {String} $region - suffix appended to $root to reach the flex-column
 *                           positioning region. '' when the region IS the root
 *                           (full-image / text-only); ' .child' when it's a
 *                           descendant (split's content side). Include the
 *                           leading space for a descendant.
 */
/**
 * Shared Styles Index
 * Main entry point for all shared styles
 *
 * Usage in block styles:
 * @use '../_shared' as shared;
 *
 * .my-block {
 *   @include shared.block-container();
 * }
 */
/**
 * Alignment Mixins
 * Reusable alignment patterns for images and media blocks
 */
/**
 * Apply image alignment within containers
 *
 * @param {String} $figure-selector - The figure/wrapper selector
 * @param {String} $block-class - The block class for data attributes
 * @param {Boolean} $include-container - Whether to include container alignment
 */
/**
 * Apply caption alignment based on image alignment
 *
 * @param {String} $caption-selector - The caption selector
 * @param {String} $block-class - The block class for data attributes
 */
/**
 * Apply vertical alignment for grid containers
 * Used for multi-image layouts (double, triple)
 *
 * @param {String} $container-selector - The grid container selector
 * @param {String} $block-class - The block class for data attributes
 */
/**
 * Shared Styles Index
 * Main entry point for all shared styles
 *
 * Usage in block styles:
 * @use '../_shared' as shared;
 *
 * .my-block {
 *   @include shared.block-container();
 * }
 */
/**
 * Grid Split Ratio Mixins
 * Reusable grid column layouts for multi-column blocks
 *
 * Usage:
 * @use '../shared/mixins' as mix;
 *
 * .my-block {
 *   @include mix.grid-split-two('.my-block-inner');
 * }
 */
/**
 * Two-column split ratio layouts
 * Supports: 50-50, 60-40, 40-60, 70-30, 30-70
 *
 * @param {String} $inner-selector - The grid container selector (e.g., '.inner', '.grid')
 * @param {String} $block-class - Optional block class for scoping
 */
/**
 * Two-column split ratios for edge-to-edge layouts
 * Uses fr units instead of column spans (simpler for edge-to-edge)
 *
 * @param {String} $inner-selector - The grid container selector
 * @param {String} $block-class - Optional block class for scoping
 */
/**
 * Three-column split ratio layouts
 * Supports: 33-33-33, 25-25-50, 50-25-25
 *
 * @param {String} $inner-selector - The grid container selector
 * @param {String} $block-class - Optional block class for scoping
 */
/**
 * Three-column split ratios for edge-to-edge layouts
 *
 * @param {String} $inner-selector - The grid container selector
 * @param {String} $block-class - Optional block class for scoping
 */
/**
 * Shared Styles Index
 * Main entry point for all shared styles
 *
 * Usage in block styles:
 * @use '../_shared' as shared;
 *
 * .my-block {
 *   @include shared.block-container();
 * }
 */
/**
 * Flexbox Split Layout Mixins
 * Reusable flexbox layouts for side-by-side blocks
 *
 * Handles common flexbox split pattern:
 * - Mobile: column layout (stacked)
 * - Desktop: row layout (side-by-side)
 * - Prevents overflow bugs from width: 100% + flex-basis conflicts
 *
 * Usage:
 * @use '../shared/mixins' as mix;
 *
 * .my-block {
 *   @include mix.flex-split-container();
 * }
 * .my-block-child {
 *   @include mix.flex-split-child();
 * }
 */
/**
 * Flexbox split container
 * Use on parent element that contains split children
 *
 * @param {String} $gap-mobile - Gap between items on mobile (default: 0)
 * @param {String} $gap-desktop - Gap between items on desktop (default: 0)
 */
/**
 * Flexbox split child
 * Use on child elements within a flex split container
 * Prevents overflow by only applying width: 100% on mobile
 *
 * IMPORTANT: This prevents the common bug where width: 100% + flex-basis
 * causes horizontal overflow in flexbox row layouts
 */
/**
 * Flexbox split ratios
 * Use on children to control their width in desktop split layout
 *
 * @param {String} $ratio - Split ratio (50-50, 40-60, 60-40)
 * @param {String} $position - Which child this is (left, right, first, second)
 */
/**
 * Flexbox split with data attribute support
 * Generates split ratios based on data-split attribute
 * Use this on the container when you want data-attribute control
 *
 * @param {String} $child-selector - The child element selector
 * @param {String} $block-class - Optional block class for scoping
 */
/**
 * Shared Styles Index
 * Main entry point for all shared styles
 *
 * Usage in block styles:
 * @use '../_shared' as shared;
 *
 * .my-block {
 *   @include shared.block-container();
 * }
 */
/**
 * Overlay System Mixins
 * Reusable overlay patterns for darkening/lightening images and media
 */
/**
 * Apply image overlay with opacity levels
 * Creates a dark overlay element that sits on top of images
 *
 * @param {String} $overlay-class - The overlay element class name (e.g., 'inner-hero-overlay')
 * @param {String} $block-class - The block class for data attributes (null uses &)
 */
/**
 * Shared Styles Index
 * Main entry point for all shared styles
 *
 * Usage in block styles:
 * @use '../_shared' as shared;
 *
 * .my-block {
 *   @include shared.block-container();
 * }
 */
/**
 * Carousel Mixins
 * Reusable patterns for Swiper.js carousel implementations
 *
 * Provides consistent edge padding and overflow control for carousels
 * to ensure first and last slides have proper spacing from viewport edges.
 */
/**
 * Carousel Edge Padding
 * Adds responsive padding to carousel wrapper to match inter-slide spacing.
 * This ensures first and last slides don't touch viewport edges.
 *
 * Usage:
 * .my-block[data-style="slider"] {
 *     @include carousel-edge-padding();
 * }
 */
/**
 * Carousel Edge Padding with Custom Values
 * Allows overriding the default spacing values if needed.
 *
 * @param {string} $mobile-sm - Spacing for mobile 320px (default: $spacing-4)
 * @param {string} $mobile-lg - Spacing for mobile 480px (default: $spacing-5)
 * @param {string} $tablet - Spacing for tablet 768px (default: $spacing-6)
 * @param {string} $desktop - Spacing for desktop 1024px (default: $spacing-8)
 *
 * Usage:
 * .my-special-carousel {
 *     @include carousel-edge-padding-custom($spacing-3, $spacing-4, $spacing-5, $spacing-6);
 * }
 */
/**
 * Shared Styles Index
 * Main entry point for all shared styles
 *
 * Usage in block styles:
 * @use '../_shared' as shared;
 *
 * .my-block {
 *   @include shared.block-container();
 * }
 */
/**
 * Artwork Card Component
 * Ported from ARTBID design system: artist-archive-block
 * Source: /Users/user/Dev/nextjs/artbid-system/src/assets/css/main.css (lines 10120-10195)
 */
/* ============================================
   GRID
   Responsive: 1 → 2 → 3 → 4 columns
   ============================================ */
/* ============================================
   IN-CONTEXT HOVER SWAP (MEDIA-2 ruling): the room shot (rendered only when
   the card opts in with show_context_hover AND the work has one) is a
   full-bleed cover that fades in OVER the letterboxed artwork. No room shot,
   no motion. Current Auction's slider and Artist Artworks share it.
   ============================================ */
/* ============================================
   CARD WRAPPER (LINK)
   Design System: @apply block; @apply focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-black; border-radius: var(--radius-brand);
   ============================================ */
.artwork-card {
  display: block;
  text-decoration: none;
  color: inherit;
  border-radius: 0;
  box-sizing: border-box;
}
.artwork-card:focus-visible {
  outline: var(--spacing-scale-0) 0.5 solid var(--color-base-black);
  outline-offset: var(--spacing-scale-0) 0.5;
}

/* ============================================
   INNER WRAPPER
   Design System: @apply block;
   ============================================ */
.artwork-card-inner {
  display: block;
  box-sizing: border-box;
}

/* ============================================
   IMAGE WRAPPER - Tan Matte Background
   Design System:
     background-color: var(--color-tan);
     @apply relative w-full;
     aspect-ratio: 3/4;
     @apply p-4 md:p-6;
     @apply overflow-hidden;
     @apply flex items-center justify-center;
     border-radius: var(--radius-brand);
     @apply mb-4;
   ============================================ */
.artwork-card-image-wrapper {
  background-color: var(--color-warm-300);
  position: relative;
  width: 100%;
  aspect-ratio: 3/4;
  padding: var(--spacing-scale-4);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 0;
  margin-bottom: var(--spacing-scale-2);
  box-sizing: border-box;
}
@media (min-width: 768px) {
  .artwork-card-image-wrapper {
    padding: var(--spacing-scale-6);
  }
}

/* ============================================
   IMAGE
   Design System: @apply w-full h-full object-contain;
   WordPress: object-fit: contain maintains natural aspect ratio
   ============================================ */
.artwork-card-image {
  position: absolute;
  inset: 0;
  margin: auto;
  max-width: calc(100% - var(--spacing-scale-4) * 2);
  max-height: calc(100% - var(--spacing-scale-4) * 2);
  width: auto;
  height: auto;
  object-fit: contain;
  display: block;
}
@media (min-width: 768px) {
  .artwork-card-image {
    max-width: calc(100% - var(--spacing-scale-6) * 2);
    max-height: calc(100% - var(--spacing-scale-6) * 2);
  }
}

/* ============================================
   IMAGE PLACEHOLDER
   ============================================ */
.artwork-card-image-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-gray-100);
  color: var(--color-gray-400);
}
.artwork-card-image-placeholder svg {
  width: var(--spacing-scale-12);
  height: var(--spacing-scale-12);
}

/* ============================================
   INFO CONTAINER (Flex container for details + badge)
   Design System: @apply flex items-start justify-between gap-4;
   ============================================ */
.artwork-card-info {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--spacing-scale-4);
}

/* ============================================
   DETAILS (Text content area)
   Design System: @apply flex-1;
   ============================================ */
.artwork-card-details {
  flex: 1;
}

/* ============================================
   TITLE
   Design System:
     @apply text-base font-medium mb-1;
     font-style: italic;
   ============================================ */
.artwork-card-title {
  font-size: var(--font-size-base);
  font-weight: var(--font-weight-normal);
  margin-bottom: var(--spacing-scale-1);
  font-style: italic;
  line-height: 1.4;
  color: var(--color-gray-900);
}

/* ============================================
   YEAR (Inline with title)
   ============================================ */
.artwork-card-year {
  font-weight: var(--font-weight-normal);
  font-style: normal;
}

/* ============================================
   ARTIST (for auction context)
   ============================================ */
.artwork-card-artist {
  font-size: var(--font-size-base);
  font-weight: var(--font-weight-normal);
  color: var(--color-gray-700);
  margin-bottom: var(--spacing-scale-1);
  line-height: 1.4;
}

/* ============================================
   META (Year, Medium)
   Design System: @apply text-sm text-gray-600 mb-1;
   ============================================ */
.artwork-card-meta {
  font-size: var(--font-size-sm);
  color: var(--color-gray-600);
  margin-bottom: var(--spacing-scale-1);
  line-height: 1.5;
}

/* ============================================
   DIMENSIONS
   Design System: @apply text-sm text-gray-500;
   ============================================ */
.artwork-card-dimensions {
  font-size: var(--font-size-sm);
  color: var(--color-gray-500);
  margin: 0;
  line-height: 1.5;
}

/* ============================================
   BADGE (Sold badge on the right)
   Artist artworks context: Just bold text "Sold"
   Other contexts: Background box (preserved for backwards compatibility)
   ============================================ */
.artwork-card-badge {
  display: inline-block;
  font-size: var(--font-size-base);
  font-weight: var(--font-weight-bold);
  color: var(--color-gray-900);
  flex-shrink: 0;
  align-self: flex-start;
}
.artwork-card-badge.artwork-card-badge--box {
  padding: var(--spacing-scale-1) var(--spacing-scale-3);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-normal);
  background-color: var(--color-gray-100);
  color: var(--color-gray-700);
  border-radius: 0;
}

/* ============================================
   PRICE
   ============================================ */
.artwork-card-price {
  font-size: var(--font-size-base);
  font-weight: var(--font-weight-bold);
  color: var(--color-gray-900);
  margin-top: var(--spacing-scale-2);
}

/* ============================================
   OVERLAY (for masonry view)
   Default: hidden everywhere except in masonry view
   ============================================ */
.artwork-card-overlay {
  display: none;
}

/* ============================================
   AUCTION CONTEXT VARIANT
   ============================================ */
[data-context=artist] .artwork-card-artist {
  display: none;
}

[data-context=auction] .artwork-card-title {
  font-style: normal;
}

[data-context=auction] .artwork-card-badge {
  display: none;
}

[data-context=auction] .artwork-card-meta,
[data-context=auction] .artwork-card-dimensions {
  display: none;
}

/**
 * Shared Styles Index
 * Main entry point for all shared styles
 *
 * Usage in block styles:
 * @use '../_shared' as shared;
 *
 * .my-block {
 *   @include shared.block-container();
 * }
 */
/**
 * Post Card Component (Journal Card)
 * Converted from: assets/css/journal-archive.css
 * Used by: Latest Posts block, Archive templates, Blog pages
 *
 * Structure:
 * .post-card (or .journal-card) - Article wrapper
 *   .post-card-image - Featured image (4:3 aspect ratio)
 *   .post-card-content - Content wrapper
 *     .post-card-meta - Date + Category
 *       .post-card-date
 *       .post-card-category
 *     .post-card-title - H3 title with display font
 *     .post-card-excerpt - Excerpt text
 *     .post-card-cta - "Read more" link
 */
/* ============================================
   GRID MIXIN
   Responsive: 1 → 2 → 3 columns
   ============================================ */
/* ============================================
   CARD WRAPPER
   ============================================ */
.post-card,
.journal-card {
  display: block;
  overflow: hidden;
  cursor: pointer;
  opacity: 1;
  transition: opacity 0.2s ease-in-out, transform 0.2s ease-out;
}
.post-card a,
.journal-card a {
  position: relative;
  z-index: 1;
}
.post-card:focus-within,
.journal-card:focus-within {
  outline: 2px solid var(--color-base-black);
  outline-offset: var(--spacing-scale-1);
  border-radius: 0;
}
.post-card[style*="display: none"],
.journal-card[style*="display: none"] {
  display: none !important;
}

/* ============================================
   CARD IMAGE
   4:3 aspect ratio with gray background
   ============================================ */
.post-card-image,
.journal-card-image,
.post-card .wp-block-post-featured-image,
.journal-card .wp-block-post-featured-image {
  width: 100%;
  margin-bottom: 0;
  display: block;
  background-color: var(--color-gray-100);
  overflow: hidden;
  position: relative;
  aspect-ratio: 1/1;
  border-radius: 0;
}
.post-card-image img,
.journal-card-image img,
.post-card .wp-block-post-featured-image img,
.journal-card .wp-block-post-featured-image img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  max-width: none;
}

/* ============================================
   CARD CONTENT
   Gap between elements: 0.75rem
   ============================================ */
.post-card-content,
.journal-card-content {
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-scale-3);
  padding-top: var(--spacing-scale-2);
}

/* ============================================
   META: Date & Category
   ============================================ */
.post-card-meta,
.journal-card-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing-scale-4);
  font-size: var(--font-size-xs);
  margin: 0;
}

.post-card-date,
.journal-card-date,
.post-card .wp-block-post-date,
.journal-card .wp-block-post-date {
  color: var(--color-gray-600);
  font-size: var(--font-size-xs);
}

.post-card-category,
.journal-card-category,
.post-card .wp-block-post-terms,
.journal-card .wp-block-post-terms {
  color: var(--color-gray-600);
  text-transform: uppercase;
  letter-spacing: var(--font-letterSpacing-wider);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-normal);
}
.post-card-category a,
.journal-card-category a,
.post-card .wp-block-post-terms a,
.journal-card .wp-block-post-terms a {
  color: inherit;
  text-decoration: none;
}

.post-card .wp-block-post-terms__separator,
.journal-card .wp-block-post-terms__separator {
  display: none;
}

/* ============================================
   TITLE
   Display font, responsive sizing
   ============================================ */
.post-card-title,
.journal-card-title,
.post-card .wp-block-post-title,
.journal-card .wp-block-post-title,
.post-card h3,
.journal-card h3,
.post-card .wp-block-post-title a,
.journal-card .wp-block-post-title a {
  font-family: var(--font-family-display);
  font-size: var(--font-size-xl);
  line-height: var(--font-lineHeight-tight);
  margin: 0;
  color: var(--color-base-black);
  font-weight: var(--font-weight-normal);
}
@media (min-width: 768px) {
  .post-card-title,
  .journal-card-title,
  .post-card .wp-block-post-title,
  .journal-card .wp-block-post-title,
  .post-card h3,
  .journal-card h3,
  .post-card .wp-block-post-title a,
  .journal-card .wp-block-post-title a {
    font-size: var(--font-size-2xl);
  }
}

.post-card-title a,
.journal-card-title a,
.post-card .wp-block-post-title a,
.journal-card .wp-block-post-title a {
  color: inherit;
  text-decoration: none;
  font-family: inherit;
}
.post-card-title a:hover,
.journal-card-title a:hover,
.post-card .wp-block-post-title a:hover,
.journal-card .wp-block-post-title a:hover {
  color: var(--color-gray-700);
}

/* ============================================
   EXCERPT
   Clamped to 3 lines
   ============================================ */
.post-card-excerpt,
.journal-card-excerpt,
.post-card .wp-block-post-excerpt,
.journal-card .wp-block-post-excerpt {
  font-size: var(--font-size-sm);
  line-height: var(--font-lineHeight-relaxed);
  color: var(--color-gray-600);
  margin: 0;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
@media (min-width: 768px) {
  .post-card-excerpt,
  .journal-card-excerpt,
  .post-card .wp-block-post-excerpt,
  .journal-card .wp-block-post-excerpt {
    font-size: var(--font-size-base);
  }
}

.post-card .wp-block-post-excerpt__more-link,
.journal-card .wp-block-post-excerpt__more-link {
  display: none;
}

/* ============================================
   READ MORE CTA
   Underlined link that removes underline on hover
   ============================================ */
.post-card-cta-wrapper,
.journal-card-cta-wrapper {
  margin: 0;
}

.post-card-cta,
.journal-card-cta,
.post-card .wp-block-read-more,
.journal-card .wp-block-read-more {
  display: inline-block;
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-normal);
  color: var(--color-base-black);
  text-decoration: underline;
  transition: text-decoration 0.2s ease-in-out;
}
.post-card-cta:hover,
.journal-card-cta:hover,
.post-card .wp-block-read-more:hover,
.journal-card .wp-block-read-more:hover {
  text-decoration: none;
}

.post-card:hover .post-card-cta,
.journal-card:hover .journal-card-cta,
.post-card:hover .wp-block-read-more,
.journal-card:hover .wp-block-read-more {
  text-decoration: none;
}

/* ============================================
   SCREEN READER TEXT
   For accessible card links
   ============================================ */
.post-card-link,
.journal-card-link {
  clip: rect(1px, 1px, 1px, 1px);
  clip-path: inset(50%);
  height: 1px;
  width: 1px;
  margin: -1px;
  overflow: hidden;
  padding: 0;
  position: absolute;
}

/* ============================================
   JOURNAL CARD — Yael's page notes (2026-10-05; artbid-v2
   design-token-index.md §6 J3 · J7 · J8). This SAME block closes
   blocks/_shared/components/_post-card.scss (the Latest Posts block) and the
   card copy inlined in assets/css/journal-archive.css (G19) — keep the two
   identical until the card has one source.
   ============================================ */
/* J3: the type on the LEFT, the date on the RIGHT (the markup keeps the date
   first; `order` moves the type ahead in the space-between row). */
.post-card-category,
.journal-card-category,
.post-card .wp-block-post-terms,
.journal-card .wp-block-post-terms {
  order: -1;
}

/* J7: the title = --font-size-xl at every width (24 desktop, 20 phone), two
   lines at most. */
/* `.post-card h3` / `.journal-card h3` are listed too: the base rule above
   names them, and a class + a tag outranks the class alone — the block's card
   title stayed on the old 2xl step from 768 up (30.5 at 1440 beside the
   journal's 24) until 2026-10-13. */
.post-card-title,
.journal-card-title,
.post-card h3,
.journal-card h3,
.post-card .wp-block-post-title,
.journal-card .wp-block-post-title {
  font-size: var(--font-size-xl);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}

.post-card .wp-block-post-title a,
.journal-card .wp-block-post-title a {
  font-size: inherit;
  display: inline; /* an inline-block link is one atomic box — the clamp can't cut inside it */
}

/* J7: the excerpt = --font-size-sm at every width, five lines at most. */
.post-card-excerpt,
.journal-card-excerpt,
.post-card .wp-block-post-excerpt,
.journal-card .wp-block-post-excerpt {
  font-size: var(--font-size-sm);
  -webkit-line-clamp: 5;
  line-clamp: 5;
}

/* The card owns its own gaps (the content's flex gap). Inside page content the
   prose rhythm (`.wp-block-post-content h3 + *`) added a paragraph gap under
   the title: 28 where /journal/ has 12. */
.post-card .post-card-content > *,
.journal-card .journal-card-content > * {
  margin-top: 0;
  margin-bottom: 0;
}

/* J8: "Read more" = the main nav's line, exactly (header-footer.css
   .header-nav-link::after): no line at rest; hovering or focusing THE LINK
   draws a 1px currentColor line in from the left, --transition-duration-300
   ease-out; no animation under prefers-reduced-motion. Hovering ANYWHERE on
   the card draws it too — the card is one clickable unit (Chuck 2026-10-05). */
.post-card-cta,
.journal-card-cta,
.post-card .wp-block-read-more,
.journal-card .wp-block-read-more {
  position: relative;
  text-decoration: none;
  /* the line lives INSIDE the link's box (as the nav's does): the card clips
     its overflow and the link is its last element, so a line drawn below the
     box was cut off (Chuck's walk, 2026-10-05). */
  padding-bottom: calc(var(--spacing-scale-0_5) + var(--border-width-1));
  /* shrink to the words: the card content is a flex column that stretches its
     children, so the link (and the line inside it) ran the card's full width
     (Chuck 2026-10-06). */
  align-self: flex-start;
}

.post-card-cta::after,
.journal-card-cta::after,
.post-card .wp-block-read-more::after,
.journal-card .wp-block-read-more::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: var(--border-width-1);
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--transition-duration-300) var(--transition-timing-ease-out);
}

.post-card:hover .post-card-cta::after,
.journal-card:hover .journal-card-cta::after,
.post-card:hover .wp-block-read-more::after,
.journal-card:hover .wp-block-read-more::after,
.post-card-cta:hover::after,
.journal-card-cta:hover::after,
.post-card .wp-block-read-more:hover::after,
.journal-card .wp-block-read-more:hover::after,
.post-card-cta:focus-visible::after,
.journal-card-cta:focus-visible::after,
.post-card .wp-block-read-more:focus-visible::after,
.journal-card .wp-block-read-more:focus-visible::after {
  transform: scaleX(1);
}

@media (prefers-reduced-motion: reduce) {
  .post-card-cta::after,
  .journal-card-cta::after,
  .post-card .wp-block-read-more::after,
  .journal-card .wp-block-read-more::after {
    transition: none;
  }
}
/**
 * Shared Styles Index
 * Main entry point for all shared styles
 *
 * Usage in block styles:
 * @use '../_shared' as shared;
 *
 * .my-block {
 *   @include shared.block-container();
 * }
 */
/**
 * Carousel Component - Shared Swiper.js Carousel Styles
 *
 * Used by: Current Auction slider, Artist slider (future)
 * Based on artbid-system carousel patterns
 *
 * Features:
 * - Variable-width slides on desktop (based on image aspect ratio)
 * - Snap scrolling on mobile for better UX
 * - Universal navigation (dots + arrows)
 * - Light/dark theme support
 */
/* ============================================
   CAROUSEL UNIVERSAL NAVIGATION
   Reusable pagination dots and arrow buttons
   ============================================ */
/* Pagination dots container */
.carousel-pagination {
  display: flex;
  gap: var(--spacing-scale-2);
}

/* Individual pagination bullet (inactive - outline only) */
.carousel-pagination-bullet {
  width: var(--spacing-scale-2);
  height: var(--spacing-scale-2);
  border-radius: 50%;
  transition: all 0.2s;
  cursor: pointer;
  background: transparent;
}

/* Active pagination bullet (filled circle, same size) */
.carousel-pagination-bullet-active {
  /* No size change - stays circular */
}

/* Light theme bullets (for dark backgrounds) */
.carousel-pagination--light .carousel-pagination-bullet {
  border: 1px solid rgba(255, 255, 255, 0.6);
}
.carousel-pagination--light .carousel-pagination-bullet:hover {
  border-color: rgba(255, 255, 255, 0.8);
}

.carousel-pagination--light .carousel-pagination-bullet-active {
  background: var(--color-base-white);
  border-color: var(--color-base-white);
}

/* Dark theme bullets (for light backgrounds) — 1px solid black ring
   (2026-07-18 ruling, matches the app's related-lots dots) */
.carousel-pagination--dark .carousel-pagination-bullet {
  border: 1px solid var(--color-base-black);
}

.carousel-pagination--dark .carousel-pagination-bullet-active {
  background: var(--color-base-black);
  border-color: var(--color-base-black);
}

/* Navigation arrows — bare mitered chevrons, lightbox parity
   (Chuck's ruling 2026-07-18: no circles or boxes anywhere; the glyph
   is the lightbox cut scaled to nav size, 23:41 ratio). The 40px hit
   target stays. Inline <svg> chevrons at every render site are retired
   by CSS (display:none) — direction rides the aria-label
   ("Previous…" / "Next…") every site already carries. Theme variants
   (--dark/--light) now set glyph color only. Mirror of nextjs-system
   main.css @spec-section: carousel-arrows — keep the two in step. */
.carousel-arrow {
  width: var(--spacing-scale-10);
  height: var(--spacing-scale-10);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  background: transparent;
  border: 0;
  border-radius: 0;
  cursor: pointer;
  opacity: 0.6;
  transition: opacity 0.2s;
}
.carousel-arrow:focus-visible {
  outline: 2px solid var(--color-base-black);
  outline-offset: 2px;
}
.carousel-arrow:hover:not(:disabled) {
  opacity: 1;
}
.carousel-arrow:disabled {
  opacity: 0.25;
  cursor: not-allowed;
}
.carousel-arrow svg {
  display: none;
}
.carousel-arrow {
  /* Default glyph = next (right); Previous overrides below */
}
.carousel-arrow::before {
  content: "";
  display: block;
  width: 14px;
  height: 25px;
  background-color: currentColor;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg width='46' height='82' viewBox='0 0 46 82' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0L45.1025 39H32L0 12V0Z' fill='black'/%3E%3Cpath d='M0 82L45.1025 43H32L0 70V82Z' fill='black'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg width='46' height='82' viewBox='0 0 46 82' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0L45.1025 39H32L0 12V0Z' fill='black'/%3E%3Cpath d='M0 82L45.1025 43H32L0 70V82Z' fill='black'/%3E%3C/svg%3E");
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
}
.carousel-arrow[aria-label^=Prev]::before {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg width='46' height='82' viewBox='0 0 46 82' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M45.1025 0L0 39H13.1025L45.1025 12V0Z' fill='black'/%3E%3Cpath d='M45.1025 82L0 43H13.1025L45.1025 70V82Z' fill='black'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg width='46' height='82' viewBox='0 0 46 82' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M45.1025 0L0 39H13.1025L45.1025 12V0Z' fill='black'/%3E%3Cpath d='M45.1025 82L0 43H13.1025L45.1025 70V82Z' fill='black'/%3E%3C/svg%3E");
}

/* Light theme arrows (for dark backgrounds) — glyph color only */
.carousel-arrow--light {
  color: var(--color-base-white);
}

/* Dark theme arrows (for light backgrounds) — glyph color only */
.carousel-arrow--dark {
  color: var(--color-base-black);
}

/* ============================================
   ARTWORK CAROUSEL
   For current auction slider and artist slider
   ============================================ */
.artwork-carousel-heading {
  font-family: var(--font-family-display);
  font-size: var(--font-size-3xl);
  margin-bottom: 0;
}
.artwork-carousel-heading--left {
  text-align: left;
}
.artwork-carousel-heading--center {
  text-align: center;
}
.artwork-carousel-heading--right {
  text-align: right;
}
.artwork-carousel-heading--2xl {
  font-size: var(--font-size-2xl);
}
.artwork-carousel-heading--3xl {
  font-size: var(--font-size-3xl);
}
.artwork-carousel-heading--4xl {
  font-size: var(--font-size-4xl);
}
.artwork-carousel-heading--5xl {
  font-size: var(--font-size-5xl);
}
.artwork-carousel-heading--6xl {
  font-size: var(--font-size-6xl);
}
.artwork-carousel-heading--7xl {
  font-size: var(--font-size-7xl);
}
.artwork-carousel-heading--sm {
  font-size: var(--font-size-3xl);
}
.artwork-carousel-heading--md {
  font-size: var(--font-size-4xl);
}
.artwork-carousel-heading--lg {
  font-size: var(--font-size-5xl);
}
.artwork-carousel-heading--xl {
  font-size: var(--font-size-6xl);
}

/* Subheading under the heading (Yael 2026-09-14, punchlist #13): body-size,
   quieter colour, follows the heading's alignment. */
.artwork-carousel-subheading {
  margin: var(--spacing-scale-2) 0 0;
  font-size: var(--font-size-base);
  color: var(--color-gray-700);
}
.artwork-carousel-subheading--left {
  text-align: left;
}
.artwork-carousel-subheading--center {
  text-align: center;
}
.artwork-carousel-subheading--right {
  text-align: right;
}

.artwork-carousel-wrapper {
  position: relative;
  margin-top: var(--spacing-scale-6);
  margin-bottom: clamp(1.5rem, 1.2rem + 1vw, 2.5rem);
}

.artwork-carousel-swiper {
  overflow: visible;
}

.artwork-carousel-slide {
  height: auto;
  /* Width controlled by Swiper configuration and card content */
}

/* Navigation wrapper: CTA button + dots/arrows */
.artwork-carousel-nav-wrapper {
  position: relative;
  display: flex;
  align-items: center;
  margin-top: var(--spacing-scale-4);
}

/* CTA Button - centered on page */
.artwork-carousel-cta {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
}

/* Navigation container — dots bottom-LEFT, arrows right (Chuck
   2026-07-18: parity with the app's related-lots carousel nav) */
.artwork-carousel-nav {
  display: flex;
  align-items: center;
  gap: var(--spacing-scale-4);
  width: 100%;
}

/* Pagination dots — left edge; arrows push to the right */
.artwork-carousel-pagination,
[class*=artwork-carousel-pagination-] {
  position: static !important;
  width: auto !important;
  flex: 1;
  display: flex !important;
  justify-content: flex-start;
}

/* Arrow buttons - no additional styles needed, inherit from .carousel-arrow--dark */
.artwork-carousel-prev,
.artwork-carousel-next {
  /* Inherits from .carousel-arrow--dark */
}

/* ============================================
   NAV POSITION MODEL (shared, 2026-08-17)
   Show/hide + position for DOTS (left/center/right) and ARROWS (left/right).
   Used by current-auction + artist-slider — both @use this partial.

   WHY GRID: the rules above give .artwork-carousel-pagination
   `position:static !important; flex:1; justify-content:flex-start`. A flex
   auto-margin "centre" only centres within the space LEFT BY the arrows (reads
   off-centre), and a `position:absolute` centre is beaten by `position:static
   !important`. Making .artwork-carousel-nav a GRID sidesteps all of it: a grid
   item ignores `flex:1`, wants `position:static`, and the middle `auto` column
   of `1fr auto 1fr` is TRUE-centred between two equal tracks regardless of the
   arrows' width. Grid placement (grid-column/justify-self) uses properties the
   !important rules never touch, so we need no !important of our own.

   Activated only when .artwork-carousel-nav carries the position data-attrs
   (both carousel blocks emit them); other carousels are unaffected.
   ============================================ */
.artwork-carousel-nav[data-dots-position] {
  display: grid;
  grid-template-columns: 1fr auto 1fr; /* left | centre | right */
  align-items: center;
  gap: var(--spacing-scale-4);
  width: 100%;
  /* DOTS → cell by position. flex:1 is inert on a grid item; the dots stay an
     internal flex row (shared rule), we only place the group. */
}
.artwork-carousel-nav[data-dots-position][data-dots-position=left] .artwork-carousel-pagination {
  grid-column: 1;
  justify-self: start;
}
.artwork-carousel-nav[data-dots-position][data-dots-position=center] .artwork-carousel-pagination {
  grid-column: 2;
  justify-self: center;
}
.artwork-carousel-nav[data-dots-position][data-dots-position=right] .artwork-carousel-pagination {
  grid-column: 3;
  justify-self: end;
}
.artwork-carousel-nav[data-dots-position] {
  /* ARROWS → left or right cell only (no centre). */
}
.artwork-carousel-nav[data-dots-position] .artwork-carousel-nav-arrows {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-scale-2);
}
.artwork-carousel-nav[data-dots-position][data-arrows-position=left] .artwork-carousel-nav-arrows {
  grid-column: 1;
  justify-self: start;
}
.artwork-carousel-nav[data-dots-position][data-arrows-position=right] .artwork-carousel-nav-arrows {
  grid-column: 3;
  justify-self: end;
}

/* ARROWS AT THE SIDES (Chuck 2026-10-29, Artist Slider card) — over the
   far-left and far-right images, at the picture's middle. carousel-init.js
   measures that middle into --sides-top on the nav wrapper (the nav keeps its
   place in the markup, so the dots still centre in the row). Over a photo the
   arrows are the bare white symbol with a soft shadow, as the video bar. From
   md up; phones keep the row (the phone rule below). */
@media (min-width: 768px) {
  .artwork-carousel-nav-wrapper:has(.artwork-carousel-nav[data-arrows-position=sides]) {
    position: relative;
  }
  .artwork-carousel-nav[data-arrows-position=sides] .artwork-carousel-nav-arrows {
    position: absolute;
    left: 0;
    right: 0;
    top: var(--sides-top, 0);
    z-index: 2;
    display: flex;
    justify-content: space-between;
    padding: 0 var(--spacing-scale-2);
    transform: translateY(-50%);
    pointer-events: none;
  }
  .artwork-carousel-nav[data-arrows-position=sides] .artwork-carousel-nav-arrows .carousel-arrow {
    pointer-events: auto;
    color: var(--color-base-white);
    filter: drop-shadow(0 0 var(--spacing-scale-1) color-mix(in srgb, var(--color-base-black) 50%, transparent));
  }
  .artwork-carousel-nav-wrapper:not([style*="--sides-top"]) .artwork-carousel-nav[data-arrows-position=sides] .artwork-carousel-nav-arrows {
    visibility: hidden;
  }
}
/* SHARED ZONE — dots and arrows shown AND at the same position. One justified
   flex row, dots then arrows (source order = the "dots always left of arrows"
   tie-breaker), gap between, never overlapping. Overrides the grid above. */
.artwork-carousel-nav.is-shared-zone {
  display: flex;
  align-items: center;
  gap: var(--spacing-scale-3);
}
.artwork-carousel-nav.is-shared-zone .artwork-carousel-pagination {
  flex: 0 0 auto !important;
}
.artwork-carousel-nav.is-shared-zone[data-dots-position=left] {
  justify-content: flex-start;
}
.artwork-carousel-nav.is-shared-zone[data-dots-position=right] {
  justify-content: flex-end;
}

/* PHONE (<768px, tablets ≥768px unaffected): the nav row can't hold dots +
   arrows + a button on one line, so we FORCE a single sensible layout and stop
   honouring the desktop position choices:
     • nav row is always dots-left / arrows-right (override the grid placement),
     • the button drops to its OWN full-width line BELOW the row.
   `full-width` is scoped to phone only — at tablet+ the button keeps its natural
   content width and the designer's chosen position (the --button-* rules above).
   $breakpoint-md is 768px, so `max-width:767px` is exactly the phone edge. */
@media (max-width: 767px) {
  .artwork-carousel-nav[data-dots-position] {
    gap: var(--spacing-scale-2);
    grid-template-columns: 1fr auto;
  }
  .artwork-carousel-nav[data-dots-position] .artwork-carousel-pagination {
    grid-column: 1 !important;
    justify-self: start !important;
  }
  .artwork-carousel-nav[data-dots-position] .artwork-carousel-nav-arrows {
    grid-column: 2 !important;
    justify-self: end !important;
  }
  .artwork-carousel-nav.is-shared-zone {
    justify-content: flex-start;
  }
  .artwork-carousel-nav-wrapper--with-button {
    flex-direction: column;
    align-items: stretch;
    gap: var(--spacing-scale-3);
  }
  .artwork-carousel-nav-wrapper--with-button .artwork-carousel-nav {
    order: 0;
  }
  .artwork-carousel-nav-wrapper--with-button .artwork-carousel-cta-button,
  .artwork-carousel-nav-wrapper--with-button .artist-slider-button {
    position: static !important;
    left: auto !important;
    transform: none !important;
    order: 1;
    width: 100%;
  }
  .artwork-carousel-nav-wrapper--with-button .artwork-carousel-cta-button .btn,
  .artwork-carousel-nav-wrapper--with-button .artist-slider-button .btn {
    width: 100%;
  }
  .artwork-carousel-nav-wrapper--button-center .artwork-carousel-nav {
    margin-left: 0;
  }
}
/* ============================================
   NAV CTA BUTTON (shared, 2026-08-17)
   An optional button that lives in the nav-wrapper beside the dots/arrows row.
   Ported from artist-slider so current-auction can share it. The wrapper gets
   `--with-button` + `--button-{align}`; the button itself is
   `.artwork-carousel-cta-button` (artist-slider's legacy `.artist-slider-button`
   is aliased below until it migrates). Button visual = the shared `.btn` classes.
   ============================================ */
.artwork-carousel-nav-wrapper--with-button {
  display: flex;
  align-items: center;
  position: relative;
}

.artwork-carousel-cta-button,
.artist-slider-button { /* legacy alias — remove once artist-slider migrates */
  display: inline-flex;
}
.artwork-carousel-cta-button .btn,
.artist-slider-button .btn {
  width: auto;
  white-space: nowrap;
}

/* Left: button left, nav row pushed right. */
.artwork-carousel-nav-wrapper--button-left {
  justify-content: space-between;
}

/* Centre: button absolutely centred, nav row stays right. */
.artwork-carousel-nav-wrapper--button-center .artwork-carousel-cta-button,
.artwork-carousel-nav-wrapper--button-center .artist-slider-button {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
}
.artwork-carousel-nav-wrapper--button-center .artwork-carousel-nav {
  margin-left: auto;
}

/* ============================================
   THE CAROUSEL SHELL (2026-10-06; inc/helpers/carousel-helpers.php,
   artbid-v2 design-token-index.md §6.1 J2)
   "N cells in view". The GAP is a token, set here and nowhere else — the
   script measures it through the probe (no px in JS). Cells per view ride
   on the root as custom properties from the emitter.
   Before Swiper starts (and always in the editor, where it never starts) the
   track lays out the cells with the same geometry; Swiper's own inline
   widths/margins take over once it adds .swiper-initialized.
   The nav reuses the shared dots/arrows/nav-position rules above.
   ============================================ */
.artbid-carousel {
  --artbid-carousel-gap: var(--spacing-scale-4);
  --artbid-carousel-cells: var(--artbid-carousel-cells-phone, 2);
  position: relative;
  min-width: 0;
}
@media (min-width: 768px) {
  .artbid-carousel {
    --artbid-carousel-cells: var(--artbid-carousel-cells-desktop, 3);
  }
}

.artbid-carousel-gap-probe {
  position: absolute;
  left: 0;
  top: 0;
  width: var(--artbid-carousel-gap);
  height: 0;
  visibility: hidden;
  pointer-events: none;
}

.artbid-carousel-track {
  overflow: hidden;
}

.artbid-carousel-track:not(.swiper-initialized) > .swiper-wrapper {
  display: flex;
  gap: var(--artbid-carousel-gap);
}

.artbid-carousel-track:not(.swiper-initialized) .artbid-carousel-slide {
  flex: 0 0 calc((100% - (var(--artbid-carousel-cells) - 1) * var(--artbid-carousel-gap)) / var(--artbid-carousel-cells));
  min-width: 0;
}

.artbid-carousel-slide {
  height: auto;
}

/* Fewer cells than fit in view: nothing to scroll — no dots, no arrows. */
.artbid-carousel.is-locked .artbid-carousel-nav-wrapper {
  display: none;
}

/* Before the script decides, keep the nav's space but hide its controls
   (no flash of arrows on a carousel that turns out to be locked). */
.artbid-carousel:not(.is-ready) .artbid-carousel-nav-wrapper {
  visibility: hidden;
}

/* The shell's 'single' and 'marquee' modes (2026-10-19, the Image Slider).
   'single' lays out like one cell; 'marquee' lets every slide keep its own
   width and moves the wrapper linearly. The pause button (anything that moves
   by itself) is the bare symbol beside the dots, black on the page. */
.artbid-carousel[data-mode=single] {
  --artbid-carousel-cells: 1;
  --artbid-carousel-slide-duration: var(--transition-duration-500);
}
@media (min-width: 768px) {
  .artbid-carousel[data-mode=single] {
    --artbid-carousel-slide-duration: var(--transition-duration-700);
  }
}
.artbid-carousel[data-mode=single] .swiper-wrapper {
  transition-timing-function: var(--transition-timing-ease-in-out);
}
@media (prefers-reduced-motion: reduce) {
  .artbid-carousel[data-mode=single] {
    --artbid-carousel-slide-duration: 0ms;
  }
}

.artbid-carousel[data-mode=marquee] .artbid-carousel-slide,
.artbid-carousel[data-mode=marquee] .artbid-carousel-track:not(.swiper-initialized) .artbid-carousel-slide {
  flex: 0 0 auto;
  width: auto;
}
.artbid-carousel[data-mode=marquee].is-strip {
  position: relative;
}
.artbid-carousel[data-mode=marquee].is-strip .swiper-wrapper {
  display: flex;
  gap: 0;
  width: max-content;
  animation: artbid-strip var(--strip-duration, 60s) linear infinite;
}
.artbid-carousel[data-mode=marquee].is-strip .artbid-carousel-slide {
  margin-right: var(--strip-gap, 0);
}
.artbid-carousel[data-mode=marquee].is-strip.is-paused .swiper-wrapper, .artbid-carousel[data-mode=marquee].is-strip:hover .swiper-wrapper, .artbid-carousel[data-mode=marquee].is-strip:focus-within .swiper-wrapper {
  animation-play-state: paused;
}
.artbid-carousel[data-mode=marquee] .artbid-carousel-pause {
  position: absolute;
  left: var(--spacing-scale-4);
  top: calc(var(--strip-pause-bottom, 100%) - var(--spacing-scale-4));
  z-index: 1;
  transform: translateY(-100%);
  color: var(--color-base-white);
  filter: drop-shadow(0 0 var(--spacing-scale-1) rgba(0, 0, 0, 0.5));
  transition: opacity var(--transition-duration-300) var(--transition-timing-ease-out);
}
.artbid-carousel[data-mode=marquee] .artbid-carousel-pause:focus-visible {
  outline-color: var(--color-base-white);
}
@media (hover: hover) and (pointer: fine) {
  .artbid-carousel[data-mode=marquee]:not(.is-paused) .artbid-carousel-pause {
    opacity: 0;
  }
  .artbid-carousel[data-mode=marquee]:hover .artbid-carousel-pause,
  .artbid-carousel[data-mode=marquee] .artbid-carousel-pause:focus-visible {
    opacity: 1;
  }
}
.artbid-carousel[data-mode=marquee]:not(.is-strip) .artbid-carousel-pause, .artbid-carousel[data-mode=marquee].is-locked .artbid-carousel-pause {
  display: none;
}

@keyframes artbid-strip {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(var(--strip-shift, -50%));
  }
}
@media (prefers-reduced-motion: reduce) {
  .artbid-carousel[data-mode=marquee] .artbid-carousel-pause {
    transition: none;
  }
}
.artbid-carousel-nav-start {
  display: flex;
  align-items: center;
  gap: var(--spacing-scale-2);
}

.artbid-carousel-pause {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--spacing-scale-8);
  height: var(--spacing-scale-8);
  padding: 0;
  color: var(--color-base-black);
  background: none;
  border: 0;
  cursor: pointer;
}
@media (pointer: coarse) {
  .artbid-carousel-pause {
    width: var(--button-height-md);
    height: var(--button-height-md);
  }
}
.artbid-carousel-pause svg {
  width: var(--spacing-scale-4);
  height: var(--spacing-scale-4);
}
.artbid-carousel-pause:focus-visible {
  outline: var(--border-width-2) solid var(--color-base-black);
  outline-offset: var(--border-width-2);
}
.artbid-carousel-pause .artbid-carousel-play-icon {
  display: none;
}

.artbid-carousel.is-paused .artbid-carousel-pause .artbid-carousel-pause-icon {
  display: none;
}
.artbid-carousel.is-paused .artbid-carousel-pause .artbid-carousel-play-icon {
  display: block;
}

/**
 * THE AMBIENT VIDEO TOGGLE — one source (2026-10-19, Lane 29). The pause /
 * play button on every silent looping video: Content Video (Ambient), an
 * Image Card and the Image & Text media cell. Markup:
 * artbid_ambient_toggle_html() (inc/helpers/ambient-video.php); script:
 * assets/js/content-video.js (adds .is-playing to the root).
 *
 * THE BARE GLYPH (Yael, card 66; Chuck 2026-10-16): no circle, just the
 * symbol, as the carousel arrows (no circles or boxes anywhere, 07-18). The
 * hit area stays (32, 44 on touch); a soft shadow keeps a white glyph readable
 * on light footage (no glyph-shadow token yet — design-token-index §2.2 gap).
 * Hidden while it plays until hover / focus (a mouse); paused, focused or on a
 * touch screen it stays in view, so play is always findable.
 *
 * @param $root  The element that carries .is-playing.
 * @param $z     Its stacking order inside the media box.
 */
/**
 * Shared Styles Index
 * Main entry point for all shared styles
 *
 * Usage in block styles:
 * @use '../_shared' as shared;
 *
 * .my-block {
 *   @include shared.block-container();
 * }
 */
/**
 * Image Block Editor Styles
 * Shared editor preview styles for all image blocks
 *
 * Usage:
 * @use '../_shared' as *;
 * @include image-block-editor-base();
 */
/**
 * Base editor styles for image blocks with object-fit modes
 * Apply to any block that uses data-object-fit and data-height attributes
 *
 * @param {String} $block-class - The block class (e.g., 'content-full-image')
 * @param {String} $figure-class - The figure class (e.g., 'content-full-image-figure')
 */
/**
 * Editor grid layouts for multi-image blocks
 *
 * @param {String} $block-class - The block class
 * @param {String} $inner-class - The inner grid container class
 */
/**
 * Shared "Remove image" button for the editor (over-image variant).
 *
 * Replaces the old inline red-text-on-transparent <Button isDestructive> that
 * was hard to see over photos. Renders as a dark, semi-transparent pill with a
 * white ✕ at rest (legible on ANY image); on hover/focus it turns red and
 * reveals a "Remove" label — unobtrusive at rest, unmistakably destructive on
 * intent. EDITOR-ONLY (this file is imported by each block's editor.scss).
 *
 * Markup contract (edit.js):
 *   <Button className="artbid-remove-image" onClick={…} isDestructive>
 *     <span class="artbid-remove-image__label">Remove</span>
 *   </Button>
 * The button must sit inside a `position: relative` parent (the image
 * container/figure it overlays) — every call site already provides one.
 */
/**
 * Media upload placeholder styling
 */
/**
 * Shared Styles Index
 * Main entry point for all shared styles
 *
 * Usage in block styles:
 * @use '../_shared' as shared;
 *
 * .my-block {
 *   @include shared.block-container();
 * }
 */
/**
 * The contact form's fields (AB-171): label sm above, a white box on a
 * gray-300 hairline, gray-400 on hover, a 2px black ring on focus; errors,
 * status, the spam check, the privacy line, the honeypot, the thank-you.
 * One look for every form that posts to the contact route: the Contact Form
 * block and the Ask a Question pop-up (2026-11-09). Include it inside the
 * form's scope (the content flow resets outrank a bare class).
 */
/**
 * Shared Styles Index
 * Main entry point for all shared styles
 *
 * Usage in block styles:
 * @use '../_shared' as shared;
 *
 * .my-block {
 *   @include shared.block-container();
 * }
 */
.container {
  width: 100%;
  max-width: var(--layout-container-wide);
  margin-left: auto;
  margin-right: auto;
  padding-left: var(--spacing-container-inline);
  padding-right: var(--spacing-container-inline);
  box-sizing: border-box;
}

[data-container=narrow] .container {
  max-width: var(--layout-container-standard);
}

[data-container=prose] .container {
  max-width: var(--layout-container-prose);
}

[data-container=ultra] .container {
  max-width: var(--layout-container-ultra);
}

/* ============================================
   SHARED STYLES (All Layouts)
   ============================================ */
.inner-hero {
  position: relative;
  width: 100%;
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

/* Art-directed desktop/mobile media (JZ-026). Show/hide the desktop vs mobile
   variant at the block's mobile edge (767px). Single-media <img> art-direction
   is handled natively by <picture> (no class needed); these classes are for the
   cases that can't use <picture>: a video's mobile IMAGE alternate (S4), and the
   two carousel swipers (C1/C3). display:none also stops the hidden variant's
   video autoplaying / (with the JS init gate) its swiper initialising. */
.inner-hero-media--mobile-only {
  display: none;
}

@media (max-width: 767px) {
  .inner-hero-media--desktop-only {
    display: none;
  }
  .inner-hero-media--mobile-only {
    display: block;
  }
}
/* Typography - Shared across all layouts */
.inner-hero-eyebrow {
  display: block;
  font-size: var(--font-size-sm, clamp(0.875rem, 0.851rem + 0.065vw, 0.9375rem));
  text-transform: uppercase;
  letter-spacing: var(--font-letterSpacing-widest);
  margin-bottom: clamp(0.5rem, 0.4rem + 0.4vw, 0.75rem);
}

/* Hide eyebrow when toggle is off */
.inner-hero[data-show-eyebrow=false] .inner-hero-eyebrow {
  display: none;
}

/* Hide main heading (JZ-037): the FRONTEND omits the <h1> from the DOM entirely
   (render.php strip) for correct heading structure. In the EDITOR the heading
   InnerBlock can't be removed (it must stay editable to toggle back), so the
   editor hides it visually instead — scoped to .editor-styles-wrapper in
   editor.scss. No frontend display:none rule. */
.inner-hero-heading {
  font-family: var(--font-display, "loretta-display", Georgia, serif);
  font-size: var(--font-size-4xl, clamp(2.25rem, 1.694rem + 1.488vw, 3.75rem));
  line-height: var(--font-lineHeight-tight);
  font-weight: var(--font-weight-normal);
  margin-bottom: var(--spacing-fluid-hero-button-gap, var(--spacing-gap-sm));
}

.inner-hero-subheading {
  font-size: var(--font-size-xl, clamp(1.25rem, 1.032rem + 0.517vw, 1.625rem));
  line-height: var(--font-lineHeight-relaxed);
  margin-bottom: var(--spacing-gap-md);
}

/* Hide subheading when toggle is off */
.inner-hero[data-show-subheading=false] .inner-hero-subheading {
  display: none;
}

.inner-hero-description {
  font-size: var(--font-size-lg, clamp(1.125rem, 0.98rem + 0.323vw, 1.375rem));
  line-height: var(--font-lineHeight-relaxed);
  max-width: var(--layout-container-prose);
  margin-bottom: clamp(1rem, 0.85rem + 0.5vw, 1.25rem);
}

/* Buttons */
/* The buttons wrapper. Until 2026-08-25 this was a core/buttons block whose OWN
   `layout` attr provided the flex row + justify; now it's the artbid/hero-buttons
   block (hero-buttons-unify-scope Phase A), a plain div, so the flex row lives
   here. Default = a wrap-friendly row; justify follows the hero's halign (below).
   Only artbid/button children exist now — the old .wp-block-button/__link
   selectors were dead (core buttons could never be here) and were removed. */
.inner-hero-buttons {
  margin-top: clamp(1.5rem, 1rem + 1.5vw, 3rem);
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  gap: var(--spacing-fluid-hero-button-gap, clamp(0.75rem, 0.5rem + 0.75vw, 1.25rem));
  align-items: center;
}

/* Justify the button row by the hero's horizontal alignment (core/buttons used
   to carry this as a saved justifyContent; now it's derived from data-halign). */
.inner-hero[data-halign=start] .inner-hero-buttons {
  justify-content: flex-start;
}

.inner-hero[data-halign=center] .inner-hero-buttons {
  justify-content: center;
}

.inner-hero[data-halign=end] .inner-hero-buttons {
  justify-content: flex-end;
}

/* Button alignment OVERRIDE (#3, 2026-08-25). When set, aligns the buttons
   independently of the text halign. Higher specificity than the halign rules
   above (extra [data-button-align] attr on the same .inner-hero). Absent (the
   'inherit' default) → the halign rules win, byte-identical to before. */
.inner-hero[data-button-align=left] .inner-hero-buttons {
  justify-content: flex-start;
}

.inner-hero[data-button-align=center] .inner-hero-buttons {
  justify-content: center;
}

.inner-hero[data-button-align=right] .inner-hero-buttons {
  justify-content: flex-end;
}

/* Hide buttons when toggle is off */
.inner-hero[data-show-buttons=false] .inner-hero-buttons {
  display: none;
}

/* ============================================
   MOBILE VISIBILITY OVERRIDES (AB-136 Slice 1)
   Per-piece hide/show ONLY on mobile (<768px), gated by customizeMobile.
   Emitted attrs: data-show-{piece}-mobile = "show" | "hide" (absent = inherit
   desktop → these rules don't match → byte-identical to today).

   - eyebrow / subheading / buttons render in the DOM (CSS-hidden when their
     desktop toggle is off), so mobile can BOTH hide and RE-SHOW them: the
     "show" rule overrides the desktop [data-show-X="false"] hide at mobile.
   - heading + timer are OMITTED from the DOM when off (SEO / child-block
     removal), so mobile is HIDE-ONLY for them — a "show" has nothing to reveal
     (see hero-mobile-overrides-scope §8). We still emit the hide rule.
   Desktop is untouched; all rules live inside the mobile media query.
   ============================================ */
@media (max-width: 767px) {
  .inner-hero[data-show-eyebrow-mobile=hide] .inner-hero-eyebrow {
    display: none;
  }
  .inner-hero[data-show-heading-mobile=hide] .inner-hero-heading {
    display: none;
  }
  .inner-hero[data-show-subheading-mobile=hide] .inner-hero-subheading {
    display: none;
  }
  .inner-hero[data-show-timer-mobile=hide] .inner-hero-timer {
    display: none;
  }
  .inner-hero[data-show-buttons-mobile=hide] .inner-hero-buttons {
    display: none;
  }
  .inner-hero[data-show-eyebrow=false][data-show-eyebrow-mobile=show] .inner-hero-eyebrow {
    display: revert;
  }
  .inner-hero[data-show-subheading=false][data-show-subheading-mobile=show] .inner-hero-subheading {
    display: revert;
  }
  .inner-hero[data-show-buttons=false][data-show-buttons-mobile=show] .inner-hero-buttons {
    display: flex;
  }
}
/* ============================================
   MOBILE REORDER (AB-136 Slice 3)
   Only when data-mobile-reorder="true" (customizeMobile + a valid mobileOrder).
   render.php emits inline CSS vars --mo-{piece}: <index> on .inner-hero; the five
   named pieces read `order: var(--mo-{piece})`. Absent the flag, .inner-hero-content
   stays in normal block flow → document order (byte-identical).

   .inner-hero-content becomes a flex COLUMN so `order` applies. `align-items:
   stretch` (the default) keeps the pieces full-width exactly as block flow did, so
   horizontal position/spacing are unchanged — only vertical order moves. A hidden
   piece (Slice 1 display:none) drops out of the flex flow with no gap (Chuck Q4).
   Unlisted pieces fall back to order:99 → after the listed ones, in source order.
   ============================================ */
@media (max-width: 767px) {
  .inner-hero[data-mobile-reorder=true] .inner-hero-content {
    display: flex;
    flex-direction: column;
    align-items: stretch;
  }
  .inner-hero[data-mobile-reorder=true] .inner-hero-eyebrow {
    order: var(--mo-eyebrow, 99);
  }
  .inner-hero[data-mobile-reorder=true] .inner-hero-heading {
    order: var(--mo-heading, 99);
  }
  .inner-hero[data-mobile-reorder=true] .inner-hero-subheading {
    order: var(--mo-subheading, 99);
  }
  .inner-hero[data-mobile-reorder=true] .inner-hero-timer {
    order: var(--mo-timer, 99);
  }
  .inner-hero[data-mobile-reorder=true] .inner-hero-buttons {
    order: var(--mo-buttons, 99);
  }
}
/* The wrapper always contains BOTH buttons (the count is not reconciled
   block-by-block — Gutenberg async state made that flaky). data-button-count=
   "one" hides the SECOND button. Frontend: the buttons are DIRECT children of
   .inner-hero-buttons. (The editor's Gutenberg wrapper case is handled in
   editor.scss, which counts nth-child inside .block-editor-block-list__layout.) */
.inner-hero[data-button-count=one] .inner-hero-buttons > .wp-block-artbid-button:nth-child(2) {
  display: none;
}

/* ============================================
   BUTTON ARRANGEMENT (one control, JZ-039/040/041 unified 2026-08-14).
   data-button-arrangement = auto | equal | stacked. Replaces the old
   data-button-layout × data-button-width pair (see hero-button-width-scope §6).
   MOBILE (<768px) ALWAYS STACKS full-width regardless of arrangement.
   ============================================ */
/* DESKTOP (≥768px): the arrangement takes effect. */
@media (min-width: 768px) {
  /* equal — both buttons take the WIDER button's width (matched to the longer
     label, neither wraps). flex:1 1 0 was wrong: it splits the row 50/50
     regardless of content, so a long label wraps + grows taller (finding
     2026-08-25). CSS Grid with two 1fr tracks + `width:fit-content` makes both
     columns equal to the WIDEST column's content; each .btn fills its track.
     The row then sizes to (2× wider button + gap); justify-content (from the
     hero halign rule above) still positions it. Grid overrides the base flex. */
  /* ONE button (#16, 2026-09-29): Equal only applies with 2+ buttons. With
     Button Count = one the grid parked the single button in the LEFT track and
     cancelled the alignment; every equal rule now skips count=one, so a lone
     button falls back to the auto row and follows halign / button-align. The
     saved buttonArrangement is untouched (switching back to two restores it). */
  .inner-hero[data-button-arrangement=equal]:not([data-button-count=one]) .inner-hero-buttons {
    display: grid;
    grid-auto-flow: column;
    grid-template-columns: repeat(2, 1fr);
    width: fit-content;
    max-width: 100%;
    /* keep the halign justification working on a grid container */
    justify-content: inherit;
  }
  .inner-hero[data-button-arrangement=equal]:not([data-button-count=one]) .inner-hero-buttons .wp-block-artbid-button {
    width: 100%;
  }
  .inner-hero[data-button-arrangement=equal]:not([data-button-count=one]) .inner-hero-buttons .btn {
    width: 100%;
  }
  /* Grid's fit-content row must still honor alignment. On a grid the block is
     placed by margins within .inner-hero-content (justify-content can't move a
     fit-content block), so center/end need margin auto. Position follows the
     hero halign by default; the button-align override (#3) wins when set (its
     extra attr raises specificity; left explicitly resets the auto margins). */
  .inner-hero[data-halign=center][data-button-arrangement=equal]:not([data-button-count=one]) .inner-hero-buttons {
    margin-left: auto;
    margin-right: auto;
  }
  .inner-hero[data-halign=end][data-button-arrangement=equal]:not([data-button-count=one]) .inner-hero-buttons {
    margin-left: auto;
    margin-right: 0;
  }
  .inner-hero[data-button-align=left][data-button-arrangement=equal]:not([data-button-count=one]) .inner-hero-buttons {
    margin-left: 0;
    margin-right: auto;
  }
  .inner-hero[data-button-align=center][data-button-arrangement=equal]:not([data-button-count=one]) .inner-hero-buttons {
    margin-left: auto;
    margin-right: auto;
  }
  .inner-hero[data-button-align=right][data-button-arrangement=equal]:not([data-button-count=one]) .inner-hero-buttons {
    margin-left: auto;
    margin-right: 0;
  }
  /* stacked — column, each button full-width. */
  .inner-hero[data-button-arrangement=stacked] .inner-hero-buttons {
    flex-direction: column;
    align-items: stretch;
  }
  .inner-hero[data-button-arrangement=stacked] .inner-hero-buttons .wp-block-artbid-button,
  .inner-hero[data-button-arrangement=stacked] .inner-hero-buttons .btn {
    width: 100%;
  }
  /* auto = the default flex row, buttons fit their text — no rules needed. */
}
/* MOBILE (<768px): every arrangement stacks full-width. */
@media (max-width: 767px) {
  .inner-hero-buttons {
    flex-direction: column;
    align-items: stretch;
  }
  .inner-hero-buttons .wp-block-artbid-button,
  .inner-hero-buttons .btn {
    width: 100%;
  }
}
/* Heading size modifiers */
.inner-hero-heading--sm {
  font-size: var(--font-size-3xl, clamp(1.875rem, 1.419rem + 1.165vw, 3rem));
}

.inner-hero-heading--md {
  font-size: var(--font-size-4xl, clamp(2.25rem, 1.694rem + 1.488vw, 3.75rem)); /* Default */
}

.inner-hero-heading--lg {
  font-size: var(--font-size-5xl, clamp(3rem, 2.226rem + 2.07vw, 5rem));
}

.inner-hero-heading--xl {
  font-size: var(--font-size-6xl, clamp(3.75rem, 2.661rem + 3.1vw, 6.75rem));
}

/* ============================================
   POSITIONING CORE (all layouts, ONE model)
   valign / halign / content-fit / underlap.
   See _shared/mixins/_hero-positioning.scss.
   ============================================ */
/* full-image + text-only: the block root IS the positioning region. */
.inner-hero[data-layout=full-image] {
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
  justify-content: safe center;
  align-items: flex-start;
  text-align: left;
}

.inner-hero[data-layout=full-image][data-underlap=true] {
  padding-top: var(--header-height, 88px);
}

@media (min-width: 768px) {
  .inner-hero[data-layout=full-image][data-underlap=true] {
    padding-top: var(--header-height, 96px);
  }
}
.inner-hero[data-layout=full-image][data-valign=start] {
  justify-content: flex-start;
}

.inner-hero[data-layout=full-image][data-valign=center] {
  justify-content: safe center;
}

.inner-hero[data-layout=full-image][data-valign=end] {
  justify-content: safe flex-end;
}

@media (max-width: 767px) {
  .inner-hero[data-layout=full-image][data-valign-mobile=start] {
    justify-content: flex-start;
  }
  .inner-hero[data-layout=full-image][data-valign-mobile=center] {
    justify-content: safe center;
  }
  .inner-hero[data-layout=full-image][data-valign-mobile=end] {
    justify-content: safe flex-end;
  }
}
.inner-hero[data-layout=full-image][data-halign=start] {
  align-items: flex-start;
}

.inner-hero[data-layout=full-image][data-halign=center] {
  align-items: center;
}

.inner-hero[data-layout=full-image][data-halign=end] {
  align-items: flex-end;
}

@media (max-width: 767px) {
  .inner-hero[data-layout=full-image][data-halign-mobile=start] {
    align-items: flex-start;
  }
  .inner-hero[data-layout=full-image][data-halign-mobile=center] {
    align-items: center;
  }
  .inner-hero[data-layout=full-image][data-halign-mobile=end] {
    align-items: flex-end;
  }
}
.inner-hero[data-layout=full-image][data-content-fit=clip] {
  overflow: hidden;
}

.inner-hero[data-layout=text-only] {
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
  justify-content: safe center;
  align-items: flex-start;
  text-align: left;
}

.inner-hero[data-layout=text-only][data-underlap=true] {
  padding-top: var(--header-height, 88px);
}

@media (min-width: 768px) {
  .inner-hero[data-layout=text-only][data-underlap=true] {
    padding-top: var(--header-height, 96px);
  }
}
.inner-hero[data-layout=text-only][data-valign=start] {
  justify-content: flex-start;
}

.inner-hero[data-layout=text-only][data-valign=center] {
  justify-content: safe center;
}

.inner-hero[data-layout=text-only][data-valign=end] {
  justify-content: safe flex-end;
}

@media (max-width: 767px) {
  .inner-hero[data-layout=text-only][data-valign-mobile=start] {
    justify-content: flex-start;
  }
  .inner-hero[data-layout=text-only][data-valign-mobile=center] {
    justify-content: safe center;
  }
  .inner-hero[data-layout=text-only][data-valign-mobile=end] {
    justify-content: safe flex-end;
  }
}
.inner-hero[data-layout=text-only][data-halign=start] {
  align-items: flex-start;
}

.inner-hero[data-layout=text-only][data-halign=center] {
  align-items: center;
}

.inner-hero[data-layout=text-only][data-halign=end] {
  align-items: flex-end;
}

@media (max-width: 767px) {
  .inner-hero[data-layout=text-only][data-halign-mobile=start] {
    align-items: flex-start;
  }
  .inner-hero[data-layout=text-only][data-halign-mobile=center] {
    align-items: center;
  }
  .inner-hero[data-layout=text-only][data-halign-mobile=end] {
    align-items: flex-end;
  }
}
.inner-hero[data-layout=text-only][data-content-fit=clip] {
  overflow: hidden;
}

/* split: the CONTENT SIDE is the positioning region (media is the other child). */
.inner-hero[data-layout=split] .inner-hero-split-content {
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
  justify-content: safe center;
  align-items: flex-start;
  text-align: left;
}

.inner-hero[data-layout=split][data-underlap=true] .inner-hero-split-content {
  padding-top: var(--header-height, 88px);
}

@media (min-width: 768px) {
  .inner-hero[data-layout=split][data-underlap=true] .inner-hero-split-content {
    padding-top: var(--header-height, 96px);
  }
}
.inner-hero[data-layout=split][data-valign=start] .inner-hero-split-content {
  justify-content: flex-start;
}

.inner-hero[data-layout=split][data-valign=center] .inner-hero-split-content {
  justify-content: safe center;
}

.inner-hero[data-layout=split][data-valign=end] .inner-hero-split-content {
  justify-content: safe flex-end;
}

@media (max-width: 767px) {
  .inner-hero[data-layout=split][data-valign-mobile=start] .inner-hero-split-content {
    justify-content: flex-start;
  }
  .inner-hero[data-layout=split][data-valign-mobile=center] .inner-hero-split-content {
    justify-content: safe center;
  }
  .inner-hero[data-layout=split][data-valign-mobile=end] .inner-hero-split-content {
    justify-content: safe flex-end;
  }
}
.inner-hero[data-layout=split][data-halign=start] .inner-hero-split-content {
  align-items: flex-start;
}

.inner-hero[data-layout=split][data-halign=center] .inner-hero-split-content {
  align-items: center;
}

.inner-hero[data-layout=split][data-halign=end] .inner-hero-split-content {
  align-items: flex-end;
}

@media (max-width: 767px) {
  .inner-hero[data-layout=split][data-halign-mobile=start] .inner-hero-split-content {
    align-items: flex-start;
  }
  .inner-hero[data-layout=split][data-halign-mobile=center] .inner-hero-split-content {
    align-items: center;
  }
  .inner-hero[data-layout=split][data-halign-mobile=end] .inner-hero-split-content {
    align-items: flex-end;
  }
}
.inner-hero[data-layout=split][data-content-fit=clip] .inner-hero-split-content {
  overflow: hidden;
}

/* ============================================
   LAYOUT 1: SPLIT LAYOUT (Media + Text)
   ============================================ */
.inner-hero[data-layout=split] {
  display: flex;
  flex-direction: column;
  gap: 0;
}
@media (min-width: 768px) {
  .inner-hero[data-layout=split] {
    flex-direction: row;
    gap: 0;
  }
}
.inner-hero[data-layout=split] {
  /* Height controlled by block-heights mixin. Row/column direction is set by
     data-media-position below (the hero-positioning mixin sets the CONTENT
     SIDE to flex-column; the split axis lives on the block root). */
  flex-direction: column;
}
@media (min-width: 768px) {
  .inner-hero[data-layout=split] {
    flex-direction: row;
  }
}

/* Media side */
.inner-hero-split-media {
  box-sizing: border-box;
}
@media (max-width: 767px) {
  .inner-hero-split-media {
    width: 100%;
  }
}
@media (min-width: 768px) {
  .inner-hero-split-media {
    flex: 0 0 auto;
  }
}
.inner-hero-split-media {
  position: relative;
  overflow: hidden;
  background-color: var(--color-gray-100, #f3f4f6);
  min-height: var(--layout-minHeight-sm); /* Ensure it has height even without media */
}
@media (max-width: 767px) {
  .inner-hero-split-media {
    height: var(--layout-minHeight-sm);
  }
}
@media (min-width: 768px) {
  .inner-hero-split-media {
    align-self: stretch;
  }
}
.inner-hero-split-media {
  /* 40/60 split: 40% text / 60% media */
}
@media (min-width: 768px) {
  .inner-hero[data-split="40-60"] .inner-hero-split-media {
    flex-basis: 60%;
  }
}
.inner-hero-split-media {
  /* 50/50 split */
}
@media (min-width: 768px) {
  .inner-hero[data-split="50-50"] .inner-hero-split-media {
    flex-basis: 50%;
  }
}

.inner-hero-split-image,
.inner-hero-split-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--focal, center);
}
@media (max-width: 767px) {
  .inner-hero-split-image,
  .inner-hero-split-video {
    object-position: var(--focal-mobile, var(--focal, center));
  }
}

.inner-hero-split-image {
  transform: scale(var(--focal-zoom, 1));
  transform-origin: var(--focal, center);
}
@media (max-width: 767px) {
  .inner-hero-split-image {
    transform: scale(var(--focal-zoom-mobile, var(--focal-zoom, 1)));
    transform-origin: var(--focal-mobile, var(--focal, center));
  }
}

/* Image fit variants */
.inner-hero[data-image-fit=landscape] .inner-hero-split-image,
.inner-hero[data-image-fit=landscape] .inner-hero-split-video {
  width: auto;
  height: 100%;
  min-width: 100%;
}

.inner-hero[data-image-fit=portrait] .inner-hero-split-image,
.inner-hero[data-image-fit=portrait] .inner-hero-split-video {
  width: 100%;
  height: auto;
  min-height: 100%;
}

/* Content side — flex column set by the positioning mixin; here we only size it,
   colour it, and pad it. valign/halign live in the mixin. */
.inner-hero-split-content {
  box-sizing: border-box;
}
@media (max-width: 767px) {
  .inner-hero-split-content {
    width: 100%;
  }
}
@media (min-width: 768px) {
  .inner-hero-split-content {
    flex: 0 0 auto;
  }
}
.inner-hero-split-content {
  position: relative;
  background-color: var(--color-base-white, #ffffff);
  padding: var(--spacing-block-md, var(--spacing-block-md));
  min-height: auto;
  overflow: visible;
}
@media (max-width: 767px) {
  .inner-hero-split-content {
    padding-inline: var(--spacing-section-inline, var(--spacing-container-inline));
  }
}
@media (min-width: 768px) {
  .inner-hero-split-content {
    align-self: stretch;
  }
}
.inner-hero-split-content {
  /* 40/60 split: 40% text / 60% media */
}
@media (min-width: 768px) {
  .inner-hero[data-split="40-60"] .inner-hero-split-content {
    flex-basis: 40%;
  }
}
.inner-hero-split-content {
  /* 50/50 split */
}
@media (min-width: 768px) {
  .inner-hero[data-split="50-50"] .inner-hero-split-content {
    flex-basis: 50%;
  }
}

.inner-hero-split-content-inner {
  width: 100%;
  max-width: var(--layout-container-prose-medium);
  color: var(--color-base-black, #000000);
}

/* JZ-024 hardening: the split content sits on a LIGHT background, but an author
   can still pick an INVERTED button variant (white bg + white border, meant for
   dark hero images) — which renders white-on-white = invisible ("unstyled
   text"). On the split content only, give inverted buttons a visible dark
   outline so they never disappear. Non-inverted variants are unaffected.
   Fresh template buttons already use the correct non-inverted variants. */
.inner-hero[data-layout=split] .inner-hero-split-content-inner .btn-primary-inverted,
.inner-hero[data-layout=split] .inner-hero-split-content-inner .btn-secondary-inverted {
  border-color: var(--color-base-black, #000000);
}

/* Media position (left/right) — the split axis on the block root. MUST be
   scoped to the SPLIT layout: full-image also carries a data-media-position
   attribute, and an unscoped `flex-direction: row` here leaked onto full-image's
   root, forcing it to `row` and BREAKING the column-based vertical positioning
   (valign had no effect — hero-positioning-v2-notes §1; fixed 2026-08-14). */
.inner-hero[data-layout=split][data-media-position=left] {
  flex-direction: column;
}
@media (min-width: 768px) {
  .inner-hero[data-layout=split][data-media-position=left] {
    flex-direction: row;
  }
}

.inner-hero[data-layout=split][data-media-position=right] {
  flex-direction: column;
}
@media (min-width: 768px) {
  .inner-hero[data-layout=split][data-media-position=right] {
    flex-direction: row-reverse;
  }
}

/* Background colors for split layout */
.inner-hero[data-layout=split][data-bg=white] .inner-hero-split-content {
  background-color: var(--color-base-white);
}
.inner-hero[data-layout=split][data-bg=white] .inner-hero-split-content .inner-hero-split-content-inner :not(.btn):not(.wp-block-button__link):not(.wp-block-artbid-button) {
  color: var(--color-base-black);
}
.inner-hero[data-layout=split][data-bg=gray] .inner-hero-split-content {
  background-color: var(--color-gray-100);
}
.inner-hero[data-layout=split][data-bg=gray] .inner-hero-split-content .inner-hero-split-content-inner :not(.btn):not(.wp-block-button__link):not(.wp-block-artbid-button) {
  color: var(--color-base-black);
}
.inner-hero[data-layout=split][data-bg=tan] .inner-hero-split-content {
  background-color: var(--color-warm-300);
}
.inner-hero[data-layout=split][data-bg=tan] .inner-hero-split-content .inner-hero-split-content-inner :not(.btn):not(.wp-block-button__link):not(.wp-block-artbid-button) {
  color: var(--color-base-black);
}

/* ============================================
   LAYOUT 2: TEXT ONLY
   ============================================ */
/* The block root is the positioning region (mixin above). We size the inner
   wrapper + constrain content width. No align-items/padding-top positioning
   here — that's the shared model now. */
.inner-hero[data-layout=text-only] .inner-hero-content-wrapper {
  position: relative;
  display: flex;
  width: 100%;
  max-width: var(--layout-container-wide);
  margin-left: auto;
  margin-right: auto;
  padding-left: var(--spacing-section-inline, var(--spacing-container-inline));
  padding-right: var(--spacing-section-inline, var(--spacing-container-inline));
  padding-bottom: clamp(0.75rem, 0.6rem + 0.5vw, 1.25rem);
  box-sizing: border-box;
}

.inner-hero[data-layout=text-only] .inner-hero-content {
  width: 100%;
  max-width: 56rem;
}

/* Background colors for text-only layout */
.inner-hero[data-layout=text-only][data-bg=white] {
  background-color: var(--color-base-white);
}
.inner-hero[data-layout=text-only][data-bg=white] .inner-hero-content :not(.btn):not(.wp-block-button__link):not(.wp-block-artbid-button) {
  color: var(--color-base-black);
}
.inner-hero[data-layout=text-only][data-bg=gray] {
  background-color: var(--color-gray-100);
}
.inner-hero[data-layout=text-only][data-bg=gray] .inner-hero-content :not(.btn):not(.wp-block-button__link):not(.wp-block-artbid-button) {
  color: var(--color-base-black);
}
.inner-hero[data-layout=text-only][data-bg=tan] {
  background-color: var(--color-warm-300);
}
.inner-hero[data-layout=text-only][data-bg=tan] .inner-hero-content :not(.btn):not(.wp-block-button__link):not(.wp-block-artbid-button) {
  color: var(--color-base-black);
}

/* Horizontal band: the content-wrapper follows halign (start/center/end) so the
   content COLUMN sits left / centered / right within the 1600px band. The mixin
   sets align-items on the region (block root); here we map it onto the wrapper's
   own justify so the text block itself moves. */
.inner-hero[data-layout=text-only][data-halign=center] .inner-hero-content-wrapper {
  justify-content: center;
}

.inner-hero[data-layout=text-only][data-halign=center] .inner-hero-content {
  margin-left: auto;
  margin-right: auto;
}

.inner-hero[data-layout=text-only][data-halign=start] .inner-hero-content-wrapper {
  justify-content: flex-start;
}

.inner-hero[data-layout=text-only][data-halign=end] .inner-hero-content-wrapper {
  justify-content: flex-end;
}

/* ============================================
   LAYOUT 3: FULL IMAGE
   ============================================ */
/* Block root is the positioning region (mixin above). Only media + overlay +
   content-wrapper sizing live here. */
.inner-hero[data-layout=full-image] {
  position: relative;
  width: 100%;
  overflow: visible; /* allow content expansion (content-fit: flow) */
}

/* Ensure background media still fills container */
.inner-hero[data-layout=full-image]::before {
  content: "";
  position: absolute;
  inset: 0;
  overflow: hidden;
  z-index: 0;
}

/* Background media */
.inner-hero-image,
.inner-hero-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 1;
  object-position: var(--focal, center);
}
@media (max-width: 767px) {
  .inner-hero-image,
  .inner-hero-video {
    object-position: var(--focal-mobile, var(--focal, center));
  }
}

.inner-hero-image-clip {
  position: absolute;
  inset: 0;
  overflow: hidden;
  z-index: 1;
}

.inner-hero-image {
  transform: scale(var(--focal-zoom, 1));
  transform-origin: var(--focal, center);
}
@media (max-width: 767px) {
  .inner-hero-image {
    transform: scale(var(--focal-zoom-mobile, var(--focal-zoom, 1)));
    transform-origin: var(--focal-mobile, var(--focal, center));
  }
}

/* ── CAROUSEL background layer (Chunk 1) ──
   Occupies the SAME background layer as .inner-hero-image (absolute, inset 0,
   z-index 1), so the overlay (z-2) and content (z-3) sit above it unchanged.
   The carousel is a background swap only — it does NOT affect content
   positioning (that's the rebuilt engine). */
.inner-hero .inner-hero-carousel {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
}
.inner-hero .inner-hero-carousel .swiper-wrapper,
.inner-hero .inner-hero-carousel .swiper-slide {
  height: 100%;
}

.inner-hero-carousel-image {
  width: 100%;
  height: 100%;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

/* Pagination dots — position within the hero (left/center/right) via the
   data-dots-position on the pagination container. Colour comes from the shared
   carousel-pagination--light|dark classes. Dots sit above the overlay. */
/* Controls row = dots + pause as ONE unit. It's the absolute, full-width bar;
   the dots + pause align within it via justify-content. This owns positioning so
   Swiper (which force-positions .swiper-pagination) can't fight it: we override
   the inner pagination back to static/inline. */
/* The controls row's inset from the hero edge and its height, named once so
   the text can clear the row (card 55: on phones bottom-aligned text ran 12px
   into the dots). Height = the pause/arrow hit area (2rem; a finger's 44). */
.inner-hero {
  --hero-controls-inset: clamp(1rem, 0.5rem + 1.5vw, 2rem);
  --hero-controls-h: 2rem;
}
@media (pointer: coarse) {
  .inner-hero {
    --hero-controls-h: var(--button-height-md);
  }
}

.inner-hero .inner-hero-carousel-controls {
  position: absolute;
  left: 0;
  right: 0;
  width: 100%;
  bottom: var(--hero-controls-inset);
  z-index: 4; /* above overlay (2) + content (3) so clickable */
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding-left: var(--spacing-section-inline, var(--spacing-container-inline));
  padding-right: var(--spacing-section-inline, var(--spacing-container-inline));
  box-sizing: border-box;
}
.inner-hero .inner-hero-carousel-controls[data-dots-position=left] {
  justify-content: flex-start;
}
.inner-hero .inner-hero-carousel-controls[data-dots-position=center] {
  justify-content: center;
}
.inner-hero .inner-hero-carousel-controls[data-dots-position=right] {
  justify-content: flex-end;
}

/* Controls row vertical position (2026-09-15): Top mirrors the bottom inset. */
.inner-hero .inner-hero-carousel-controls[data-controls-vertical=top] {
  top: var(--hero-controls-inset);
  bottom: auto;
}

/* Variant visibility for the CONTROLS row (2026-09-15, found while porting the
   carousel to split): the global `.inner-hero-media--mobile-only { display:none }`
   (0,1,0) LOSES to the controls rule above (0,2,0), so with a mobile carousel
   BOTH controls rows showed at every width — two pause buttons. Same bug on
   full-image; fixed for both by restating the variant rule at the controls'
   specificity. The swipers themselves were already fine (no display in their rule). */
.inner-hero .inner-hero-carousel-controls.inner-hero-media--mobile-only {
  display: none;
}

@media (max-width: 767px) {
  .inner-hero .inner-hero-carousel-controls.inner-hero-media--desktop-only {
    display: none;
  }
  .inner-hero .inner-hero-carousel-controls.inner-hero-media--mobile-only {
    display: flex;
  }
}
/* The pagination inside the controls row: neutralise Swiper's absolute full-width
   positioning so it flows inline next to the pause button. */
.inner-hero .inner-hero-carousel-controls .inner-hero-carousel-pagination {
  position: static;
  width: auto;
  left: auto;
  right: auto;
  bottom: auto;
  transform: none;
  display: flex;
  gap: 0.5rem;
}

/* Arrows (card 55, Yael #27): the house chevron (components/_carousel.scss),
   sized to the controls row — the pause control's box and shadow, the glyph
   at the row's scale (23:41, one base unit tall). Colour follows the dots. */
.inner-hero .inner-hero-carousel-arrow {
  flex: 0 0 auto;
  width: var(--hero-controls-h);
  height: var(--hero-controls-h);
  opacity: 1;
  filter: drop-shadow(0 0 var(--spacing-scale-1) rgba(0, 0, 0, 0.5));
}
.inner-hero .inner-hero-carousel-arrow::before {
  width: calc(var(--spacing-scale-4) * 23 / 41);
  height: var(--spacing-scale-4);
}
.inner-hero .inner-hero-carousel-arrow:hover {
  opacity: 0.8;
}
.inner-hero .inner-hero-carousel-arrow:focus-visible {
  outline-color: currentColor;
}

.inner-hero .inner-hero-carousel-controls.carousel-pagination--dark .inner-hero-carousel-arrow {
  filter: drop-shadow(0 0 var(--spacing-scale-1) rgba(255, 255, 255, 0.6));
}

/* The active dot as a mini timer (card 55, Yael #23): with autoplay it fills
   clockwise over the slide's time (--dot-progress from carousel-init.js), the
   ring stays drawn. Paused = it holds where it is. */
.inner-hero .inner-hero-carousel-pagination.has-progress .carousel-pagination-bullet-active {
  background: conic-gradient(currentColor calc(var(--dot-progress, 1) * 1turn), transparent 0);
}

.inner-hero .carousel-pagination--light .inner-hero-carousel-pagination.has-progress .carousel-pagination-bullet-active {
  color: var(--color-base-white, #fff);
}

.inner-hero .carousel-pagination--dark .inner-hero-carousel-pagination.has-progress .carousel-pagination-bullet-active {
  color: var(--color-base-black, #000);
}

/* Pause/play control — inline in the controls row, next to the dots. */
.inner-hero .inner-hero-carousel-pause {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  color: var(--color-base-white, #fff);
  background: rgba(0, 0, 0, 0.35);
  border: 0;
  border-radius: 50%;
  cursor: pointer;
}
.inner-hero .inner-hero-carousel-pause svg {
  width: 16px;
  height: 16px;
}
.inner-hero .inner-hero-carousel-pause:focus-visible {
  outline: 2px solid var(--color-base-white, #fff);
  outline-offset: 2px;
}
.inner-hero .inner-hero-carousel-pause {
  /* THE BARE GLYPH (card 66, Chuck 2026-10-16 — the same control as the
     Content Video pause): no circle, just the symbol, with a soft shadow for
     light images. It stays in view: it sits in the dots row, which always
     shows. */
  background: none;
  border-radius: 0;
  filter: drop-shadow(0 0 var(--spacing-scale-1) rgba(0, 0, 0, 0.5));
}
.inner-hero .inner-hero-carousel-pause svg rect, .inner-hero .inner-hero-carousel-pause svg polygon {
  fill: currentColor;
}
.inner-hero .inner-hero-carousel-pause {
  /* A finger gets the full touch target (the buttons' rule, as the video's). */
}
@media (pointer: coarse) {
  .inner-hero .inner-hero-carousel-pause {
    width: var(--button-height-md);
    height: var(--button-height-md);
  }
}

/* Dark-dots variant → dark glyph for contrast on light images. */
.inner-hero .inner-hero-carousel-controls.carousel-pagination--dark .inner-hero-carousel-pause {
  color: var(--color-base-black, #000);
  filter: drop-shadow(0 0 var(--spacing-scale-1) rgba(255, 255, 255, 0.6));
}
.inner-hero .inner-hero-carousel-controls.carousel-pagination--dark .inner-hero-carousel-pause:focus-visible {
  outline-color: var(--color-base-black, #000);
}

/* Overlay for darkening media - use shared mixin */
.inner-hero-overlay {
  position: absolute;
  inset: 0;
  z-index: 2;
  background-color: rgba(0, 0, 0, 0.5);
  pointer-events: none;
}

.inner-hero[data-overlay=none] .inner-hero-overlay {
  display: none;
}

.inner-hero[data-overlay=light] .inner-hero-overlay {
  background-color: rgba(0, 0, 0, 0.3);
}

.inner-hero[data-overlay=medium] .inner-hero-overlay {
  background-color: rgba(0, 0, 0, 0.5);
}

.inner-hero[data-overlay=heavy] .inner-hero-overlay {
  background-color: rgba(0, 0, 0, 0.7);
}

/* Content wrapper */
.inner-hero[data-layout=full-image] .inner-hero-content-wrapper {
  position: relative;
  z-index: 3;
  width: 100%;
  padding: var(--spacing-block-md) var(--spacing-section-inline, var(--spacing-container-inline));
  box-sizing: border-box;
}

/* A slideshow with its controls row at the bottom: the text stops one base
   unit above the row, never under the dots (the row is absolute, so nothing
   else holds the text off it). */
.inner-hero[data-layout=full-image]:has(> .inner-hero-carousel-controls:not([data-controls-vertical=top])) .inner-hero-content-wrapper {
  padding-bottom: max(var(--spacing-block-md), var(--hero-controls-inset) + var(--hero-controls-h) + var(--spacing-scale-4));
}

/* Content container */
.inner-hero[data-layout=full-image] .inner-hero-content {
  position: relative;
  z-index: 3;
  max-width: 56rem;
  /* The content-wrapper is a flex container (halign band below). A flex item's
     default min-width is `auto`, so it refuses to shrink below its content's
     intrinsic width — long text then blows past the wrapper's RIGHT padding
     (left holds, right overflows; reported editor + frontend, 2026-08-23).
     min-width:0 lets it shrink within the padding; overflow-wrap breaks a
     single very long token instead of overflowing. */
  min-width: 0;
  overflow-wrap: break-word;
}

/* Horizontal band for full-image: the content-wrapper follows halign. */
.inner-hero[data-layout=full-image][data-halign=center] .inner-hero-content-wrapper {
  display: flex;
  justify-content: center;
}

.inner-hero[data-layout=full-image][data-halign=start] .inner-hero-content-wrapper {
  display: flex;
  justify-content: flex-start;
}

.inner-hero[data-layout=full-image][data-halign=end] .inner-hero-content-wrapper {
  display: flex;
  justify-content: flex-end;
}

/* Art-direction inset off the image's left edge — DESKTOP ONLY, halign:start
   (2026-07-10 mobile walk: at 390px the 2rem floor stacked on the wrapper's
   inline padding = lopsided left vs right). */
@media (min-width: 768px) {
  .inner-hero[data-layout=full-image][data-halign=start] .inner-hero-content {
    padding-left: clamp(2rem, 1rem + 3vw, 6rem);
  }
}

/* Text theme variants */
.inner-hero[data-style*=text-light] .inner-hero-content {
  color: var(--color-base-white, #ffffff);
}

.inner-hero[data-style*=text-light] .inner-hero-eyebrow {
  color: rgba(255, 255, 255, 0.8);
}

.inner-hero[data-style*=text-light] .inner-hero-subheading {
  color: rgba(255, 255, 255, 0.9);
}

.inner-hero[data-style*=text-dark] .inner-hero-content {
  color: var(--color-base-black, #000000);
}

.inner-hero[data-style*=text-dark] .inner-hero-eyebrow {
  color: rgba(0, 0, 0, 0.7);
}

.inner-hero[data-style*=text-dark] .inner-hero-subheading {
  color: rgba(0, 0, 0, 0.8);
}

/* Inline links in hero copy follow the TEXT THEME, not the global link colour.
   theme.json sets a global `a { color: black }` (via a low-specificity :where()
   rule) which otherwise wins over the inherited white — so a link inside a
   white heading rendered BLACK (text + underline). Force links (and their
   underline, which uses currentColor) to the theme colour. EXCLUDE button-links
   (.btn/.wp-block-button__link/.wp-block-artbid-button) — those own their
   styling (same exclusion the split-content contrast rules use). The underline
   itself is the client's requested affordance; only its COLOUR is corrected. */
.inner-hero[data-style*=text-light] .inner-hero-content a:not(.btn):not(.wp-block-button__link):not(.wp-block-artbid-button) {
  color: var(--color-base-white, #ffffff);
  text-decoration-color: currentColor;
}

.inner-hero[data-style*=text-light] .inner-hero-content a:not(.btn):not(.wp-block-button__link):not(.wp-block-artbid-button):hover {
  color: rgba(255, 255, 255, 0.85);
}

.inner-hero[data-style*=text-dark] .inner-hero-content a:not(.btn):not(.wp-block-button__link):not(.wp-block-artbid-button) {
  color: var(--color-base-black, #000000);
  text-decoration-color: currentColor;
}

.inner-hero[data-style*=text-dark] .inner-hero-content a:not(.btn):not(.wp-block-button__link):not(.wp-block-artbid-button):hover {
  color: rgba(0, 0, 0, 0.75);
}

/* ============================================
   COUNTDOWN TIMER (Chunk 2, docs/hero-timer-scope.md)
   A content sub-component: first child of the positioned content, before the
   InnerBlocks. It adds NO positioning of its own — valign/halign/content-fit
   from the rebuilt engine govern where the whole content region (timer +
   InnerBlocks) sits. The timer's own row follows the content's horizontal
   alignment via `justify-content: inherit` off the content's text-align.
   ============================================ */
.inner-hero-timer {
  margin-bottom: var(--spacing-gap-grid-sm, 1.5rem);
  /* THE TIMER NEVER OUTGROWS ITS SPACE (2026-10-20, card 75). The timer is
     an inline-size container: its width comes from the hero column, never
     from the digits (so a big timer can't push a split column off screen),
     and the digits keep their size step until the row would overflow, then
     shrink just enough to fit (four units at 390 on home); a narrow split
     column goes two by two (below). */
  container-type: inline-size;
  --timer-gap: clamp(var(--spacing-scale-4), 0.5rem + 1.5vw, var(--spacing-scale-8));
  --timer-units: 4;
  --timer-pair: 1.36;
}

/* Units on show right now (Days drops under 24 hours; Show Days / Seconds off). */
.inner-hero-timer:has(.inner-hero-timer-unit:nth-child(3):last-child) {
  --timer-units: 3;
}

.inner-hero-timer:has(.inner-hero-timer-unit:nth-child(2):last-child) {
  --timer-units: 2;
}

.inner-hero-timer--font-sans {
  --timer-pair: 1.12;
}

/* A narrow space (the split column at 768, 220 wide): four in a row would
   shrink the digits below their labels ("SECONDS" ≈ 63 at xs). Two by two
   instead, the digits sized for two per row. */
@container (width < 17.5rem) {
  .inner-hero-timer .inner-hero-timer-display {
    display: grid;
    grid-template-columns: repeat(2, max-content);
    --timer-units: 2;
  }
}
/* Avoid the "00 00 00" flash on load: the server renders zeros, then
   countdown-init.js writes the real values and adds `.is-ready`. Hide until
   then. (If JS never runs the timer stays hidden — better than a stuck 00:00.)
   Scoped so it only affects the LIVE timer, never the editor dummy preview
   (which has no JS and should always show). */
.inner-hero-timer[data-end-date]:not(.is-ready) {
  visibility: hidden;
}

.inner-hero-timer-display {
  display: flex;
  /* Last resort only (labels wider than the shrunk digits, or a 3-digit
     hours count): the units wrap rather than spill off the screen. */
  flex-wrap: wrap;
  gap: var(--timer-gap);
  /* Follow the content's horizontal alignment (halign drives text-align on
     the content wrapper). start/center/end all work because these map to
     flex-start/center/flex-end via the keyword. */
  justify-content: flex-start;
}

/* halign → timer row alignment. The engine sets the content's text-align;
   mirror it here so the timer row sits under the same edge as the copy. */
.inner-hero[data-halign=center] .inner-hero-timer-display {
  justify-content: center;
}

.inner-hero[data-halign=end] .inner-hero-timer-display {
  justify-content: flex-end;
}

.inner-hero-timer-unit {
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* Digit typography (walk find TF-1, docs/hero-timer-scope.md §2.1).
   A ticking readout must not bounce vertically (per-digit baseline/height) or
   reflow horizontally (per-digit width). Two independent fixes:

   1. VERTICAL — lining figures. `font-variant-numeric: lining-nums` puts every
      digit on one baseline at cap height. This is FONT work CSS can't fake, and
      it must be applied on the real render path: the Adobe kit DOES deliver
      Loretta's `lnum` (Typekit panel: lnum/onum/frac/liga/ordn/subs/sups
      available; tnum/pnum NOT). Verified via CSS render path (not canvas —
      canvas silently ignores fontFeatureSettings): baseline scatter 12px→1px.

   2. HORIZONTAL — a FIXED cell width, since the kit ships no `tnum` so digits
      stay proportional. `min-width` does NOT hold (the widest pair '00'
      overflows the floor → cell grows). A fixed `width` centered pins every
      value to one box. Measured: the widest two-digit pair is a constant
      1.348em across sizes, so `width: 1.4em` (small headroom) tracks any
      font-size and holds BOTH styles (the sans is narrower, centered fine). */
.inner-hero-timer-value {
  /* Fit = (width − gaps) ÷ (units per row × one pair of digit slots); 100cqi
     = the timer's own width. Declared here so the units count resolves from
     the row (the narrow two-by-two sets 2). */
  --timer-fit: calc((100cqi - (var(--timer-units) - 1) * var(--timer-gap)) / (var(--timer-units) * var(--timer-pair)));
  line-height: 1;
  /* lining-nums (baseline) for both fonts; tabular-nums equalises per-digit
     advance for the SANS (Helvetica has `tnum`), which otherwise sits
     off-centre in its slot. Loretta has no `tnum` — inert there, and its wide
     glyphs already fill the slot. Belt (tnum) + braces (per-digit slots). */
  font-variant-numeric: lining-nums tabular-nums;
  font-feature-settings: "lnum" 1, "tnum" 1;
  /* TWO fixed-width digit slots, not one centered pair (TF-1b). A centered
     proportional pair slides its leading digit as the trailing digit changes
     width (kit has no `tnum`). Per-digit slots = structural tabular. */
  display: inline-flex;
  /* default style = serif (Loretta); --font-* modifiers below switch it. */
  font-family: var(--font-family-display);
  font-weight: var(--font-weight-normal);
}

.inner-hero-timer-digit {
  display: inline-block;
  /* SERIF (Loretta) default: no `tnum`, so its digits have unequal advances.
     A fixed em slot + centre holds them steady (measured 2px, overlay-clean).
     Lining figures (the kit carries `lnum` again since 2026-10-20): the
     widest, 0, is 0.674em, so 0.68em holds every digit and keeps a pair
     reading as one number (0.72em left air inside "02"). */
  width: 0.68em;
  text-align: center;
  /* The timer's top edge IS the top of the figures (Yael, card 75, 2026-10-24:
     "for no spacing, it really needs to be flush against the top of the
     numbers"). Line-height 1 still left the font's own air above the lining
     figures (8 at XL on a laptop); trimming the line to the cap height removes
     it, so Space top None means touching. Browsers without text-box keep
     today's look. */
  text-box: trim-start cap alphabetic;
}

/* Loretta's lining figures stand ~0.1em taller than its capitals (measured: a
   cap trim left them 4–10 px above the box, 0.1em at every size, Chromium and
   WebKit), so the serif gives that back; Helvetica's figures are cap height. */
.inner-hero-timer--font-serif .inner-hero-timer-digit {
  padding-top: 0.1em;
}

/* SANS (Helvetica) HAS `tnum` → every digit shares the "0" advance = 1ch.
   Slot = 1ch and let the tabular metrics seat the glyph (NO forced centre —
   centring re-introduces per-glyph side-bearing offset, which slid the `1`
   visibly). Verified aligned by overlay. */
.inner-hero-timer--font-sans .inner-hero-timer-digit {
  width: 1ch;
  text-align: initial;
}

/* Type style. serif = real Loretta (the display face — its lining figures work
   through the kit, proven above). sans = Helvetica (measured 0px shift), the
   utilitarian alternate. */
.inner-hero-timer--font-serif .inner-hero-timer-value {
  font-family: var(--font-family-display);
}

.inner-hero-timer--font-sans .inner-hero-timer-value {
  font-family: var(--font-family-sans);
}

/* Digit weight. Reference the weight tokens so a primitive change propagates;
   500 (medium) has no token, so it stays a raw numeric (the one exception). */
.inner-hero-timer--weight-light .inner-hero-timer-value {
  font-weight: var(--font-weight-light);
}

.inner-hero-timer--weight-regular .inner-hero-timer-value {
  font-weight: var(--font-weight-normal);
}

.inner-hero-timer--weight-medium .inner-hero-timer-value {
  font-weight: 500;
}

.inner-hero-timer--weight-bold .inner-hero-timer-value {
  font-weight: var(--font-weight-bold);
}

/* Timer digit sizes. Width is font-relative (the digit slots), so size only
   sets font-size — the cell scales with it and stays fixed-per-value. Each
   step is capped by --timer-fit (above): the size holds until the row would
   overflow its space, then shrinks to fit. */
.inner-hero-timer--sm .inner-hero-timer-value {
  font-size: min(clamp(2rem, 1.75rem + 0.75vw, 2.5rem), var(--timer-fit));
}

.inner-hero-timer--md .inner-hero-timer-value {
  font-size: min(clamp(2.5rem, 2rem + 1.5vw, 3.5rem), var(--timer-fit));
}

.inner-hero-timer--lg .inner-hero-timer-value {
  font-size: min(clamp(3rem, 2.5rem + 2vw, 4.5rem), var(--timer-fit));
}

/* XL / 2XL (Yael 2026-09-14, punchlist #10): continue the ladder — each step
   ~1.3× the last at both ends of the clamp. */
.inner-hero-timer--xl .inner-hero-timer-value {
  font-size: min(clamp(3.75rem, 3rem + 2.75vw, 6rem), var(--timer-fit));
}

.inner-hero-timer--2xl .inner-hero-timer-value {
  font-size: min(clamp(4.5rem, 3.5rem + 3.75vw, 8rem), var(--timer-fit));
}

/* Word labels (Days/Hours/…) — JZ-023: size is a control, independent of the
   digit size. Three steps mapped to the theme's font-size scale. */
.inner-hero-timer-name {
  /* The label never widens its unit: a zero-width row, the word centred and
     free to run a little into the gap, so a unit is exactly its two digit
     slots and the fit above is exact. */
  display: flex;
  justify-content: center;
  width: 0;
  white-space: nowrap;
  text-transform: uppercase;
  letter-spacing: var(--font-letterSpacing-wider);
  margin-top: 0.25rem;
  opacity: 0.75;
}

/* …and the timer's bottom edge IS the labels' baseline (same card: "same with
   the bottom"): the air under the capitals goes, so Space bottom None touches.
   The word sits in its own block (text-box needs one; the label itself is a
   zero-width flex row that centres it). */
.inner-hero-timer-word {
  display: block;
  text-box: trim-end cap alphabetic;
}

.inner-hero-timer--label-xs .inner-hero-timer-name {
  font-size: var(--font-size-xs);
}

.inner-hero-timer--label-sm .inner-hero-timer-name {
  font-size: var(--font-size-sm);
}

.inner-hero-timer--label-md .inner-hero-timer-name {
  font-size: var(--font-size-base);
}

/* Label typography (2026-08-23): style + weight, mirroring the digit controls.
   Only emitted when the author picks a non-default value — the 'inherit' default
   emits NO class so labels inherit the site font/weight exactly as before. */
.inner-hero-timer--label-font-serif .inner-hero-timer-name {
  font-family: var(--font-family-display);
}

.inner-hero-timer--label-font-sans .inner-hero-timer-name {
  font-family: var(--font-family-sans);
}

.inner-hero-timer--label-weight-light .inner-hero-timer-name {
  font-weight: var(--font-weight-light);
}

.inner-hero-timer--label-weight-regular .inner-hero-timer-name {
  font-weight: var(--font-weight-normal);
}

.inner-hero-timer--label-weight-medium .inner-hero-timer-name {
  font-weight: 500;
}

.inner-hero-timer--label-weight-bold .inner-hero-timer-name {
  font-weight: var(--font-weight-bold);
}

/* Independent timer alignment (2026-08-23): decouple the row from the hero's
   halign. data-timer-align on the timer element wins over the hero-halign rules
   above (more specific: it targets the timer node directly). 'inherit' emits no
   attr → the hero-halign rules apply (today's behaviour). */
.inner-hero-timer[data-timer-align=left] .inner-hero-timer-display {
  justify-content: flex-start;
}

.inner-hero-timer[data-timer-align=center] .inner-hero-timer-display {
  justify-content: center;
}

.inner-hero-timer[data-timer-align=right] .inner-hero-timer-display {
  justify-content: flex-end;
}

/* Aligned to the HEADING'S TEXT (card 75, Chuck 2026-10-25): with a heading in
   the hero, _shared/js/timer-heading-align.js measures where the heading's
   lines start and end and sets --timer-offset; the numbers keep their own
   width and sit at that offset (Left = from the text's start, Right = to its
   end, Centre = on it). Without the script (or no heading) the rules above
   apply unchanged. */
/* LABEL ALIGNMENT (card 75, Chuck 2026-10-25: "the labels are just always
   centred, they don't left align with the number or right align"). Its own
   setting beside the other label controls; default Centre = under the middle
   of the number, as always. Left = each word starts at its number's left edge,
   Right = ends at its right edge. The label is a zero-width row, so the unit
   puts it on the edge and the word runs inward. */
.inner-hero-timer[data-label-align=left] .inner-hero-timer-unit {
  align-items: flex-start;
}

.inner-hero-timer[data-label-align=left] .inner-hero-timer-name {
  justify-content: flex-start;
}

.inner-hero-timer[data-label-align=right] .inner-hero-timer-unit {
  align-items: flex-end;
}

.inner-hero-timer[data-label-align=right] .inner-hero-timer-name {
  justify-content: flex-end;
}

.inner-hero-timer[data-heading-aligned] .inner-hero-timer-display {
  width: max-content;
  max-width: 100%;
  margin-inline-start: var(--timer-offset, 0px);
  justify-content: flex-start;
}

/* Auto-hide at zero (2026-08-23): countdown-init.js adds .is-expired when the
   countdown reaches 0 (or loads after the auction ended). Hide completely rather
   than sit at 00:00. Live timer only — the editor dummy has no JS. */
.inner-hero-timer.is-expired {
  display: none;
}

/* Colour follows the block's text theme, same pattern the headings use. */
.inner-hero[data-style*=text-light] .inner-hero-timer-value,
.inner-hero[data-style*=text-light] .inner-hero-timer-name {
  color: var(--color-base-white, #fff);
}

.inner-hero[data-style*=text-dark] .inner-hero-timer-value,
.inner-hero[data-style*=text-dark] .inner-hero-timer-name {
  color: var(--color-base-black, #000);
}

/* ============================================
   HEIGHT VARIANTS
   Applied via shared block-heights mixin.
   All presets are MINIMUMS so content-fit:flow can grow the box (F3).
   ============================================ */
.inner-hero[data-height=auto] {
  height: auto;
  min-height: auto;
}
.inner-hero[data-height=narrow] {
  min-height: max(var(--layout-height-narrow), var(--layout-minHeight-sm));
}
.inner-hero[data-height=half] {
  min-height: max(var(--layout-height-half), var(--layout-minHeight-md));
}
.inner-hero[data-height=two-thirds] {
  min-height: max(var(--layout-height-two-thirds), var(--layout-minHeight-lg));
}
.inner-hero[data-height=three-quarters] {
  min-height: max(var(--layout-height-three-quarters), var(--layout-minHeight-lg));
}
.inner-hero[data-height=full] {
  min-height: max(var(--layout-height-full), var(--layout-minHeight-xl));
  height: var(--layout-height-full);
}
@media (max-width: 767px) {
  .inner-hero[data-height=narrow] {
    min-height: var(--layout-minHeight-sm);
  }
  .inner-hero[data-height=half] {
    min-height: var(--layout-minHeight-md);
  }
  .inner-hero[data-height=two-thirds] {
    min-height: var(--layout-minHeight-md);
  }
  .inner-hero[data-height=three-quarters] {
    min-height: var(--layout-minHeight-lg);
  }
  .inner-hero[data-height=full] {
    min-height: var(--layout-minHeight-lg);
  }
}

/* content-fit: flow requires ALL presets to be minimums. The shared
   block-heights mixin hard-sets `height: 100vh` on `full` (it's shared with
   other blocks — do not edit the mixin, F-E). Override it here so the hero's
   `full` can grow with content instead of clipping. */
.inner-hero[data-height=full] {
  height: auto;
  min-height: max(var(--layout-height-full), var(--layout-minHeight-xl));
}
@media (max-width: 767px) {
  .inner-hero[data-height=full] {
    min-height: var(--layout-minHeight-lg);
  }
}

/* ============================================
   MOBILE HEIGHT OVERRIDE (Slice 5, 2026-09-14 — hero-mobile-overrides-scope)
   data-height-mobile only exists with customizeMobile + a value; absent =
   the mixin's mobile floors (today). Full-image/text-only: the block.
   Split: the media side. Last in the file on purpose (source order beats the
   mixin's mobile branch and the [data-height="full"] override above).
   ============================================ */
@media (max-width: 767px) {
  .inner-hero[data-height-mobile=auto] {
    height: auto;
    min-height: auto;
  }
  .inner-hero[data-height-mobile=narrow] {
    height: auto;
    min-height: max(var(--layout-height-narrow), var(--layout-minHeight-xs));
  }
  .inner-hero[data-height-mobile=half] {
    height: auto;
    min-height: max(var(--layout-height-half), var(--layout-minHeight-xs));
  }
  .inner-hero[data-height-mobile=two-thirds] {
    height: auto;
    min-height: max(var(--layout-height-two-thirds), var(--layout-minHeight-xs));
  }
  .inner-hero[data-height-mobile=three-quarters] {
    height: auto;
    min-height: max(var(--layout-height-three-quarters), var(--layout-minHeight-xs));
  }
  .inner-hero[data-height-mobile=full] {
    height: auto;
    min-height: max(var(--layout-height-full), var(--layout-minHeight-xs));
  }
  /* Split: the block hugs its two stacked sides; the MEDIA side takes the height. */
  .inner-hero[data-layout=split][data-height-mobile] {
    min-height: auto;
  }
  .inner-hero[data-layout=split][data-height-mobile=auto] .inner-hero-split-media {
    height: var(--layout-minHeight-sm);
    min-height: 0;
  }
  .inner-hero[data-layout=split][data-height-mobile=narrow] .inner-hero-split-media {
    height: max(var(--layout-height-narrow), var(--layout-minHeight-xs));
    min-height: 0;
  }
  .inner-hero[data-layout=split][data-height-mobile=half] .inner-hero-split-media {
    height: var(--layout-height-half);
    min-height: 0;
  }
  .inner-hero[data-layout=split][data-height-mobile=two-thirds] .inner-hero-split-media {
    height: var(--layout-height-two-thirds);
    min-height: 0;
  }
  .inner-hero[data-layout=split][data-height-mobile=three-quarters] .inner-hero-split-media {
    height: var(--layout-height-three-quarters);
    min-height: 0;
  }
  .inner-hero[data-layout=split][data-height-mobile=full] .inner-hero-split-media {
    height: var(--layout-height-full);
    min-height: 0;
  }
}
/* ============================================
   LANE 21 — the FREE content model (2026-09-30; artbid-v2
   docs/plan/wp-sidebar-architecture-scope.md §4.4/§4.5).
   Every rule below keys on something a LEGACY hero never emits
   (data-line-align · data-distribute · data-content-model="free" ·
   data-phone-reorder · data-arrangement · data-align · data-hide-phone ·
   .ab-hide-phone), so every hero saved before 1.9.53 renders exactly as before.
   ============================================ */
/* ALIGNMENT — how LINES sit inside the text group (position moves the group).
   Later + equal specificity to the positioning mixin's `text-align: left`. */
.inner-hero[data-line-align=left],
.inner-hero[data-line-align=left] .inner-hero-split-content {
  text-align: left;
}

.inner-hero[data-line-align=center],
.inner-hero[data-line-align=center] .inner-hero-split-content {
  text-align: center;
}

.inner-hero[data-line-align=right],
.inner-hero[data-line-align=right] .inner-hero-split-content {
  text-align: right;
}

/* Justify (2026-11-07, Yael's artist page draft): the system's Justify, as the
   shared text-alignment mixin: both edges flush, the last line left, hyphenated;
   headings stay left with their natural spacing. */
.inner-hero:is([data-line-align=justify], [data-line-align=justify-center], [data-line-align=justify-right]),
.inner-hero:is([data-line-align=justify], [data-line-align=justify-center], [data-line-align=justify-right]) .inner-hero-split-content {
  text-align: justify;
  text-align-last: left;
  hyphens: auto;
  -webkit-hyphens: auto;
}
.inner-hero:is([data-line-align=justify], [data-line-align=justify-center], [data-line-align=justify-right]) :is(h1, h2, h3, h4, h5, h6),
.inner-hero:is([data-line-align=justify], [data-line-align=justify-center], [data-line-align=justify-right]) .inner-hero-split-content :is(h1, h2, h3, h4, h5, h6) {
  text-align: left;
  text-align-last: auto;
  hyphens: manual;
  -webkit-hyphens: manual;
}

/* Last line centred / right (2026-11-13, Yael's Text Block card): the same Justify. */
.inner-hero[data-line-align=justify-center],
.inner-hero[data-line-align=justify-center] .inner-hero-split-content {
  text-align-last: center;
}

.inner-hero[data-line-align=justify-right],
.inner-hero[data-line-align=justify-right] .inner-hero-split-content {
  text-align-last: right;
}

/* TEXT WIDTH (2026-11-07, Yael's artist page draft; Chuck): the ONE measure
   list (Narrow 65ch · Medium 80ch · Wide 100ch · Full), as Image & Text. No
   data-text-width = the width every hero had before. Beside the image the half
   is narrower than every measure, so there a width is a SHARE of the text side
   (Narrow 65% · Medium 80% · Wide 90%), still capped by its measure, and the
   text position places it. Stacked on a phone: the measure alone. */
.inner-hero[data-text-width=xx-narrow] .inner-hero-content,
.inner-hero[data-text-width=xx-narrow] .inner-hero-split-content-inner {
  max-width: var(--layout-container-prose-xx-narrow);
}

@media (min-width: 768px) {
  .inner-hero[data-text-width=xx-narrow] .inner-hero-split-content-inner {
    max-width: min(var(--layout-container-prose-xx-narrow), 40%);
  }
}
.inner-hero[data-text-width=x-narrow] .inner-hero-content,
.inner-hero[data-text-width=x-narrow] .inner-hero-split-content-inner {
  max-width: var(--layout-container-prose-x-narrow);
}

@media (min-width: 768px) {
  .inner-hero[data-text-width=x-narrow] .inner-hero-split-content-inner {
    max-width: min(var(--layout-container-prose-x-narrow), 50%);
  }
}
.inner-hero[data-text-width=narrow] .inner-hero-content,
.inner-hero[data-text-width=narrow] .inner-hero-split-content-inner {
  max-width: var(--layout-container-prose);
}

@media (min-width: 768px) {
  .inner-hero[data-text-width=narrow] .inner-hero-split-content-inner {
    max-width: min(var(--layout-container-prose), 65%);
  }
}
.inner-hero[data-text-width=medium] .inner-hero-content,
.inner-hero[data-text-width=medium] .inner-hero-split-content-inner {
  max-width: var(--layout-container-prose-medium);
}

@media (min-width: 768px) {
  .inner-hero[data-text-width=medium] .inner-hero-split-content-inner {
    max-width: min(var(--layout-container-prose-medium), 80%);
  }
}
.inner-hero[data-text-width=wide] .inner-hero-content,
.inner-hero[data-text-width=wide] .inner-hero-split-content-inner {
  max-width: var(--layout-container-prose-wide);
}

@media (min-width: 768px) {
  .inner-hero[data-text-width=wide] .inner-hero-split-content-inner {
    max-width: min(var(--layout-container-prose-wide), 90%);
  }
}
.inner-hero[data-text-width=full] .inner-hero-content,
.inner-hero[data-text-width=full] .inner-hero-split-content-inner {
  max-width: none;
}

/* Buttons + timer without their own alignment follow the LINES (FREE only;
   a legacy hero keeps following the position). No data-line-align = the
   legacy forced-left lines, so they sit left. */
.inner-hero[data-content-model=free] .inner-hero-buttons:not([data-align]) {
  justify-content: flex-start;
}

.inner-hero[data-content-model=free][data-line-align=center] .inner-hero-buttons:not([data-align]) {
  justify-content: center;
}

.inner-hero[data-content-model=free][data-line-align=right] .inner-hero-buttons:not([data-align]) {
  justify-content: flex-end;
}

.inner-hero[data-content-model=free] .inner-hero-buttons[data-align=left] {
  justify-content: flex-start;
}

.inner-hero[data-content-model=free] .inner-hero-buttons[data-align=center] {
  justify-content: center;
}

.inner-hero[data-content-model=free] .inner-hero-buttons[data-align=right] {
  justify-content: flex-end;
}

.inner-hero[data-content-model=free] .inner-hero-timer:not([data-timer-align]) .inner-hero-timer-display {
  justify-content: flex-start;
}

.inner-hero[data-content-model=free][data-line-align=center] .inner-hero-timer:not([data-timer-align]) .inner-hero-timer-display {
  justify-content: center;
}

.inner-hero[data-content-model=free][data-line-align=right] .inner-hero-timer:not([data-timer-align]) .inner-hero-timer-display {
  justify-content: flex-end;
}

/* Button ARRANGEMENT on the Buttons block (FREE). Same behaviour as the
   legacy hero-root rules above; equal needs 2+ buttons (#16). */
@media (min-width: 768px) {
  .inner-hero[data-content-model=free] .inner-hero-buttons[data-arrangement=equal]:has(> .wp-block-artbid-button + .wp-block-artbid-button) {
    display: grid;
    grid-auto-flow: column;
    grid-template-columns: repeat(2, 1fr);
    width: fit-content;
    max-width: 100%;
    justify-content: inherit;
  }
  .inner-hero[data-content-model=free] .inner-hero-buttons[data-arrangement=equal]:has(> .wp-block-artbid-button + .wp-block-artbid-button) .wp-block-artbid-button {
    width: 100%;
  }
  .inner-hero[data-content-model=free] .inner-hero-buttons[data-arrangement=equal]:has(> .wp-block-artbid-button + .wp-block-artbid-button) .btn {
    width: 100%;
  }
  .inner-hero[data-content-model=free][data-line-align=center] .inner-hero-buttons[data-arrangement=equal]:not([data-align]),
  .inner-hero[data-content-model=free] .inner-hero-buttons[data-arrangement=equal][data-align=center] {
    margin-left: auto;
    margin-right: auto;
  }
  .inner-hero[data-content-model=free][data-line-align=right] .inner-hero-buttons[data-arrangement=equal]:not([data-align]),
  .inner-hero[data-content-model=free] .inner-hero-buttons[data-arrangement=equal][data-align=right] {
    margin-left: auto;
    margin-right: 0;
  }
  .inner-hero[data-content-model=free] .inner-hero-buttons[data-arrangement=stacked] {
    flex-direction: column;
    align-items: stretch;
  }
  .inner-hero[data-content-model=free] .inner-hero-buttons[data-arrangement=stacked] .wp-block-artbid-button,
  .inner-hero[data-content-model=free] .inner-hero-buttons[data-arrangement=stacked] .btn {
    width: 100%;
  }
}
/* DISTRIBUTE: spread — the content fills the band and its elements space out
   top to bottom. Only with a set height (auto hugs the content → = packed). */
.inner-hero[data-distribute=spread]:not([data-height=auto]) .inner-hero-content-wrapper,
.inner-hero[data-distribute=spread]:not([data-height=auto]) .inner-hero-split-content-inner {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
}
.inner-hero[data-distribute=spread]:not([data-height=auto]) .inner-hero-content,
.inner-hero[data-distribute=spread]:not([data-height=auto]) .inner-hero-split-content-inner {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

/* PHONES (<768px): per-block hide + order (rule 7). */
@media (max-width: 767px) {
  .inner-hero .ab-hide-phone,
  .inner-hero [data-hide-phone=true] {
    display: none !important;
  }
  .inner-hero[data-phone-reorder=true] .inner-hero-content,
  .inner-hero[data-phone-reorder=true] .inner-hero-split-content-inner {
    display: flex;
    flex-direction: column;
    align-items: stretch;
  }
  .inner-hero[data-phone-reorder=true] .inner-hero-content > *,
  .inner-hero[data-phone-reorder=true] .inner-hero-split-content-inner > * {
    order: var(--po, 99);
  }
}
