/* ============================================================
   HOMEPAGE HERO BANNER — BOS and SpiderNet (hero-banner.js)
   Moved out of bos-home.css 2026-10-07 so both homepages share it.
   Markup: <section class="hero-banner"> with a .container > .row >
   .col-lg-6 > .hero-text-backdrop text card; hero-banner.js inserts the
   photo panel, caption, arrows and dots. --hero-bg is the section's own
   background (BOS navy by default; SpiderNet sets its dark gray).
   BOS's search form in the text card is styled in bos-home.css.
   ============================================================ */

/* height was briefly driven by the CSS `aspect-ratio` property (matching
   the hero photos' native 2000x672 size) to stop the banner cropping the
   photo vertically past ~1600px wide, but every bug reported afterward —
   a flex row overflowing the viewport at ~900px, .hero-banner's own
   box measuring wider than the window at 1423px — traced to width ranges
   that property governed, with no code-level explanation found on static
   analysis (no headless browser in this environment to confirm the exact
   mechanism, e.g. a possible circular-dependency edge case between
   aspect-ratio and this element's absolutely-positioned inset:0 children
   establishing their containing block against it). Reverted 2026-09-11 to
   plain min-height, and background-size:auto 100% on .hero-slide (below)
   took over guaranteeing the photo's full height is always visible
   instead. The ::before rule right after this one restores widescreen
   proportional growth using the older, more conservatively-supported
   padding-percentage technique instead. */
.hero-banner {
  height: auto;
  min-height: 480px;
  overflow: hidden;
  position: relative;
  display: flex;
  align-items: center;
  padding-top: 30px;
  padding-bottom: 30px;
}

/* From 1512px wide, min-height's fixed 480px falls short of the photo's
   2000x672 shape (480/2000*672 would need ~1429px+ of width just to
   stop background-size:auto 100% (below) from leaving an uncropped gap
   on the right — visible from 1512px, per Nicky 2026-09-11) — so from
   here up, grow height in step with width instead of leaving it pinned.
   Classic padding-percentage aspect-ratio technique, not the CSS
   `aspect-ratio` property (see note above) — an invisible flex item
   whose own width is pinned to 0 but whose padding-top percentage still
   resolves against the FLEX CONTAINER's width (percentages on padding
   always resolve against the containing block's width, regardless of
   which box they're padding), forcing .hero-banner's auto height
   to be at least 33.6% (672/2000) of its own width — well-supported,
   pre-dates flexbox and Grid, no known edge cases with this page's
   flex + absolutely-positioned-children structure. */
@media (min-width: 1512px) {
  .hero-banner::before {
    content: '';
    display: block;
    width: 0;
    padding-top: 33.6%;
  }
}

/* Bootstrap's .container spans the full hero width even though only the
   left column (.col-lg-6) has visible content — its empty right half was
   sitting above the slide (z-index:2) and swallowing clicks meant for the
   image. Make the wrapper click-through and only re-enable the actual
   visible text card, so the rest of the banner reaches the slide link. */
.hero-banner .container { pointer-events: none; min-width: 0; }

/* .hero-image-panel (hero-banner.js, inserted as .hero-banner's first
   child) and .container are both flex items of .hero-banner — flex
   items default to min-width:auto, which floors their shrink at their
   own content's min-content width regardless of flex-shrink or the
   parent's overflow:hidden. That let the row push .hero-banner's
   own box wider than the viewport at ~900px, dragging .hero-caption
   (position:absolute; right:20px — relative to that oversized box)
   off-screen with it. Reported 2026-09-10. */
.hero-image-panel { min-width: 0; }

.hero-text-backdrop {
  pointer-events: auto;
  color: rgba(255, 255, 255, 0.6);
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(5px);
  border-radius: 6px;
  padding: 32px 36px 28px;
  width: 100%;
}

/* Slideshow slides — <a> when the species has a taxon page (clickable image),
   plain <div> otherwise (e.g. Armadillidae isopod, no taxon page yet) */
