/* =========================================================
   STORM — SPI MEDIA
   -----------------------------------------------------------
   Loads ON TOP of base-web-style.css.

   FROM BASE, unchanged:
     hero       .spi-banner.is-overlay
     shell      .spi-section-full / .spi-section-padded /
                .spi-container / .spi-section-header
     type       .spi-h1 / .spi-display / .spi-h2 / .spi-h3 /
                .spi-body / .spi-eyebrow / .spi-meta / .spi-tag
     rows       .spi-row.spi-scroll.is-aligned
     video card .spi-card-video / .spi-video-thumb / .spi-play /
                .spi-video-title
     article    .spi-card-article (+ -img / -body)
     filters    .spi-toggle + button.active
     search     .spi-input
     button     .btn.default
     lightbox   spi-video-modal.js (shared; builds its own overlay,
                so this page carries no modal markup at all)

   What is left is the spacing of the stacked rows, the filter
   bar's own layout, the mixed grid, and the states a fetched
   page needs. The filter bar is NOT base's: see the note in
   section 3.

   No tokens are redefined and no colours are invented.
   ========================================================= */

/* ---------------------------------------------------------
   1. HERO
--------------------------------------------------------- */
/* The knobs are MINIMUM heights: the band never gets shorter than
   its content plus padding. .spi-section-full adds 72px above and
   below (40px on phones) on top of .spi-banner-content's own 64px
   (32 / 16), which held this banner at 407px however low the knob
   was set. The content's padding is the inset on its own, so the
   title sits as far from the bottom edge as from the side. */
.media-hero {
  --spi-banner-h: 300px;
  --spi-banner-h-tablet: 300px;
  --spi-banner-h-mobile: 280px;
  padding-top: 0;
  padding-bottom: 0;
}

.media-hero .spi-banner-content .spi-body {
  max-width: 640px;
}

/* ---------------------------------------------------------
   2. THE ROW STACK (.media-row)
   Three carousels in a row is one list, not three chapters, so
   they should not each carry a full section's padding at both
   ends: base's two section paddings plus the 48px under
   .spi-scroll came to 192px between one row and the next heading.

   Each section drops the padding below it, and a row that follows
   another row keeps only --spi-gap (24px) above, so one row's
   titles sit 32px from the next heading at every width (Dylan
   asked for tighter; it was 80px, 48px on phones). The first row
   keeps a full section's padding under the banner. The 8px left
   under the cards is room for the 4px focus ring, which
   .spi-scroll's overflow would otherwise clip.
--------------------------------------------------------- */
.media-row {
  padding-bottom: 0;
}

.media-row + .media-row {
  padding-top: var(--spi-gap);
}

.media-row .spi-scroll {
  padding-bottom: 8px;
}

/* Base sizes a video card at 320px at every width, which is wider
   than the row on a 320px phone. This is the 78% base gives every
   other card in a .spi-scroll on a phone, with the 320px kept as
   the ceiling so a large phone doesn't get a larger card. */
@media (max-width: 600px) {
  .media-row .spi-scroll {
    --spi-row-w: min(320px, 78%);
  }
}

/* Loading. A row's cards come from YouTube after the page has
   painted, so on a first visit (or once the 24h cache runs out) the
   row was one "Loading videos…" line that then grew by a card's
   height, and every heading below dropped ~180px, three times over —
   an estimated layout shift of 0.19 at 375px and 0.31 at 600px. The
   notice now sits INSIDE the row, centred across it, and the row
   holds one card's height until the cards replace the notice. */
.media-row .spi-scroll > .media-notice {
  flex: 0 0 100%;
  align-self: center;
}

/* An invisible stand-in card, only while the notice is there: the
   row's card width, a 16:9 thumbnail, and 50px for the 12px gap and
   a two-line title. It sits past the right edge, like any card that
   runs off a scroller. */
.media-row .spi-scroll:has(> .media-notice)::after {
  content: "";
  flex: 0 0 var(--spi-row-w, 320px);
  aspect-ratio: 16 / 9;
  margin-bottom: 50px;
}

/* ---------------------------------------------------------
   3. FILTER BAR (.media-filter-bar)
   Three pill groups and a search field. The CONTROLS are all
   base — .spi-toggle and .spi-input — and the shell is base's
   .spi-section-padded; only the bar's own layout is here.

   Deliberately NOT shared with Pro Staff's .ps-filter-bar even
   though both are filter bars: that one is sticky, full-bleed
   and carries two groups; this one is in the page flow, inside
   the container, and carries three groups plus a heading. The
   part that genuinely repeats is .spi-toggle, and that is
   already in base.
--------------------------------------------------------- */
.media-filter-bar {
  padding-bottom: 24px;
  border-bottom: 1px solid var(--spi-border);
}

