/* stories.css
 *
 * Homepage Stories section + video <dialog> modal. Sits after Highlights;
 * shipped 2026-05-15 for the grant launch.
 *
 * BEM blocks: .stories, .story-card, .video-modal, .courses-cta
 * Tokens from base.css :root. No new variables defined here.
 */

/* ── Stories section ── */

.stories {
  position: relative;
  overflow: hidden;
  padding-block: var(--section-py);   /* Phase 8: standardized section rhythm */
  background: var(--color-surface-subtle);
}

.stories__inner {
  position: relative;
  z-index: 2;
  text-align: center;
}

.stories__header {
  margin-bottom: var(--spacing-3xl);
}

.stories__title {
  font-size: clamp(2.25rem, 5vw, 3.5rem);
  font-weight: var(--font-weight-extrabold);
  margin-bottom: var(--spacing-sm);
}

.stories__subtitle {
  max-width: 36rem;
  margin: 0 auto var(--spacing-lg);
  font-size: clamp(1rem, 2.5vw, 1.25rem);
  color: var(--color-text-light);
  font-weight: var(--font-weight-medium);
}

.stories__divider {
  width: 120px;
  height: var(--width-accent-line-thin);
  margin: 0 auto;
  background: linear-gradient(
    90deg,
    transparent,
    var(--color-secondary),
    var(--color-primary),
    var(--color-secondary),
    transparent
  );
}

.stories__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--spacing-xl);
  margin-top: var(--spacing-2xl);
}

@media (min-width: 640px) {
  .stories__grid {
    grid-template-columns: repeat(2, 1fr);
    gap: var(--spacing-xl);
  }
}

@media (min-width: 1024px) {
  .stories__grid {
    grid-template-columns: repeat(4, 1fr);
    gap: calc(var(--spacing-xl) + var(--spacing-sm));
  }
}

/* ── Story card ── */

.story-card {
  position: relative;
  display: flex;
  flex-direction: column;
  text-align: left;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-2xl);
  box-shadow: var(--shadow-card-glass);
  cursor: pointer;
  overflow: hidden;
  transition:
    transform 0.4s cubic-bezier(0.4, 0, 0.2, 1),
    box-shadow 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}

.story-card:hover,
.story-card:focus-within {
  transform: translateY(-6px);
  box-shadow: var(--shadow-xl);
}

.story-card__media {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--color-surface-subtle);
}

.story-card__poster {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}

.story-card:hover .story-card__poster,
.story-card:focus-within .story-card__poster {
  transform: scale(1.04);
}

/* Play-button overlay — pure CSS triangle inside a circular brand-gradient
   button. Centered absolutely over the poster. */
.story-card__play {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 72px;
  height: 72px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: var(--radius-full);
  background: linear-gradient(
    135deg,
    var(--color-primary),
    var(--color-secondary)
  );
  color: var(--color-text-inverse);
  box-shadow:
    0 12px 32px var(--color-primary-alpha-40),
    inset 0 2px 0 var(--color-overlay-white-border);
  cursor: pointer;
  transition:
    transform 0.3s cubic-bezier(0.4, 0, 0.2, 1),
    box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Soft, expanding ripple ring around the play button — at-rest pulse so the
   Stories section reads as "alive". Pure pseudo-element so it composes with
   the button's own box-shadow halo without fighting it. */
.story-card__play::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: 0 0 0 0 var(--color-overlay-white-soft);
  pointer-events: none;
  animation: story-play-pulse 2.4s ease-out infinite;
}

@keyframes story-play-pulse {
  0% {
    box-shadow: 0 0 0 0 var(--color-overlay-white-soft);
    opacity: 0.9;
  }
  100% {
    box-shadow: 0 0 0 18px var(--color-overlay-white-faint);
    opacity: 0;
  }
}

.story-card:hover .story-card__play,
.story-card:focus-within .story-card__play {
  transform: scale(1.08);
  box-shadow:
    0 16px 40px var(--color-primary-alpha-50),
    inset 0 2px 0 var(--color-overlay-white-shine);
}

.story-card__play:focus-visible {
  outline: 3px solid var(--color-secondary);
  outline-offset: 4px;
}

/* CSS triangle, optically nudged 4px right so it appears centered in the
   circular button (visual center of a triangle is left of geometric center). */