.hero-slide {
  position: absolute;
  inset: 0;
  /* auto 100% — always scale the photo to exactly match the section's
     height, letting width overflow (cropped by .hero-banner's own
     overflow:hidden) or fall short (a plain navy gap, .hero-banner's
     own background-color, on the left — where the text card sits) as
     the section's fixed min-height (480px, or 400px at 768-1199.98px
     below) happens to compare to the photo's native 2000x672 shape at a
     given viewport width. Explicit "always fill height, crop/gap width
     instead" per Nicky (2026-09-11) — cover picked whichever dimension
     needed MORE scale (sometimes height, cropping the subject vertically
     — the original ≥1600px bug) and contain picked whichever needed
     LESS (sometimes width, leaving an unwanted vertical letterbox gap —
     reported immediately after switching to it). Neither ever guaranteed
     height was the bound; this always does. */
  background-size: auto 100%;
  background-position: right center;
  background-repeat: no-repeat;
  opacity: 0;
  pointer-events: none;   /* stacked slides all sit at inset:0 — opacity:0
                             alone doesn't stop the inactive ones (esp. the
                             last one in DOM order) from swallowing clicks */
  transition: opacity 1.4s ease-in-out;
  z-index: 0;
}
.hero-slide.active { opacity: 1; pointer-events: auto; }
.hero-slide--linked { cursor: pointer; }

/* Slide caption — the name is plain text, never a link (clicking the
   picture navigates, clicking the caption should not); the credit may
   contain its own link out to the photographer's site (bos_personLinkHtml) */
.hero-caption {
  position: absolute;
  bottom: 14px;
  right: 20px;
  z-index: 10;
  display: flex;
  flex-direction: row;
  align-items: baseline;
  gap: 8px;
  font-size: 11px;
  /* Its own line height: SpiderNet's theme sets 30px on body, which made the
     caption 38px tall there (25px on BOS) and ran it into .hero-dots above. */
  line-height: 1.6;
  color: rgba(255,255,255,0.6);
  letter-spacing: 0.04em;
  font-style: normal;
  text-shadow: 0 1px 4px rgba(0,0,0,0.7);
  transition: opacity 0.5s ease;
  background: rgba(0, 0, 0, 0.55);
  padding: 4px 15px;
  border-radius: 3px;
  /* Previously unconstrained outside the ≤767px mobile block, so a long
     name+credit pair grew past .hero-banner's left edge and got
     hard-clipped mid-character by its overflow:hidden instead of
     truncating — visible from ~768-1024px, reported 2026-09-10 (the
     narrow-desktop/tablet range's shrunk .hero-banner width leaves
     less room than the wider default desktop layout). */
  max-width: calc(100% - 40px);
}
/* display:flex children also default to min-width:auto, which would
   stop them shrinking enough to ever trigger their own ellipsis below —
   same gotcha as .hero-image-panel/.container above, just one level in. */
