:root {
  --paper: #f6f2e7;
  --paper-alt: #efe8d6;
  --paper-box: #f1ead9;
  --ink: #2b2620;
  --muted: #6b6357;
  --line: #ddd3bd;
  --green: #1f3d2b;
  --accent: #b9532f;

  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-serif: Georgia, "Iowan Old Style", "Palatino Linotype", "Book Antiqua", Palatino, serif;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
}

body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.45;
}

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

/* Header */

.site-header {
  position: sticky;
  top: 0;
  /* Leaflet's own CSS puts its zoom control / popups / attribution at
     z-index up to 1000 (.leaflet-top/.leaflet-bottom, .leaflet-pane
     children) -- on map.html and species.html, scrolling the page past a
     map panel put those controls above this sticky header instead of
     behind it, since 10 lost to Leaflet's 1000. Comfortably above that
     ceiling so the header always wins, on every page (not just the two
     with maps), rather than tracking Leaflet's own value here. */
  z-index: 2000;
  background: var(--paper);
  border-bottom: 1px solid var(--line);
}

/* Top-level MAP/ATLAS switch -- the site's primary navigation, so it's
   sized and weighted to read as such: below the wordmark (not above it,
   where it would read as a status strip rather than a way to navigate),
   its own strip rather than folded into brand-row's flex layout (so it
   doesn't have to compete for space with the wordmark/lang-switch on
   narrow screens), and identical across map.html, atlas.html and
   species.html regardless of what each page's own header-row otherwise
   contains (search box, back link, ...). */
.top-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  padding: 0 1rem 0.85rem;
}

.top-nav-link {
  font-family: var(--font-sans);
  font-size: 0.95rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--muted);
  background: var(--paper-alt);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 0.6rem 1.6rem;
}

.top-nav-link:hover,
.top-nav-link:focus-visible {
  color: var(--green);
  border-color: var(--green);
}

.top-nav-link.active {
  background: var(--green);
  border-color: var(--green);
  color: var(--paper);
}

.header-row {
  padding: 0.75rem 1rem 0.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.brand-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}

.wordmark {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 700;
  font-size: 1.5rem;
  color: var(--green);
  letter-spacing: 0.01em;
}

/* Language switch */

.lang-switch {
  display: flex;
  border: 1px solid var(--line);
  border-radius: 999px;
  overflow: hidden;
  flex: 0 0 auto;
}

.lang-btn {
  font-family: var(--font-sans);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--muted);
  background: var(--paper-alt);
  border: none;
  padding: 0.3rem 0.55rem;
  cursor: pointer;
}

.lang-btn + .lang-btn {
  border-left: 1px solid var(--line);
}

.lang-btn:hover {
  color: var(--green);
}

.lang-btn.active {
  background: var(--green);
  color: var(--paper);
}

.search-box {
  width: 100%;
  font: inherit;
  font-size: 1rem; /* keep >=16px: prevents iOS Safari zooming in on focus */
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--paper-alt);
  color: var(--ink);
}

.search-box:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  background: var(--paper);
}

/* Quick-nav: a quiet table-of-contents strip, visually separated from
   the header/search area above it -- small pills, muted color, no bold
   caps, not meant to read as buttons. */

.quick-nav {
  display: flex;
  gap: 0.3rem;
  overflow-x: auto;
  padding: 0.45rem 1rem;
  background: var(--paper-alt);
  border-top: 1px solid var(--line);
  scrollbar-width: thin;
}

.quick-nav a {
  flex: 0 0 auto;
  font-family: var(--font-sans);
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.01em;
  white-space: nowrap;
  color: var(--muted);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 0.18rem 0.55rem;
}

.quick-nav a:hover,
.quick-nav a:focus-visible {
  color: var(--green);
  border-color: var(--green);
}

/* Layout */

main {
  max-width: 1100px;
  margin: 0 auto;
  padding: 0.75rem 1rem 3rem;
}

.page-title {
  margin: 1.25rem 0 0.25rem;
  font-family: var(--font-serif);
  font-weight: 700;
  font-size: 1.3rem;
  color: var(--green);
}

.status {
  margin: 0.75rem 0;
  font-size: 0.875rem;
  color: var(--muted);
}