.story-card__play-icon {
  display: block;
  width: 0;
  height: 0;
  margin-left: 4px;
  border-style: solid;
  border-width: 12px 0 12px 20px;
  border-color: transparent transparent transparent currentColor;
}

.story-card__body {
  padding: var(--spacing-md) var(--spacing-lg) var(--spacing-lg);
}

.story-card__title {
  font-size: clamp(1rem, 2vw, 1.125rem);
  font-weight: var(--font-weight-semibold);
  color: var(--color-text);
  line-height: 1.4;
  margin: 0;
}

/* ── Stories cinematic variant — premium video tiles ──
 * Scoped to the .story-card--cinematic modifier so the Promos section's
 * plain .story-card is left untouched. The poster fills the full rounded card
 * face with a dead-centered play button; the on-card title is hidden (still
 * shown in the player). On hover the .fx-grad-border ring brightens, a brand
 * tinted shadow lifts the card, and a sheen sweeps across the poster.
 */
.story-card--cinematic {
  overflow: visible; /* let the .fx-grad-border ring sit outside the card */
  border: none;
  background: transparent;
}

.story-card--cinematic .story-card__media {
  border-radius: var(--radius-2xl); /* media is the full card face */
}

.story-card--cinematic .story-card__play {
  z-index: 4; /* above the sheen + caption (they can get close on small cards) */
}

/* Diagonal sheen that sweeps across the poster once on hover/focus. */
.story-card--cinematic .story-card__media::before {
  content: "";
  position: absolute;
  top: -10%;
  left: -70%;
  width: 45%;
  height: 120%;
  z-index: 2;
  background: linear-gradient(
    100deg,
    transparent 0%,
    var(--color-overlay-white-soft) 50%,
    transparent 100%
  );
  transform: skewX(-16deg);
  pointer-events: none;
  opacity: 0;
}

.story-card--cinematic:hover .story-card__media::before,
.story-card--cinematic:focus-within .story-card__media::before {
  animation: story-sheen 0.9s ease-out;
}

@keyframes story-sheen {
  0% {
    left: -70%;
    opacity: 0;
  }
  18% {
    opacity: 1;
  }
  100% {
    left: 130%;
    opacity: 0;
  }
}

/* Title hidden on the card face for now (kept in the DOM for screen readers;
   the play button's aria-label names each video, and the title still shows in
   the video-player caption). With no caption, the play button sits dead-center
   over a clean poster. To restore the on-card glass caption, reinstate the
   absolute gradient bar here. */
