/* ---------- Fonts ---------- */
/* Anonymous Pro: OFL, self-hosted from Google Fonts. Used for nav/headings,
   matching the monospace-ish feel of the current site's UI chrome. */
@font-face {
  font-family: 'anonymous-pro';
  src: url('/assets/fonts/anonymous-pro-regular.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'anonymous-pro';
  src: url('/assets/fonts/anonymous-pro-bold.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* Sofia Sans: OFL, self-hosted from Google Fonts. Free stand-in for the
   commercial Sofia Pro used on the current site until/unless licensed
   Sofia Pro files are dropped in — see automation/README.md for swap notes. */
@font-face {
  font-family: 'sofia-sans';
  src: url('/assets/fonts/sofia-sans-variable.woff2') format('woff2-variations');
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
}

:root {
  --font-body: 'sofia-sans', Helvetica, Arial, sans-serif;
  --font-mono: 'anonymous-pro', 'Courier New', monospace;

  /* Darker neutral-gray page background — still reads as "light," just not
     white, and doesn't fight photos the way true black/white would. Neutral
     (not warm) so it doesn't read as brown. */
  --color-bg: #383838;
  --color-text: #f0e8da;        /* off-white, a little warm -- the bg is dark enough now that text reads light-on-dark */
  --color-muted: #b6ac9b;       /* dimmer warm off-white for secondary text, still on the dark-ish bg */
  --color-border: #1e1e1e;      /* darker than --color-bg so hairlines are visible against it */
  --color-surface: #f2f2f2;     /* near-white "card" surface for menus/controls that sit on top of the gray bg */
  --color-surface-hover: #e2e2e2;
  --color-surface-text: #262929; /* dark text for the few things that sit on --color-surface's light card, not the dark bg -- dropdown menu, map empty-state */
  --color-link: #dfe9ff;        /* light blue that stays legible on the gray bg, for the birds.helsel.co banner */
  /* Topbar nav on gallery pages is a dark bar, darker still than the page
     bg, so it shares the same warm off-white text as the rest of the site. */
  --color-nav-bg: #2e3131;
  --color-nav-text: #f0e8da;

  --sidebar-width: 270px;
  --touch-target: 44px;         /* minimum comfortable tap target */
  --hero-padding: clamp(1.5rem, 5vw, 4rem);
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family: var(--font-body);
  color: var(--color-text);
  background: var(--color-bg);
  line-height: 1.5;
  /* Tells the browser this page is intentionally light-on-gray, so Chromium's
     auto-dark-mode heuristics (which can invert text to white on OSes/browsers
     with dark mode on) don't override our actual colors. */
  color-scheme: light;
}

.site-footer {
  /* Empty for now -- just breathing room between the last element on a
     page and the bottom of the scroll, so content doesn't feel like it
     stops abruptly at the viewport edge. Real footer content can go here
     later without needing to touch this spacing. */
  height: 6rem;
}

a {
  color: inherit;
  text-decoration: none;
}

img {
  max-width: 100%;
  display: block;
}

/* ---------- Anaglyph 3D hover effect ----------
   Ported from the current site's SmugMug custom CSS, same red/cyan
   text-shadow split + jitter animation, applied to our own nav links. */
.site-nav a {
  position: relative;
  transition: text-shadow 0.15s ease;
}
.site-nav a:hover {
  color: inherit !important;
  text-shadow:
    -2px 0 0 rgba(255, 0, 60, 0.8),
     2px 0 0 rgba(0, 255, 255, 0.8) !important;
  animation: anaglyph-jitter 0.3s steps(2) infinite;
}
@keyframes anaglyph-jitter {
  0%   { transform: translate(0, 0); }
  50%  { transform: translate(-1px, 0); }
  100% { transform: translate(1px, 0); }
}

/* ---------- Nav ---------- */
.site-nav {
  font-family: var(--font-mono);
}
.site-nav__brand a {
  font-weight: 700;
  font-size: 1.1rem;
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  min-height: var(--touch-target);
}
.site-nav__logo-mark {
  height: 2.25rem;
  width: auto;
}
.site-nav__logo-mark--invert {
  filter: invert(1) brightness(1.4);
}
.site-nav__links {
  list-style: none;
  margin: 0;
  padding: 0;
}
/* Hamburger toggle: only shown at phone width in sidebar (homepage) mode --
   see the 600px media query below. Hidden here so it never appears on
   tablet/desktop, where the stacked link list is already shown inline. */
.site-nav__menu-toggle {
  display: none;
  background: none;
  border: none;
  color: var(--color-nav-text);
  font-family: var(--font-mono);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-size: 1rem;
  cursor: pointer;
  min-height: var(--touch-target);
  padding: 0 0.25rem;
}
.site-nav__menu-toggle-close {
  display: none;
}
.site-nav__links a {
  text-transform: uppercase;
  font-size: 1.35rem;
  letter-spacing: 0.03em;
  color: var(--color-muted);
  display: inline-flex;
  align-items: center;
  min-height: var(--touch-target);
}

/* Sidebar mode: homepage */
.site-nav--sidebar {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  width: var(--sidebar-width);
  padding: 2rem 1.5rem 2rem 3rem;
  border-right: 1px solid var(--color-border);
  overflow-y: auto;
}
.site-nav--sidebar .site-nav__brand {
  margin-bottom: 2rem;
}
.site-nav--sidebar .site-nav__links--vertical li {
  /* Generous gap to the NEXT item, but tight line-height within this one --
     otherwise a wrapped label like "The Post Office" reads as two separate
     menu items instead of one two-line one. */
  margin-bottom: 1.25rem;
  padding-bottom: 1.25rem;
  border-bottom: 1px solid rgba(240, 232, 218, 0.2);
}
.site-nav--sidebar .site-nav__links--vertical li:last-child {
  border-bottom: none;
}
/* Homepage menu items sized up further, independent of the gallery topbar's
   link size. */
.site-nav--sidebar .site-nav__links a {
  font-size: 1.7rem;
  line-height: 1.15;
}

/* Topbar mode: gallery pages -- a filled color bar instead of a thin
   border line, so the nav reads as its own header rather than a hairline.
   The bar's background spans the full viewport width, but its content
   (.site-nav__inner) is inset to the same max-width/padding as .gallery-page
   below it, so HOME | SEARCH | OTHER PHOTOS lines up with the photos'
   right edge instead of sitting flush against the browser edge. */
.site-nav--topbar {
  padding: 1rem 0;
  background: var(--color-nav-bg);
  /* Own stacking context above page content -- otherwise the OTHER PHOTOS
     dropdown (a child of this bar) loses to Leaflet's internal map panes
     on gallery pages with a map, since those panes' z-index is compared
     against this bar's ambient stacking context, not just the dropdown's
     own z-index. */
  position: relative;
  z-index: 900;
}
.site-nav--topbar .site-nav__inner {
  max-width: 1100px;
  margin: 0 auto;
  padding: 0 2rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
}
/* The bar itself is dark, so its own brand + top-level links need light
   text. The dropdown MENU (a light card floating below) is untouched --
   this only targets direct children of the topbar, not the nested
   .site-nav__dropdown-menu links two levels down, which stay dark-on-light. */
.site-nav--topbar .site-nav__brand a,
.site-nav--topbar .site-nav__inner > .site-nav__links > li > a {
  color: var(--color-nav-text);
}
.site-nav--topbar .site-nav__links--horizontal {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.25rem;
  align-items: center;
}
/* Small vertical separators between HOME | SEARCH | OTHER PHOTOS. */
.site-nav--topbar .site-nav__links--horizontal > li {
  display: flex;
  align-items: center;
}
/* A real text glyph, not a drawn 1-2px box -- a CSS hairline at that width
   kept failing to render visibly (subpixel/anti-aliasing at typical zoom
   levels), whereas a font-rendered character can't have that problem. */
.site-nav--topbar .site-nav__links--horizontal > li:not(:first-child)::before {
  content: '|';
  margin-right: 1.25rem;
  color: var(--color-nav-text);
  opacity: 0.7;
  font-size: 1.3em;
}
.site-nav__dropdown {
  position: relative;
}
.site-nav__dropdown-toggle {
  cursor: pointer;
}
.site-nav__dropdown-menu {
  display: none;
  position: absolute;
  right: 0;
  top: 100%;
  list-style: none;
  /* No margin-top here on purpose: a gap between the toggle and this menu
     is dead space the mouse has to cross, and leaving that space breaks
     :hover (moving through it exits every hoverable descendant of
     .site-nav__dropdown) before the pointer ever reaches the menu. The
     menu sits flush against the toggle instead, with padding providing
     the same visual breathing room without an actual gap. */
  margin: 0;
  padding: 0.75rem 0 0.5rem;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  min-width: 180px;
  max-width: calc(100vw - 2rem);
  z-index: 10;
}
/* Hover works for desktop mice; the `.is-open` class (toggled by nav.js on
   click/tap) is what actually makes this usable on touch devices, since
   touch has no hover state to rely on. */
.site-nav__dropdown:hover .site-nav__dropdown-menu,
.site-nav__dropdown:focus-within .site-nav__dropdown-menu,
.site-nav__dropdown.is-open .site-nav__dropdown-menu {
  display: block;
}
.site-nav__dropdown-menu li {
  padding: 0;
}
.site-nav__dropdown-menu li a {
  padding: 0.5rem 1rem;
  width: 100%;
  /* The dropdown is a light card floating below the dark topbar, so its
     links need the dark surface-text color, not the page's light text. */
  color: var(--color-surface-text);
}

/* ---------- Homepage ---------- */
.homepage {
  margin-left: var(--sidebar-width);
}
.hero {
  position: relative;
  height: 100vh;
  padding: var(--hero-padding);
  /* Explicit rather than relying on inheriting body's color -- the framing
     padding above/below the photo and the leftover space below a shorter
     mobile hero must always read as the exact same color, not two shades
     that happen to usually match. */
  background: var(--color-bg);
}
.hero__slide {
  position: absolute;
  inset: var(--hero-padding);
  opacity: 0;
  transition: opacity 0.8s ease;
}
.hero__slide.is-active {
  opacity: 1;
}
.hero__slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ---------- Gallery pages ---------- */
.gallery-page {
  max-width: 1100px;
  margin: 0 auto;
  padding: 2rem;
}
.gallery-page__title {
  font-family: var(--font-mono);
  text-transform: uppercase;
  font-size: 2rem;
  margin: 0.5rem 0 1rem;
}
.gallery-page__description {
  color: var(--color-muted);
  max-width: 60ch;
}

.birds-banner {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 0.75rem 1.5rem;
  margin-bottom: 1.75rem;
  padding: 0.9rem 1.25rem;
  background: var(--color-nav-bg);
  border: 1px solid var(--color-border);
  border-radius: 0.75rem;
  font-family: var(--font-mono);
}
.birds-banner__link,
.birds-banner__button {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  color: var(--color-text);
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: 999px;
  padding: 0.4rem 0.9rem;
  font-size: 0.85rem;
  text-decoration: none;
  white-space: nowrap;
}
.birds-banner__link {
  padding-left: 0.4rem;
}
.birds-banner__link:hover,
.birds-banner__button:hover {
  background: var(--color-surface-hover, var(--color-nav-bg));
}
.birds-banner__thumb {
  height: 1.7rem;
  width: 1.7rem;
  object-fit: cover;
  flex: none;
  border-radius: 999px;
  border: 1px solid var(--color-border);
}

/* ---------- Birding in Texas page ---------- */
.birding-breadcrumb {
  display: block;
  margin-bottom: 1rem;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--color-muted);
}
.birding-collapsible {
  margin-bottom: 1.5rem;
  border: 1px solid var(--color-border);
  border-radius: 0.75rem;
  background: var(--color-nav-bg);
  padding: 0 1.1rem;
}
.birding-collapsible[open] {
  padding-bottom: 1.1rem;
}
.birding-collapsible__summary {
  cursor: pointer;
  list-style: none;
  padding: 0.9rem 0;
  font-family: var(--font-mono);
  font-size: 1.15rem;
  font-weight: 600;
  color: var(--color-text);
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.birding-collapsible__summary::-webkit-details-marker {
  display: none;
}
.birding-collapsible__summary::after {
  content: '+';
  font-size: 1.1rem;
  color: var(--color-muted);
  margin-left: 1rem;
}
.birding-collapsible[open] .birding-collapsible__summary::after {
  content: '\2212';
}
.birding-collapsible__summary:hover {
  color: var(--color-link);
}
.birding-locations-list {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.15rem 1.5rem;
  font-family: var(--font-mono);
  font-size: 0.85rem;
}
.birding-locations-list__item {
  display: flex;
  flex-direction: column;
  padding: 0.15rem 0.4rem;
  margin: 0 -0.4rem;
  border-bottom: 1px solid rgba(240, 232, 218, 0.12);
  border-radius: 0.25rem;
  transition: background-color 0.15s ease;
}
.birding-locations-list__item--active {
  background: var(--color-bg);
}
.birding-locations-list__name {
  color: var(--color-text);
}
.birding-locations-list__place {
  color: var(--color-muted);
  font-size: 0.75rem;
}
.birding-locations-list__links {
  display: flex;
  gap: 0.75rem;
  margin-top: 0.1rem;
}
.birding-locations-list__links a {
  color: var(--color-muted);
  text-decoration: underline;
  font-size: 0.72rem;
}
.birding-locations-list__links a:hover {
  color: var(--color-link);
}

.birding-resources-columns {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  column-gap: 2rem;
}
.birding-resources-column__heading {
  margin: 0 0 0.5rem;
  font-family: var(--font-mono);
  font-size: 1rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-muted);
}
.birding-resources {
  list-style: none;
  font-family: var(--font-mono);
  font-size: 0.85rem;
}
.birding-resources__item {
  padding: 0.6rem 0;
  border-bottom: 1px solid rgba(240, 232, 218, 0.12);
}
.birding-resources__item:last-child {
  border-bottom: none;
}
.birding-resources__item a {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4rem;
  color: var(--color-text);
  text-decoration: none;
}
.birding-resources__item a:hover {
  color: var(--color-link);
}
.birding-resources__title {
  text-decoration: underline;
}
.birding-resources__note {
  color: var(--color-muted);
  font-size: 0.8rem;
  text-decoration: none;
}

.birding-submit {
  max-width: 500px;
  padding-top: 1.5rem;
  border-top: 1px solid var(--color-border);
}
.birding-submit__title {
  font-family: var(--font-mono);
  text-transform: uppercase;
  font-size: 1.3rem;
  margin: 0 0 0.5rem;
}
.birding-submit__note {
  color: var(--color-muted);
  margin: 0 0 1.5rem;
}
.birding-submit__success {
  color: var(--color-text);
}
.birding-submit__errors {
  color: #ff9a9a;
  margin: 0 0 1rem;
  padding-left: 1.2rem;
}
.birding-submit__form {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.birding-submit__field {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  font-family: var(--font-mono);
  text-transform: uppercase;
  font-size: 0.8rem;
  letter-spacing: 0.02em;
}
.birding-submit__field input,
.birding-submit__field textarea {
  font-family: inherit;
  font-size: 1rem;
  text-transform: none;
  letter-spacing: normal;
  padding: 0.6rem 0.75rem;
  background: var(--color-surface);
  color: var(--color-surface-text);
  border: 1px solid var(--color-border);
}
.birding-submit__honeypot {
  /* Hidden from real visitors via CSS (not type="hidden", which some
     bots' form-fillers skip) rather than removed from the DOM, so it's
     still there for a bot to find and fill in. */
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
.birding-submit__button {
  align-self: flex-start;
  font-family: var(--font-mono);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 0.75rem 1.5rem;
  background: var(--color-surface);
  color: var(--color-surface-text);
  border: 1px solid var(--color-border);
  cursor: pointer;
}
.birding-submit__button:hover {
  background: var(--color-surface-hover);
}

.gallery-map__popup-thumb {
  display: block;
  width: 160px;
  height: 110px;
  object-fit: cover;
  margin-bottom: 0.4rem;
}
.gallery-map__popup-title {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.85rem;
  color: var(--color-surface-text);
  text-decoration: underline;
}
a.gallery-map__popup-title:hover {
  color: var(--color-link);
}

.gallery-map {
  width: 100%;
  height: 420px;
  margin-bottom: 2rem;
  border: 1px solid var(--color-border);
}
.gallery-map__empty {
  padding: 2rem;
  color: var(--color-surface-text);
  text-align: center;
  background: var(--color-surface);
}
.birding-map-note {
  margin: -1.5rem 0 2rem;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: var(--color-muted);
}
.gallery-map__marker--active {
  filter: hue-rotate(120deg) saturate(1.5);
  transform: scale(1.3);
  transform-origin: bottom center;
}
.gallery-map__locate a {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  font-size: 1.2rem;
  background: #fff;
  color: #333;
  text-decoration: none;
}
.gallery-map__locate a:hover {
  background: #f0f0f0;
}

/* Row-based grid: photos.php groups photos into rows of matching orientation
   (two portraits together, or two landscapes together) so a row never mixes
   a tall portrait with a short landscape -- that was leaving a gap under
   whichever photo was shorter. Landscape pairs are scaled up to the same
   full row width as a portrait pair, rather than left at their smaller
   natural size, so both row types read as the same size of "unit." Odd
   photos left without a same-orientation partner get their own single-item
   row. */
.photo-grid {
  display: flex;
  flex-direction: column;
  gap: 2rem;
}
.photo-row {
  display: flex;
  gap: 1.5rem;
  /* A row can end up pairing two different heights (e.g. a landscape next
     to a near-square photo) -- center them on each other instead of
     hugging the shorter one to the top with dead space below it. */
  align-items: center;
}
.photo-row:has(.photo-grid__caption) {
  /* Titled/captioned photos (birds, post office) read better with a clean
     shared top edge across the row -- captions sit directly under each
     photo either way, but a top edge makes the row look intentional
     instead of like the images are floating at random heights. */
  align-items: flex-start;
}
.photo-row--single {
  /* An unpaired photo has no partner to sit next to -- center it in the
     row instead of leaving it flush left with empty space to the right. */
  justify-content: center;
}
.photo-row--single .photo-grid__item {
  max-width: 48%;
}
.photo-grid__item {
  margin: 0;
  flex: 1 1 0;
  min-width: 0;
}
.photo-grid__link {
  display: block;
  background: var(--color-surface);
}
.photo-grid__link img {
  width: 100%;
  height: auto;
}
.photo-grid__caption {
  margin-top: 0.5rem;
  font-family: var(--font-mono);
}
.photo-grid__caption-title {
  display: block;
  text-transform: uppercase;
  font-size: 0.85rem;
  font-weight: 700;
}
.photo-grid__caption-text {
  display: block;
  font-family: var(--font-body);
  color: var(--color-muted);
  font-size: 0.9rem;
  margin-top: 0.25rem;
}

/* ---------- Bird audio play button ---------- */
.bird-audio {
  margin-top: 0.5rem;
}
.bird-audio__row {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
}
.bird-audio__play {
  flex: none;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-surface-text);
  cursor: pointer;
  font-size: 0.8rem;
  line-height: 1;
}
.bird-audio__play:hover {
  background: var(--color-surface-hover);
}
.bird-audio__attribution {
  margin: 0;
  font-size: 0.6rem;
  color: var(--color-muted);
  line-height: 1.4;
}
.bird-audio__attribution a {
  text-decoration: underline;
}

/* Progress bar shared by both the grid play button and the lightbox player.
   Two stacked fills over a track: a faint one for how much has downloaded
   (buffered), a solid one for playback position -- clicking anywhere on the
   track seeks to that point. Hidden until Play is first pressed. */
.audio-progress {
  position: relative;
  margin-top: 0.5rem;
  height: 5px;
  border-radius: 3px;
  background: var(--color-border);
  cursor: pointer;
}
.audio-progress[hidden] {
  display: none;
}
.audio-progress__buffered,
.audio-progress__played {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  border-radius: 3px;
  width: 0%;
  pointer-events: none;
}
.audio-progress__buffered {
  background: var(--color-muted);
  opacity: 0.4;
}
.audio-progress__played {
  background: var(--color-link, var(--color-nav-text));
}

/* ---------- Lightbox ---------- */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 4rem 5rem 2rem;
  background: rgba(20, 18, 16, 0.92);
}
.lightbox[hidden] {
  display: none;
}
.lightbox__stage {
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.lightbox__image {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  cursor: zoom-in;
  transition: transform 0.2s ease;
}
.lightbox__image.is-zoomed {
  transform: scale(1.8);
  cursor: zoom-out;
}
/* Close/prev/next are plain glyphs on the dark backdrop, no button chrome,
   so they read like part of the viewer rather than boxed UI controls. */
.lightbox__close,
.lightbox__prev,
.lightbox__next {
  position: absolute;
  border: none;
  background: none;
  color: var(--color-nav-text);
  font-family: var(--font-mono);
  cursor: pointer;
}
.lightbox__close {
  top: 1.5rem;
  right: 1.5rem;
  text-transform: uppercase;
  font-size: 0.85rem;
  letter-spacing: 0.03em;
}
.lightbox__prev,
.lightbox__next {
  top: 50%;
  transform: translateY(-50%);
  font-size: 2.5rem;
  line-height: 1;
  padding: 0.5rem;
}
.lightbox__prev {
  left: 1rem;
}
.lightbox__next {
  right: 1rem;
}
.lightbox__info {
  flex: none;
  width: 100%;
  max-width: 700px;
  margin-top: 1.5rem;
  text-align: center;
  color: var(--color-nav-text);
}
.lightbox__title {
  margin: 0 0 0.35rem;
  font-family: var(--font-mono);
  text-transform: uppercase;
  font-size: 1.1rem;
  font-weight: 700;
}
.lightbox__caption-text {
  margin: 0;
  font-size: 0.9rem;
  opacity: 0.85;
}
.lightbox__audio {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-top: 0.75rem;
}
.lightbox__audio[hidden] {
  /* display:flex above otherwise beats the browser's default [hidden]
     rule outright -- any author rule wins over that UA default, hidden
     attribute or not, so this has to be spelled out explicitly. */
  display: none;
}
.lightbox__audio-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
}
.lightbox__audio .audio-progress {
  width: 100%;
  max-width: 260px;
}
.lightbox__play {
  flex: none;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-surface-text);
  cursor: pointer;
  font-size: 0.8rem;
}
.lightbox__play:hover {
  background: var(--color-surface-hover);
}
.lightbox__attribution {
  font-size: 0.7rem;
  opacity: 0.85;
  text-align: left;
}
.lightbox__attribution a {
  color: inherit;
  text-decoration: underline;
}
body.lightbox-open {
  overflow: hidden;
}

.back-to-top {
  position: fixed;
  right: 1.5rem;
  bottom: 1.5rem;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  border: 1px solid var(--color-border);
  background: var(--color-nav-bg);
  color: var(--color-nav-text);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
  opacity: 0.6;
  transition: opacity 0.15s ease;
  z-index: 50;
}
.back-to-top:hover {
  opacity: 1;
}
.back-to-top[hidden] {
  display: none;
}

/* =====================================================================
   Responsive
   ===================================================================== */

/* Tablet: collapse the fixed sidebar into a static top bar. */
@media (max-width: 800px) {
  .site-nav--sidebar {
    position: static;
    width: auto;
    height: auto;
    border-right: none;
    border-bottom: 1px solid var(--color-border);
    padding: 1rem 1.25rem;
  }
  .site-nav--sidebar .site-nav__brand {
    margin-bottom: 0.75rem;
  }
  .site-nav--sidebar .site-nav__links--vertical {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 1.25rem;
  }
  .site-nav--sidebar .site-nav__links--vertical li {
    margin-bottom: 0;
  }
  .homepage {
    margin-left: 0;
  }
  .hero {
    height: 70vh;
    /* --hero-padding frames the photo nicely at desktop width, but at
       tablet/phone width that same inset eats a large share of a much
       narrower screen -- looks oddly small and leaves a background-colored
       strip on the sides/bottom instead of a subtle frame. Full-bleed on
       those three sides; keep the top inset so the photo doesn't sit flush
       against the nav bar above it. */
    padding: var(--hero-padding) 0 0;
  }
  .hero__slide {
    inset: var(--hero-padding) 0 0;
  }
}

/* Phone: tighter spacing, larger tap targets, single-column photo grid. */
@media (max-width: 600px) {
  .birding-locations-list,
  .birding-resources-columns {
    grid-template-columns: 1fr;
  }
  .birding-resources-column + .birding-resources-column {
    margin-top: 1rem;
  }
  .site-nav--topbar {
    padding: 0.85rem 0;
  }
  /* Stack brand above links (instead of the default side-by-side, which
     was wrapping into three uneven rows -- brand alone, then HOME|SEARCH,
     then a lone divider + OTHER PHOTOS on its own line below that). */
  .site-nav--topbar .site-nav__inner {
    padding: 0 1.25rem;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.6rem;
  }
  .site-nav--topbar .site-nav__links--horizontal {
    gap: 0.4rem 0.75rem;
  }
  /* Smaller so HOME | SEARCH | OTHER PHOTOS reliably fits on one row at
     phone widths instead of wrapping. */
  .site-nav--topbar .site-nav__links a {
    font-size: 1rem;
  }
  .site-nav--topbar .site-nav__links--horizontal > li:not(:first-child)::before {
    margin-right: 0.75rem;
    font-size: 1.1em;
  }
  /* Homepage mobile menu: a hamburger toggle instead of the tablet's
     wrapped inline links, which read as cramped/unclear at phone width.
     Tapping it turns the whole nav into a full-page overlay -- logo row on
     top with a Close toggle in its place, gallery links stacked below. */
  .site-nav--sidebar {
    padding: 0.85rem 1rem;
  }
  .site-nav--sidebar .site-nav__inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
  }
  .site-nav--sidebar .site-nav__brand {
    margin-bottom: 0;
  }
  .site-nav--sidebar .site-nav__menu-toggle {
    display: inline-flex;
    align-items: center;
  }
  .site-nav--sidebar .site-nav__links--vertical {
    display: none;
  }
  .site-nav--sidebar.is-menu-open {
    position: fixed;
    inset: 0;
    z-index: 950;
    background: var(--color-nav-bg);
    overflow-y: auto;
    border-bottom: none;
  }
  .site-nav--sidebar.is-menu-open .site-nav__inner {
    /* Stays row-direction on purpose -- brand and the Close toggle need to
       stay side by side on their own top line, like the closed state.
       flex-wrap (set above, unconditionally) is what pushes the links list
       onto its own full-width line below, without needing to stack the
       brand/toggle pair too. */
    align-items: center;
    /* Default align-content spreads a wrapped flex container's multiple
       lines out to fill any leftover height -- exactly the "huge gap"
       problem this whole open-state layout keeps tripping on. Pin all
       three lines (brand+toggle, divider, links) to the top instead. */
    align-content: flex-start;
    min-height: 100%;
  }
  .site-nav--sidebar.is-menu-open .site-nav__inner::after {
    /* Full-width divider between the brand/toggle line and the links list
       below -- can't be a border on .site-nav__brand or .site-nav__menu-toggle
       since neither spans the full row width on its own. */
    content: '';
    flex-basis: 100%;
    border-bottom: 1px solid rgba(240, 232, 218, 0.2);
    margin: 0.85rem 0;
    order: 1;
  }
  .site-nav--sidebar.is-menu-open .site-nav__links--vertical {
    display: flex;
    flex-direction: column;
    flex-basis: 100%;
    order: 2;
  }
  .site-nav--sidebar.is-menu-open .site-nav__links--vertical a {
    font-size: 1.6rem;
  }
  .site-nav--sidebar.is-menu-open .site-nav__menu-toggle-open {
    display: none;
  }
  .site-nav--sidebar.is-menu-open .site-nav__menu-toggle-close {
    display: inline;
  }
  body.nav-menu-open {
    overflow: hidden;
  }
  .site-nav__dropdown-menu {
    right: auto;
    left: 0;
  }

  .gallery-page {
    padding: 1.25rem;
  }
  .gallery-page__title {
    font-size: 1.5rem;
  }

  .hero {
    height: 60vh;
    /* A little more breathing room above the photo than the tablet
       breakpoint's plain --hero-padding top inset. */
    padding-top: calc(var(--hero-padding) + 0.75rem);
  }
  .hero__slide {
    top: calc(var(--hero-padding) + 0.75rem);
  }

  .photo-grid {
    gap: 1.75rem;
  }
  .photo-row {
    flex-direction: column;
  }
  .photo-row--single .photo-grid__item {
    max-width: 100%;
  }

  .gallery-map {
    height: 280px;
  }

  .bird-audio__play {
    width: 1.85rem;
    height: 1.85rem;
    font-size: 0.7rem;
  }
  .bird-audio__attribution {
    font-size: 0.55rem;
    line-height: 1.3;
  }

  .lightbox {
    padding: 3.5rem 0.5rem 1.5rem;
  }
  .lightbox__prev {
    left: 0.25rem;
  }
  .lightbox__next {
    right: 0.25rem;
  }
}