.hero-caption-name {
  color: rgba(255,255,255,0.85);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.hero-caption-credit {
  font-size: 10px;
  color: rgba(255,255,255,0.85);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.hero-caption-credit a { color: inherit; text-decoration: underline; text-decoration-color: rgba(255,255,255,0.3); }
.hero-caption-credit a:hover { color: rgba(255,255,255,0.85); text-decoration-color: currentColor; }



/* ============================================================
   HERO MOBILE LAYOUT — image above, text below
   Primary layout at ≤767px; ≤479px fine-tunes further. 768-991px
   (tablet) instead uses the "narrow desktop" overlay-on-photo layout
   below (text card on the left half only, search bar relocated below
   the hero) — the stacked treatment tried at that width capped the
   image panel's height while its width grew with the viewport,
   producing a very wide/short crop that showed too much empty
   background to the left of the subject (subject is anchored right,
   see .hero-slide below).
   ============================================================ */

@media (max-width: 767px) {
  /* Stack vertically instead of overlapping; image panel first,
     text panel below, flush against the sticky header above. */
  .hero-banner {
    display: block;
    position: relative;
    min-height: 0;
    padding: 0;
    overflow: visible;
  }

  /* .hero-slide children (hero-banner.js) are position:absolute; inset:0
     inside .hero-image-panel — giving the panel itself a position and
     a fluid height makes them fill just this box instead of the whole
     section. */
  .hero-image-panel {
    position: relative;
    height: clamp(260px, 78vw, 320px);
    overflow: hidden;
    width: 100%;
  }

  .hero-slide {
    position: absolute;
    inset: 0;
    /* Subject sits in the right 30-40% of the source photo — cover +
       right-anchored position means any cropping eats the left side
       first, at any panel width/height. The subject never crops. */
    background-position: right center;
    background-size: cover;
  }

  button[aria-label="Previous image"],
  button[aria-label="Next image"] {
    top: 50% !important;
    transform: translateY(-50%) !important;
  }

  .hero-caption {
    position: absolute;
    bottom: 8px;
    right: 10px;
    z-index: 10;
    /* May span the whole photo (10px margin each side) — the prev/next
       arrows sit at mid-height, well clear of this bottom line. */
    max-width: calc(100% - 20px);
    font-size: 10px;
  }
  .hero-caption-name {
    max-width: 100%;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  /* The photographer's credit is never cut off: it keeps its full width
     and only the taxon name beside it shrinks (ellipsis). */
  .hero-caption-credit {
    flex: 0 0 auto;
    max-width: none;
    white-space: nowrap;
    overflow: visible;
    text-overflow: clip;
  }

  /* Text panel — solid background matching the section's own inline
     navy, no translucent blur backdrop (only needed for legibility
     over a photo, not needed on a solid panel). */
  .hero-banner .container {
    position: relative;
    z-index: 5;
    background: var(--hero-bg, #1c2b42);
    padding-top: 20px;
    padding-bottom: 20px;
  }

  .hero-text-backdrop {
    background: transparent;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    border-radius: 0;
    padding: 0 4px;
    width: 100%;
  }

  .hero-banner h4 {
    font-size: 2rem !important;
    line-height: 1.3;
    margin-bottom: 12px !important;
  }

  .hero-banner .fs-16 {
    font-size: 14px !important;
    line-height: 1.55;
    margin-bottom: 16px !important;
  }
}

@media (max-width: 479px) {
  button[aria-label="Previous image"],
  button[aria-label="Next image"] {
    width: 28px !important;
    height: 28px !important;
    font-size: 14px !important;
  }
  button[aria-label="Previous image"] { left: 6px !important; }
  button[aria-label="Next image"] { right: 6px !important; }

  .hero-caption {
    font-size: 10px;
    right: 10px;
    bottom: 10px;
    max-width: calc(100% - 20px);
  }
}

/* Hero position dots (hero-banner.js .hero-dots, a sibling right after
   .hero-image-panel). Desktop/tablet: overlaid inside the banner's bottom
   edge, right-aligned just above .hero-caption (the text card fills the
   left half and the caption the bottom-right corner, so centred dots
   collided with both), on a translucent pill so they read on any photo. Phones:
   a strip under the photo (the caption and credit already use the photo's
   bottom edge there). Each button is a 22px hit target around an 8px dot;
   the current banner's dot widens to a bar, and a dot pulses while its
   banner's image is still downloading. */
.hero-dots {
  position: absolute;
  right: 20px;
  bottom: 50px;
  z-index: 10;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  padding: 2px 6px;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.35);
  max-width: calc(100% - 40px);
}
.hero-dot {
  width: 22px;
  height: 22px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.hero-dot::before {
  content: '';
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.5);
  transition: width 0.3s, background 0.3s;
}
.hero-dot:hover::before,
.hero-dot:focus-visible::before { background: rgba(255, 255, 255, 0.85); }
.hero-dot:focus-visible { outline: 2px solid #fff; outline-offset: -3px; border-radius: 999px; }
.hero-dot.active::before { width: 18px; background: #fff; }
.hero-dot.loading::before { animation: hero-dot-pulse 0.9s ease-in-out infinite; }
@keyframes hero-dot-pulse { 50% { background: rgba(255, 255, 255, 0.15); } }
@media (prefers-reduced-motion: reduce) {
  .hero-dot.loading::before { animation: none; background: rgba(255, 255, 255, 0.85); }
}
@media (max-width: 767px) {
  .hero-dots {
    position: static;
    max-width: none;
    border-radius: 0;
    padding: 4px 8px;
    background: var(--hero-bg, #1c2b42); /* the hero section's own background */
  }
}


/* ============================================================
   HERO — NARROW DESKTOP + TABLET (iPad portrait/landscape, lg-only
   laptop windows). Still the desktop overlay-on-photo layout (not the
   mobile stack, which stops at 767px) — but at this width the text
   card and the photo's subject occupy the same space, and there
   isn't enough room for both. Rather than trading image height
   against text height: the heading shrinks, the text card is forced
   to the left half (.col-lg-6 only gets its 50% width from Bootstrap
   at ≥992px natively — width:100% below that, from the plain
   `.row > *` base rule, so it must be set explicitly here), and
   on BOS, bos-home.js moves the search form out of the text card into
   a standalone .hero-search-bar below the banner (bos-home.css).
   ============================================================ */
@media (min-width: 768px) and (max-width: 1199.98px) {
  .hero-banner {
    min-height: 400px;
  }

  .hero-banner .col-lg-6 {
    width: 50%;
  }

  .hero-banner h4 {
    font-size: 1.8em !important;
  }
}

/* Caption over a banner's drawn watermark (hero-banner.js fitCaption()):
   placed and grown to cover it; text right-aligned, vertically centred. */
.hero-caption--covers {
  justify-content: flex-end;
  align-items: center;
  box-sizing: border-box;
}