.story-card--cinematic .story-card__body {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Conic brand-gradient ring (.fx-grad-border): faint at rest, full on hover. */
.story-card--cinematic.fx-grad-border::before {
  opacity: 0.28;
  transition: opacity 0.4s ease;
}

.story-card--cinematic.fx-grad-border:hover::before,
.story-card--cinematic.fx-grad-border:focus-within::before {
  opacity: 1;
}

.story-card--cinematic:hover,
.story-card--cinematic:focus-within {
  box-shadow: var(--shadow-card-brand);
}

/* Staggered entrance: the shared .stagger cascade only targets `.reveal`, but
   these cards use `.reveal--scale`, so stagger them here. The hover/focus reset
   (equal specificity, declared after) cancels the delay so the lift is instant. */
.stories__grid.stagger > .story-card--cinematic:nth-child(2) {
  transition-delay: calc(1 * var(--transition-stagger));
}
.stories__grid.stagger > .story-card--cinematic:nth-child(3) {
  transition-delay: calc(2 * var(--transition-stagger));
}
.stories__grid.stagger > .story-card--cinematic:nth-child(4) {
  transition-delay: calc(3 * var(--transition-stagger));
}

.stories__grid.stagger > .story-card--cinematic:hover,
.stories__grid.stagger > .story-card--cinematic:focus-within {
  transition-delay: 0ms;
}

/* ── Video modal (<dialog>) ── */

/* The dialog shrink-wraps to the video's real aspect (portrait phone footage
   gets a portrait modal — no fixed-landscape black side-bars). min-width keeps
   it from collapsing during the brief metadata load before sizing settles. */
.video-modal {
  position: fixed;
  inset: 0;
  margin: auto;
  width: fit-content;
  min-width: 240px;
  max-width: min(94vw, 1280px);
  max-height: 96vh;
  padding: 0;
  border: none;
  border-radius: var(--radius-2xl);
  background: #0b0f14;
  color: var(--color-text-inverse);
  box-shadow: 0 32px 80px rgba(0, 0, 0, 0.55);
  overflow: hidden;
}

.video-modal[open] {
  animation: video-modal-in 0.34s cubic-bezier(0.16, 1, 0.3, 1);
}

@keyframes video-modal-in {
  from {
    opacity: 0;
    transform: translateY(10px) scale(0.96);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.video-modal::backdrop {
  background: rgba(8, 12, 20, 0.72);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}

.video-modal[open]::backdrop {
  animation: video-backdrop-in 0.34s ease;
}

@keyframes video-backdrop-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.video-modal__player {
  display: block;
  width: auto;
  height: auto;
  max-width: min(94vw, 1280px);
  max-height: 84vh; /* leaves room for the caption within the modal's 96vh cap */
  margin: 0 auto;
  background: #000;
}

/* Premium caption bar: dark surface with a brand-gradient hairline on top. */
.video-modal__title {
  position: relative;
  margin: 0;
  padding: var(--spacing-md) var(--spacing-lg);
  font-size: var(--font-size-md);
  font-weight: var(--font-weight-semibold);
  color: var(--color-text-inverse);
  background: linear-gradient(180deg, #11161d, #0b0f14);
  text-align: left;
}

.video-modal__title::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 2px;
  background: var(--gradient-brand);
}

.video-modal__close {
  position: absolute;
  top: var(--spacing-sm);
  right: var(--spacing-sm);
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.75rem;
  line-height: 1;
  border: none;
  border-radius: var(--radius-full);
  background: var(--color-overlay-white-strong);
  color: var(--color-text);
  cursor: pointer;
  box-shadow: var(--shadow-md);
  transition:
    background 0.2s ease,
    transform 0.2s ease;
}

.video-modal__close:hover {
  background: var(--color-surface);
  transform: scale(1.05);
}

.video-modal__close:focus-visible {
  outline: 3px solid var(--color-secondary);
  outline-offset: 2px;
}

/* ── Courses CTA band ── */

.courses-cta {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding-block: var(--spacing-3xl);
  background: linear-gradient(
    135deg,
    var(--color-primary) 0%,
    var(--color-secondary) 100%
  );
  color: var(--color-text-inverse);
}

/* Soft-fade the CTA bottom into the footer surface so the gradient band
   does not collide with the footer top edge. Decorative only. */
.courses-cta::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 6rem;
  background: linear-gradient(to bottom, transparent, var(--color-surface));
  pointer-events: none;
  z-index: 1;
}

.courses-cta__inner {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-lg);
  align-items: center;
  text-align: center;
}

@media (min-width: 768px) {
  .courses-cta__inner {
    flex-direction: row;
    justify-content: space-between;
    text-align: left;
    gap: var(--spacing-2xl);
  }
}

.courses-cta__copy {
  max-width: 36rem;
}

.courses-cta__title {
  font-size: clamp(1.5rem, 3.5vw, 2.25rem);
  font-weight: var(--font-weight-extrabold);
  color: var(--color-text-inverse);
  margin: 0 0 var(--spacing-sm);
  /* Shimmer reads on the brand-gradient CTA band: white title with a soft
     brand-gold (#F6B507) highlight that sweeps left to right, then fully
     clears so the title rests on pure white for a couple seconds each cycle.
     The 300% background gives the gold band room to travel completely off
     both edges, so the rest state is genuinely full-white (a 200% background
     always leaves a tint in view). Clipping the plan's --gradient-brand
     (primary to secondary) on top of the same band would be invisible; this
     preserves the shimmer intent on this surface. */
  background: linear-gradient(
    120deg,
    var(--color-text-inverse) 37%,
    var(--color-accent) 50%,
    var(--color-text-inverse) 63%
  );
  background-size: 300% 100%;
  background-position: 100% 50%;
  -webkit-background-clip: text;
          background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: courses-cta-shimmer 6.5s ease-in-out infinite;
}

@keyframes courses-cta-shimmer {
  0%   { background-position: 100% 50%; }
  60%  { background-position: 0% 50%; }
  100% { background-position: 0% 50%; }
}

.courses-cta__lede {
  font-size: clamp(1rem, 2vw, 1.125rem);
  color: var(--color-text-inverse);
  opacity: 0.92;
  margin: 0;
  line-height: 1.55;
}

.courses-cta__btn {
  /* Solid white pill on the gradient band for high contrast. Inherits .btn
     base from components.css (padding, focus ring, sizing). */
  background: var(--color-surface);
  color: var(--color-primary);
  font-weight: var(--font-weight-semibold);
  box-shadow: var(--shadow-md);
  white-space: nowrap;
  transition:
    transform 280ms cubic-bezier(0.34, 1.2, 0.64, 1),
    box-shadow 280ms cubic-bezier(0.34, 1.2, 0.64, 1),
    color 280ms cubic-bezier(0.34, 1.2, 0.64, 1);
}

.courses-cta__btn:hover,
.courses-cta__btn:focus-visible {
  background: var(--color-surface);
  color: var(--color-primary-dark);
  transform: translateY(-2px);
  box-shadow: var(--shadow-lg);
}

/* ── Featured lesson band — free public taste, sits just above the
   Courses CTA. Light surface card so the rhythm reads: invite (light) →
   explore the full catalog (gradient courses-cta) → footer. ── */

.featured-lesson {
  position: relative;
  overflow: hidden;
  padding-block: var(--spacing-3xl) var(--spacing-2xl);
  /* Soft brand "stage" behind the particle field so the moved canvas has
     something to read against on the pale page tint (was a flat
     --color-bg, which gave the particles almost no contrast). */
  /* GCO-97: light brand stage (on-theme). The neural-network canvas is painted
     with normal blending + gold signal pulses (see featured-bg.js) so it reads
     against the pale backdrop without the off-theme dark section. */
  background:
    radial-gradient(
      ellipse 75% 65% at 50% 40%,
      var(--color-secondary-alpha-10),
      transparent 70%
    ),
    var(--color-bg);
}

/* Particle field + fireflies moved here from Program Highlights (owner
   request). Stacking inside .featured-lesson:
   fireflies z-index 0 < canvas (.featured-lesson__bg) 1 < card content 2.
   Canvas/fireflies are aria-hidden; featured-bg.js drives the canvas and
   pauses its RAF loop off-screen. */
.featured-lesson__bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
  opacity: 0.95;
  pointer-events: none;
}