.media-filter-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 16px 32px;
}

/* <fieldset> names the group for a screen reader but brings a
   border and padding of its own. */
.media-filter-group {
  border: 0;
  margin: 0;
  padding: 0;
  min-width: 0;
}

.media-filter-group > legend,
.media-filter-group > label {
  display: block;
  padding: 0;
  margin-bottom: 8px;
}

/* Base centres .spi-toggle; in a left-aligned control bar the
   pills should start at the label. Topic has thirteen of them,
   so this group is allowed to take a full row of its own. */
.media-filter-group .spi-toggle {
  justify-content: flex-start;
}

.media-filter-topic {
  flex: 1 1 100%;
}

.media-search-group {
  margin-left: auto;
}

.media-search {
  min-width: 240px;
}

@media (max-width: 1024px) {
  .media-search-group {
    margin-left: 0;
    flex: 1 1 100%;
  }
}

@media (max-width: 600px) {
  .media-filter-bar {
    padding-bottom: 16px;
  }

  .media-filter-inner {
    gap: 12px;
  }

  /* Thirteen topic pills stacked would bury the grid they filter,
     so each group scrolls sideways instead — the same trade base
     makes in .spi-subnav. */
  .media-filter-group .spi-toggle {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    padding-bottom: 2px;
  }

  .media-filter-group .spi-toggle::-webkit-scrollbar {
    display: none;
  }

  .media-filter-group .spi-toggle button {
    flex: 0 0 auto;
    /* Base sizes a toggle pill at 33px, which is a reviewed
       decision, so it is raised here rather than in base: on a
       phone these pills are how the page is navigated. */
    min-height: 44px;
    white-space: nowrap;
  }
}

/* ---------------------------------------------------------
   4. THE MIXED GRID (.media-grid)
   Videos are 16/9 and articles are 16/10, so the cards are not
   the same shape. auto-fill on one track width keeps the columns
   aligned and lets the two card types sit in the same flow —
   base's fixed .spi-grid-4 would force a column count that does
   not suit a feed this long.

   The track is 260px, or half the row if that is smaller, so the
   feed never drops to one column on any screen. Two fixed tracks
   switched at 600px gave four 133px columns at 600 and a single
   537px one at 601 — a 123,000px page.
--------------------------------------------------------- */
.media-grid {
  --media-gap: var(--spi-gap);
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(260px, calc((100% - var(--media-gap)) / 2)), 1fr));
  gap: var(--media-gap);
  align-items: start;
}

@media (max-width: 600px) {
  .media-grid {
    --media-gap: var(--spi-gap-sm);
  }
}

/* ---------------------------------------------------------
   5. CARDS
   Both card types are base's; these are the things a card in a
   filtered, clickable feed needs that a static one does not.
--------------------------------------------------------- */
.media-card {
  transition: var(--spi-ease);
}

/* MUST stay: base's .spi-card-video sets display:block, and an
   author class beats the browser's built-in [hidden]{display:none}.
   The filters and search hide cards with the hidden attribute, so
   without this the count changes and every video stays on screen. */
.media-card[hidden] {
  display: none;
}

.media-card:hover {
  transform: translateY(-3px);
}

.media-card:focus-visible {
  outline: 2px solid var(--spi-accent);
  outline-offset: 2px;
}

.media-article:hover {
  border-color: var(--spi-gray-400);
}

/* An article card's headline: 15px, sentence case — the same call
   Newsroom made for the same feed. It is an <h3> (it sits under the
   section's h2), and on the live site the store theme restyles a
   bare h3 as 32px / 900 / uppercase with a 16px margin; this
   selector out-ranks the theme's `h3`, so no !important is needed. */
.media-article .spi-card-article-body h3 {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.4;
  text-transform: none;
}

/* The live theme zeroes paragraph margins and a local preview does
   not. Declared so a card's label sits the same in both. */
.media-card .spi-meta {
  margin: 0;
}

@media (prefers-reduced-motion: reduce) {
  .media-card,
  .media-card:hover {
    transition: none;
    transform: none;
  }
}

/* ---------------------------------------------------------
   6. COUNT, NOTICES, EMPTY STATE
   The old page had no empty state: filter down to nothing and
   the grid just went blank.
--------------------------------------------------------- */

/* The results belong to the filter bar directly above them, so
   the count sits as close to the bar as it does to the grid. */
.media-results {
  padding-top: var(--spi-gap);
}

.media-count {
  margin: 0 0 24px;
}

.media-notice {
  margin: 0;
  padding: 24px 0;
  text-align: center;
}

.media-empty {
  padding: 56px 24px;
  text-align: center;
}

.media-empty .spi-body {
  margin: 8px 0 20px;
}