.empty-state {
  color: var(--muted);
  padding: 2rem 0;
  text-align: center;
}

/* Order sections -- no collapse, the atlas is one continuous page */

.order-group {
  margin-top: 1.5rem;
  border-bottom: 1px solid var(--line);
  /* Quick-nav jumps land here via scrollIntoView, which would otherwise put
     the section flush against the real viewport top -- underneath the
     sticky header, which visually occupies that space regardless. --header-h
     is measured live in app.js (not a guessed constant): the header's own
     height genuinely varies by viewport width (row vs. wrapped-column
     layout) and content (quick-nav can wrap), so no single CSS value stays
     correct across breakpoints. The 12px is just breathing room. */
  scroll-margin-top: calc(var(--header-h, 0px) + 12px);
}

.order-header {
  padding: 0.6rem 0.1rem;
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  column-gap: 0.6rem;
}

.order-name {
  font-family: var(--font-sans);
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--green);
}

.order-desc {
  font-family: var(--font-sans);
  font-size: 0.78rem;
  font-style: italic;
  color: var(--muted);
}

.order-body {
  padding-bottom: 0.75rem;
}

/* Family "boxes" holding the card grid */

.family-box {
  margin: 0.6rem 0.1rem;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--paper-box);
  padding: 0 0.65rem 0.65rem;
}

.family-header {
  padding: 0.55rem 0 0.4rem;
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  column-gap: 0.5rem;
}

.family-name {
  font-family: var(--font-sans);
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--ink);
}

.family-desc {
  font-family: var(--font-sans);
  font-size: 0.72rem;
  font-style: italic;
  color: var(--muted);
}

/* Card grid: 2 per row on phones per the brief */

.card-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.6rem;
}

.species-card {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 0.5rem;
  /* Without this, a CSS Grid item's automatic minimum width defaults to
     its content's min-content size -- for a grid item containing an <img>,
     that's the image's own INTRINSIC width (e.g. 1024px for the "large"
     iNaturalist size), regardless of any width:100%/aspect-ratio set on
     the image itself. That silently forced this card's own grid column
     wider than its "1fr" siblings once real photos replaced the empty
     placeholder spans, breaking the grid's uniformity. min-width: 0 is the
     standard fix: it lets the item shrink to the track's actual size
     instead of being floored by its content. */
  min-width: 0;
}

.species-card:hover,
.species-card:focus-visible {
  border-color: var(--accent);
}

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

.card-dex {
  font-family: var(--font-sans);
  font-size: 0.68rem;
  font-weight: 600;
  color: var(--muted);
}

.card-thumb {
  display: block;
  width: 100%;
  max-width: 100%;
  aspect-ratio: 1 / 1;
  background: var(--paper-alt);
  border: 1px solid var(--line);
  border-radius: 4px;
  object-fit: cover; /* only affects an <img> -- a no-op on the plain placeholder <span> used when a species has no photo */
}

/* Compact photo credit -- atlas cards and rank rows (species.image_attribution,
   see CLAUDE.md's "Species photo cascade"). Deliberately reuses the SAME
   attribution string shown in full on the species page rather than a
   shortened variant: ellipsis truncation here still leaves it legible as
   "there is a credit", the full text is one tap/click away on the species
   page, and the untruncated string is still available via the title
   attribute (a screen reader gets the full aria-label regardless of visual
   truncation). */