.featured-lesson__inner {
  position: relative;
  z-index: 2;
  display: flex;
  justify-content: center;
}

.featured-lesson__card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
  max-width: 44rem;
  padding: var(--spacing-2xl);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  text-align: center;
  align-items: center;
  border-top: 4px solid var(--color-accent);
}

.featured-lesson__eyebrow {
  margin: 0;
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-semibold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-accent-dark);
}

.featured-lesson__title {
  margin: 0;
  font-size: clamp(1.5rem, 3.5vw, 2.25rem);
  font-weight: var(--font-weight-extrabold);
  color: var(--color-text);
}

.featured-lesson__lede {
  margin: 0;
  max-width: 38rem;
  font-size: clamp(1rem, 2vw, 1.125rem);
  line-height: 1.55;
  color: var(--color-text-light);
}

.featured-lesson__cta {
  margin-top: var(--spacing-md);
  white-space: nowrap;
}

.featured-lesson__cta:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-lg);
}

@media (max-width: 600px) {
  .featured-lesson__card {
    padding: var(--spacing-lg);
  }
}

/* ── Reduced-motion respect ── */

@media (prefers-reduced-motion: reduce) {
  .story-card,
  .story-card__poster,
  .story-card__play,
  .video-modal__close,
  .courses-cta__btn,
  .featured-lesson__cta {
    transition: none;
  }
  .featured-lesson__cta:hover {
    transform: none;
  }
  .story-card:hover,
  .story-card:focus-within {
    transform: none;
  }
  .story-card:hover .story-card__poster,
  .story-card:focus-within .story-card__poster {
    transform: none;
  }
  .story-card__play::after,
  .courses-cta__title {
    animation: none;
  }
  .story-card__play::after {
    opacity: 0;
  }
  .story-card--cinematic:hover .story-card__media::before,
  .story-card--cinematic:focus-within .story-card__media::before {
    animation: none;
  }
  .video-modal[open],
  .video-modal[open]::backdrop {
    animation: none;
  }
  .courses-cta__btn:hover,
  .courses-cta__btn:focus-visible {
    transform: none;
  }
}