.photo-credit {
  display: block;
  font-family: var(--font-sans);
  font-size: 0.62rem;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.card-name {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 0.92rem;
  line-height: 1.25;
  color: var(--ink);
}

.card-common {
  font-family: var(--font-sans);
  font-size: 0.76rem;
  color: var(--muted);
}

/* Shown only when a search result matched on a vernacular name in a
   language other than the one currently displayed (see matchInfo in
   app.js) -- explains why the card appeared, distinct from .card-common
   (italic + accent, not the plain muted tone the always-shown name uses). */
.card-match-tag {
  font-family: var(--font-sans);
  font-size: 0.72rem;
  font-style: italic;
  color: var(--accent);
}

/* Footer */

.site-footer {
  border-top: 1px solid var(--line);
  padding: 1rem;
  text-align: center;
}

.site-footer p {
  margin: 0;
  font-family: var(--font-sans);
  font-size: 0.72rem;
  color: var(--muted);
}

.site-footer a {
  color: var(--muted);
  text-decoration: underline;
}

.site-footer a:hover,
.site-footer a:focus-visible {
  color: var(--green);
}

/* Key figures (species page's total-records/global-rank row, and the region
   map's side-panel total-records/species-count row) and section titles
   (species page's Seasonality/Distribution headings, and the region panel's
   Most common/Rarest headings). */

.key-figures {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
  padding: 1rem 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  margin: 0.5rem 0;
}

.figure {
  display: flex;
  flex-direction: column;
}

.figure-value {
  font-family: var(--font-serif);
  font-weight: 700;
  font-size: 1.4rem;
  color: var(--green);
}

.figure-label {
  font-family: var(--font-sans);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
}

.section-title {
  margin: 1.5rem 0 0.5rem;
  font-family: var(--font-serif);
  font-weight: 700;
  font-size: 1.15rem;
  color: var(--green);
}

/* Month filter, region selector, and map panels/legend/popup -- shared by
   the species map (species.html) and the region map (map.html), so this
   lives here rather than being duplicated in species.css and map.css. */

.month-filter {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  margin-bottom: 0.6rem;
}

.month-btn {
  font-family: var(--font-sans);
  font-size: 0.68rem;
  font-weight: 500;
  color: var(--muted);
  background: var(--paper-alt);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 0.22rem 0.6rem;
  cursor: pointer;
}

.month-btn:hover,
.month-btn:focus-visible {
  color: var(--green);
  border-color: var(--green);
}

.month-btn.active {
  background: var(--green);
  border-color: var(--green);
  color: var(--paper);
}

.region-selector {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  margin-bottom: 0.6rem;
}

.region-btn {
  font-family: var(--font-sans);
  font-size: 0.68rem;
  font-weight: 600;
  color: var(--muted);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 0.22rem 0.6rem;
  cursor: pointer;
}

.region-btn:hover,
.region-btn:focus-visible {
  color: var(--green);
  border-color: var(--green);
}

.region-btn.active {
  background: var(--green);
  border-color: var(--green);
  color: var(--paper);
}

/* Archipelagos are rendered as multiple side-by-side panels (island groups
   are too far apart to share one sane frame) -- mainland is just a
   single-panel group so it reuses the exact same layout, not a special
   case. Row on wide screens, column on narrow ones (region-selector /
   month-filter's own breakpoint below matches). */
.map-panels {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.map-panel-wrap {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  flex: 1 1 0%;
  min-width: 0; /* let flex children shrink below their content size */
}

.map-panel-label {
  font-family: var(--font-sans);
  font-size: 0.68rem;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.map-panel {
  width: 100%;
  height: 45vh;
  min-height: 240px;
  border: 1px solid var(--line);
  border-radius: 6px;
}

/* .map-panel, not a bare class: leaflet.css loads after this stylesheet and
   its own .leaflet-container rule sets a default grey background at the
   same specificity, so a plain .map-panel background rule loses the cascade
   and never shows without the compound selector raising specificity. Muted
   blue-grey "sea" -- land is the light paper tone (LAND_FILL in common.js,
   a literal color string since Leaflet needs one there, not a CSS var), so
   land vs. sea now reads as a real, unambiguous distinction, not two shades
   of the same paper hue. */
.map-panel.leaflet-container {
  background: #c2cdd2;
}

@media (min-width: 640px) {
  .map-panels {
    flex-direction: row;
    align-items: stretch;
    height: 60vh;
    min-height: 320px;
  }

  .map-panel {
    height: 100%;
  }
}

.map-legend {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 0.4rem 0.5rem;
  font-family: var(--font-sans);
  font-size: 0.68rem;
  color: var(--ink);
  line-height: 1.5;
}

.legend-row {
  display: flex;
  align-items: center;
  gap: 0.35rem;
}

.legend-swatch {
  display: inline-block;
  width: 0.7rem;
  height: 0.7rem;
  border: 1px solid var(--line);
  border-radius: 2px;
  flex: 0 0 auto;
}

.map-status {
  margin: 0.5rem 0 0;
  font-family: var(--font-sans);
  font-size: 0.8rem;
  color: var(--muted);
}

.map-popup {
  font-family: var(--font-sans);
  font-size: 0.85rem;
  color: var(--ink);
}

.map-popup a {
  color: var(--green);
  font-weight: 600;
}

/* Cladogram (static/cladogram.js) -- shared by tree.html's full tree view
   and species.html's "Position in the tree of life" section, both of which
   only build the small node graph and let cladogram.js lay it out and draw
   it as plain SVG (no graph library). */

.cladogram-canvas {
  overflow-x: auto; /* a deep/wide slice can exceed the viewport -- scroll it, never wrap or clip */
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--paper-box);
  padding: 0.5rem;
}

.cladogram-svg {
  display: block;
  font-family: var(--font-sans);
}

.cladogram-edge {
  stroke: var(--muted);
  stroke-width: 1.5;
}

.cladogram-dot {
  fill: var(--green);
}

.cladogram-label {
  font-size: 0.78rem;
  fill: var(--ink);
}

.cladogram-node.is-tip .cladogram-label {
  font-family: var(--font-serif);
  font-style: italic;
}

.cladogram-node.is-internal .cladogram-label {
  font-size: 0.72rem;
  fill: var(--muted);
}

/* A tip with no resolved species (see CLAUDE.md's "not every species has a
   phylogeny placement") -- dimmed and unlinked, never mistaken for a real
   result. */
.cladogram-node.is-muted .cladogram-dot {
  fill: var(--line);
}

.cladogram-node.is-muted .cladogram-label {
  fill: var(--muted);
  font-style: italic;
}

.cladogram-node.is-highlighted .cladogram-dot {
  fill: var(--accent);
}

.cladogram-node.is-highlighted .cladogram-label {
  font-weight: 700;
  fill: var(--accent);
}

/* tree.js's search/deep-link target -- applied directly to a node after the
   fact (not baked into the initial render like is-highlighted above), since
   which tip is "found" changes without a full re-render. */
.cladogram-node.is-search-highlight .cladogram-dot {
  fill: var(--accent);
}

.cladogram-node.is-search-highlight .cladogram-label {
  font-weight: 700;
  fill: var(--accent);
}

.cladogram-node a .cladogram-label {
  fill: var(--green);
}

.cladogram-node a:hover .cladogram-label,
.cladogram-node a:focus-visible .cladogram-label {
  fill: var(--accent);
}

.cladogram-node.is-clickable {
  cursor: pointer;
}

.cladogram-node.is-clickable:hover .cladogram-label,
.cladogram-node.is-clickable:focus-visible .cladogram-label {
  fill: var(--green);
}

.cladogram-node.is-clickable:focus-visible .cladogram-dot {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* Aligned tip labels (tree.js's full-tree view, renderCladogram's alignTips
   option): a dashed guide from the tip's real branch position out to the
   shared label column on the right -- the dot itself stays put so the
   topology reads correctly, only the label is flush-aligned. */
.cladogram-tip-extension {
  stroke: var(--line);
  stroke-width: 1;
  stroke-dasharray: 2 3;
}

/* A clade the user has manually collapsed (tree.js) -- children hidden,
   drawn as a solid larger marker so it reads as "more here", not a dead end. */
.cladogram-node.is-collapsed .cladogram-dot {
  fill: var(--accent);
}

.cladogram-node.is-collapsed .cladogram-label {
  fill: var(--accent);
  font-weight: 600;
}

/* Wider screens: more nav breathing room, more columns per row */

@media (min-width: 480px) {
  .card-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (min-width: 640px) {
  .top-nav {
    padding: 0 1.5rem 1rem;
  }

  .top-nav-link {
    font-size: 1.05rem;
    padding: 0.7rem 2rem;
  }

  .header-row {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    padding: 1rem 1.5rem 0.5rem;
  }

  .wordmark {
    font-size: 1.75rem;
  }

  .search-box {
    width: 280px;
  }

  .quick-nav {
    padding: 0.45rem 1.5rem;
  }

  main {
    padding: 1rem 1.5rem 4rem;
  }

  .card-grid {
    grid-template-columns: repeat(4, 1fr);
  }
}

@media (min-width: 900px) {
  .card-grid {
    grid-template-columns: repeat(5, 1fr);
  }
}