/* ── Promos section (Watch our program) ──
 * Sits between Hero and About. Two .story-card cards reuse the Stories
 * lightbox modal via stories.js (querySelectorAll('.story-card')). The
 * grid mirrors .stories__grid but caps at 2 columns since there are only
 * two promo cards and they read better at a larger size.
 */

.promos {
  position: relative;
  padding-block: var(--section-py);   /* Phase 8: standardized section rhythm */
  background: var(--color-surface-subtle);   /* P8.5: alternating surface rhythm */
}

/* GCO-97 candidate: fix the Watch our program waveform so it stays put while
   the section scrolls over it. Falls back to scroll on reduced motion (and
   where fixed attachment is unsupported, e.g. most mobile browsers). */
.promos .tx-waveform {
  background-attachment: fixed;
  animation: promos-wave-drift 18s linear infinite;
}
/* GCO-97: subtle horizontal drift so the sine traces read as moving waves.
   240px is one tile width, so the loop is seamless. */
@keyframes promos-wave-drift {
  from { background-position-x: 0; }
  to { background-position-x: 240px; }
}
@media (prefers-reduced-motion: reduce) {
  .promos .tx-waveform {
    background-attachment: scroll;
    animation: none;
  }
}

.promos__inner {
  position: relative;
  text-align: center;
}

.promos__header {
  margin-bottom: var(--spacing-2xl);
}

.promos__title {
  font-size: clamp(2rem, 4.5vw, 3rem);
  font-weight: var(--font-weight-extrabold);
  margin-bottom: var(--spacing-sm);
}

.promos__subtitle {
  max-width: 36rem;
  margin: 0 auto var(--spacing-lg);
  font-size: clamp(1rem, 2.5vw, 1.125rem);
  color: var(--color-text-light);
  font-weight: var(--font-weight-medium);
}

.promos__divider {
  width: 120px;
  height: var(--width-accent-line-thin);
  margin: 0 auto;
  background: linear-gradient(
    90deg,
    transparent,
    var(--color-secondary),
    var(--color-primary),
    var(--color-secondary),
    transparent
  );
}

.promos__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--spacing-xl);
  margin-top: var(--spacing-xl);
  max-width: 1080px;
  margin-inline: auto;
}

/* GCO-97 candidate: stagger the two cards' arrival pop left -> right. */
.promos__grid .reveal--pop:nth-child(2) {
  transition-delay: 0.12s;
}

@media (min-width: 768px) {
  .promos__grid {
    grid-template-columns: repeat(2, 1fr);
    gap: calc(var(--spacing-xl) + var(--spacing-sm));
  }
}

/* ──────────────────────────────────────────────────────────────────────
   Gallery (Phase 8.5)
   ──────────────────────────────────────────────────────────────────────
   Static photo grid + shared image lightbox <dialog>. Wired in
   assets/js/gallery.js. Mirrors the .video-modal pattern.
   ────────────────────────────────────────────────────────────────────── */

.gallery {
  padding: var(--spacing-3xl) 0;
  background: linear-gradient(
    180deg,
    var(--color-surface) 0%,
    var(--color-surface-subtle) 100%
  );
}

.gallery__inner {
  max-width: var(--width-max, 1200px);
  margin: 0 auto;
  padding: 0 var(--spacing-md);
}

.gallery__header {
  text-align: center;
  margin-bottom: var(--spacing-2xl);
}

.gallery__title {
  font-size: var(--font-size-3xl);
  font-weight: var(--font-weight-extrabold);
  letter-spacing: 0.04em;
  margin: 0 0 var(--spacing-sm);
  background: linear-gradient(
    90deg,
    var(--color-primary),
    var(--color-secondary)
  );
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.gallery__subtitle {
  font-size: var(--font-size-md);
  color: var(--color-text-light);
  margin: 0 auto;
  max-width: 60ch;
}

/* Keep "US Virgin Islands" from breaking across lines mid-phrase. */
.gallery__nowrap {
  white-space: nowrap;
}

.gallery__divider {
  width: 64px;
  height: 3px;
  margin: var(--spacing-md) auto 0;
  background: linear-gradient(
    90deg,
    var(--color-primary),
    var(--color-secondary)
  );
  border-radius: 999px;
}

.gallery__grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--spacing-sm);
  grid-template-columns: repeat(2, 1fr);
}

@media (min-width: 640px) {
  .gallery__grid {
    grid-template-columns: repeat(3, 1fr);
    gap: var(--spacing-md);
  }
}

@media (min-width: 1024px) {
  .gallery__grid {
    grid-template-columns: repeat(4, 1fr);
  }
}

.gallery__item {
  margin: 0;
}

.gallery__thumb {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: var(--color-surface-subtle);
  border-radius: var(--radius-md);
  overflow: hidden;
  cursor: zoom-in;
  position: relative;
  aspect-ratio: 3 / 2;
  transition:
    transform 0.15s ease,
    box-shadow 0.15s ease;
}

.gallery__thumb:hover,
.gallery__thumb:focus-visible {
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
  outline: none;
}

.gallery__thumb:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

.gallery__thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.4s ease;
}

.gallery__thumb:hover img {
  transform: scale(1.04);
}

/* ── Gallery filter: Photos / Videos toggle (GCO-97) ── */

.gallery-filter {
  display: flex;
  justify-content: center;
  gap: var(--spacing-sm);
  margin-top: var(--spacing-lg);
  margin-bottom: var(--spacing-xl);
}

.gallery-filter__btn {
  min-height: 44px;
  padding: 0.5rem 1.75rem;
  border: 2px solid var(--color-primary);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--color-primary);
  font-weight: var(--font-weight-bold);
  font-size: var(--font-size-md);
  letter-spacing: 0.02em;
  cursor: pointer;
  transition:
    background 0.2s ease,
    color 0.2s ease,
    border-color 0.2s ease;
}

.gallery-filter__btn.is-active {
  background: linear-gradient(
    135deg,
    var(--color-primary),
    var(--color-secondary)
  );
  color: var(--color-text-inverse);
  border-color: transparent;
}

.gallery-filter__btn:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

/* Filter state: hide the inactive media type in place. */
.gallery__grid--photos .gallery__item--video,
.gallery__grid--videos .gallery__item--photo {
  display: none;
}

/* Video cards fill their grid cell like the photo thumbs. */
.gallery__item--video .story-card {
  width: 100%;
}

@media (prefers-reduced-motion: reduce) {
  .gallery-filter__btn {
    transition: none;
  }
}

/* ── Lightbox dialog ── */

.lightbox {
  position: fixed;
  inset: 0;
  margin: auto;
  border: 0;
  padding: 0;
  background: transparent;
  max-width: 100vw;
  max-height: 100vh;
  width: 100vw;
  height: 100vh;
  color: #fff;
}

.lightbox::backdrop {
  background: rgba(0, 0, 0, 0.92);
}

.lightbox[open] {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
}

.lightbox__image {
  max-width: 92vw;
  max-height: 82vh;
  width: auto;
  height: auto;
  object-fit: contain;
  border-radius: var(--radius-md);
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.5);
}

.lightbox__close,
.lightbox__nav {
  position: absolute;
  appearance: none;
  border: 0;
  background: rgba(0, 0, 0, 0.45);
  color: #fff;
  width: 48px;
  height: 48px;
  border-radius: 999px;
  font-size: 2rem;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition:
    background 0.15s ease,
    transform 0.15s ease;
}

.lightbox__close:hover,
.lightbox__nav:hover,
.lightbox__close:focus-visible,
.lightbox__nav:focus-visible {
  background: rgba(0, 0, 0, 0.75);
  outline: none;
}

.lightbox__close {
  top: var(--spacing-lg);
  right: var(--spacing-lg);
}

.lightbox__nav {
  top: 50%;
  transform: translateY(-50%);
  font-size: 2.5rem;
}

.lightbox__nav:hover,
.lightbox__nav:focus-visible {
  transform: translateY(-50%) scale(1.06);
}

.lightbox__nav--prev {
  left: var(--spacing-md);
}
.lightbox__nav--next {
  right: var(--spacing-md);
}

@media (min-width: 768px) {
  .lightbox__nav--prev {
    left: var(--spacing-2xl);
  }
  .lightbox__nav--next {
    right: var(--spacing-2xl);
  }
}

.lightbox__counter {
  margin: var(--spacing-md) 0 0;
  font-size: var(--font-size-sm);
  color: rgba(255, 255, 255, 0.85);
  letter-spacing: 0.04em;
}

@media (prefers-reduced-motion: reduce) {
  .gallery__thumb,
  .gallery__thumb img,
  .lightbox__close,
  .lightbox__nav {
    transition: none;
  }
  .gallery__thumb:hover img {
    transform: none;
  }
}
