:root {
  /* Palette sourced from the FBA Threat Database logo's blood-red map. */
  --bg: #faf5f5;
  --surface: #ffffff;
  --surface-alt: #f5eded;
  --border: #e3cdcf;
  --border-strong: #c79ea1;
  --text: #241315;
  --muted: #6b5457;
  --heading: #3a1215;
  --primary: #c6202c;
  --primary-dark: #89161e;
  --primary-soft: #f8e7e9;
  --primary-contrast: #ffffff;
  --glass-bg: rgba(255, 255, 255, 0.7);
  --glass-border: rgba(199, 158, 161, 0.55);
  --glass-blur: blur(16px);
  --glow: 0 8px 26px rgba(198, 32, 44, 0.14);
  --glow-strong: 0 12px 36px rgba(198, 32, 44, 0.22);
  --shadow: 0 10px 30px rgba(36, 19, 21, 0.08);
  --shadow-soft: 0 4px 12px rgba(36, 19, 21, 0.06);
  --radius: 16px;
  --radius-sm: 10px;
  --max-width: 1180px;
  --focus: #89161e;
}

/* The Anti-Black List pages (search, detail, submission form) use a
   neutral gray palette instead of the site's red -- same component
   styling everywhere (buttons, tags, links, focus rings all read these
   variables), so overriding the tokens here is enough to re-theme
   every button/badge/link on those pages without touching their
   individual CSS rules. Applied via <body class="theme-gray">, set
   only on antiblack.php, search_antiblack.php, and
   submit_antiblack.php. */
body.theme-gray {
  --surface-alt: #ececea;
  --border: #dcdcdc;
  --border-strong: #a8a8a8;
  --primary: #52514f;
  --primary-dark: #2f2e2d;
  --primary-soft: #eceae8;
  --primary-contrast: #ffffff;
  --glass-border: rgba(140, 140, 140, 0.4);
  --glow: 0 8px 26px rgba(50, 50, 50, 0.14);
  --glow-strong: 0 12px 36px rgba(50, 50, 50, 0.22);
  --focus: #2f2e2d;
}

/* .status-operating and .status-shutdown are hardcoded colors rather
   than reading --primary (they're shared with admin views like the
   activity feed, which should stay in the site's normal colors there)
   -- override them specifically within the gray theme instead. Kept
   as two distinct shades (lighter = still operating, darker = shut
   down) rather than one flat gray, so the status is still readable
   at a glance. */
body.theme-gray .status-operating {
  background: #8a8886;
  color: #fff;
}

body.theme-gray .status-shutdown {
  background: #4a4948;
  color: #fff;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  background: var(--bg);
  color: var(--text);
  line-height: 1.55;
  text-rendering: optimizeLegibility;
}

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

a {
  color: var(--primary);
  text-underline-offset: 0.18em;
  text-decoration-thickness: 1.5px;
}

a:hover {
  color: var(--primary-dark);
}

a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 3px;
}

button,
input[type="submit"] {
  min-height: 46px;
  padding: 0.8rem 1.05rem;
  border: 1px solid transparent;
  border-radius: 999px;
  background: var(--primary);
  color: var(--primary-contrast);
  font-weight: 700;
  cursor: pointer;
}

button:hover,
input[type="submit"]:hover {
  background: var(--primary-dark);
  box-shadow: var(--glow-strong);
}

.skip-link {
  position: absolute;
  left: 1rem;
  top: -4rem;
  z-index: 1000;
  background: var(--primary-dark);
  color: var(--primary-contrast);
  padding: 0.85rem 1rem;
  border-radius: 999px;
  transition: top 0.2s ease;
}

.skip-link:focus {
  top: 1rem;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.site-header,
.site-footer,
.hero,
.search,
.card,
.business-card,
.form-card,
.empty {
  position: relative;
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  background: var(--glass-bg);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: var(--shadow-soft);
  /* Ported from the B1 Rolodex -- without this, border-color/box-shadow/
     transform hover changes (below, and on .grid .card:hover) snap
     instantly instead of floating smoothly into place. */
  transition: box-shadow 0.2s ease, border-color 0.2s ease, transform 0.2s ease;
}

/* Fallback for browsers without backdrop-filter support: a solid surface
   instead of a half-transparent panel over unpredictable content. */
@supports not (backdrop-filter: blur(1px)) {
  .site-header,
  .site-footer,
  .hero,
  .search,
  .card,
  .business-card,
  .form-card,
  .empty {
    background: var(--surface);
  }
}

.site-header {
  max-width: var(--max-width);
  margin: 1rem auto 1.25rem;
  padding: 0.85rem 1.1rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  position: sticky;
  top: 0.75rem;
  z-index: 40;
}

.site-brand {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-width: 0;
}

.logo-link {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
}

.logo {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.brand-copy {
  min-width: 0;
}

.site-title {
  display: inline-block;
  font-size: 1.35rem;
  font-weight: 800;
  color: var(--heading);
  text-decoration: none;
}

.site-tagline {
  margin: 0.2rem 0 0;
  color: var(--muted);
  font-size: 0.95rem;
}

/* The tagline under the site title ("A Safety & Accountability Resource
   for FBAs") felt like too much competing text in the header on phone
   and tablet screens, where it's squeezed right up against the logo and
   hamburger menu. Laptop and desktop have the room to spare, so it stays
   there; 900px matches the site's existing tablet-vs-laptop cutoff used
   elsewhere (e.g. the footer columns below). The site title itself and
   the logo are untouched at every width. */
@media (max-width: 900px) {
  .site-tagline {
    display: none;
  }
}

/* --- Hamburger nav ---------------------------------------------------
   A plain <button id="navToggle"> + <nav id="siteNav">, toggled by JS in
   footer.php (adds/removes .is-open, flips aria-expanded). The nav lives
   inside a dropdown panel behind the hamburger at every screen width, not
   just on mobile. */
.nav-hamburger {
  position: relative;
  margin-left: auto;
}

.hamburger-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--heading);
  cursor: pointer;
}

.hamburger-icon-open,
.hamburger-icon-close {
  width: 24px;
  height: 24px;
}

/* Two separate, explicit SVGs swapped by aria-expanded state, rather than
   one icon animated with CSS transforms. */
.hamburger-icon-close {
  display: none;
}

.hamburger-toggle[aria-expanded="true"] .hamburger-icon-open {
  display: none;
}

.hamburger-toggle[aria-expanded="true"] .hamburger-icon-close {
  display: block;
}

.hamburger-toggle[aria-expanded="true"] {
  background: var(--primary-soft);
  border-color: var(--primary);
  color: var(--primary-dark);
}

.site-nav {
  position: absolute;
  right: 0;
  top: calc(100% + 0.5rem);
  z-index: 45;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  min-width: 240px;
  padding: 0.6rem;
  /* Fully opaque, not the shared glass treatment used elsewhere -- a
     dropdown menu sits directly over page content and needs to stay
     legible. */
  background: var(--surface);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  box-shadow: var(--glow);
  /* With every nested dropdown open (Admin alone is 7+ links now), the
     panel's natural height can exceed the viewport -- without a cap and
     its own scrollbar, the bottom entries (Banned IPs, Logout, etc.) end
     up pushed below the visible page with no way to reach them. */
  max-height: calc(100vh - 90px);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

.site-nav.hidden,
html.has-js .site-nav:not(.is-open) {
  display: none;
}

.site-nav a {
  display: flex;
  align-items: center;
  min-height: 42px;
  padding: 0.55rem 0.8rem;
  border-radius: var(--radius-sm);
  color: var(--heading);
  text-decoration: none;
  font-weight: 650;
}

.site-nav a:hover {
  background: var(--primary-soft);
  color: var(--primary-dark);
}

.nav-dropdown {
  position: relative;
}

.nav-dropdown summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 42px;
  padding: 0.55rem 0.8rem;
  border-radius: var(--radius-sm);
  color: var(--heading);
  font-weight: 650;
  cursor: pointer;
  list-style: none;
  transition: background 0.15s ease, color 0.15s ease;
}

.nav-dropdown summary::-webkit-details-marker {
  display: none;
}

.nav-dropdown summary::marker {
  content: "";
}

.nav-dropdown summary::after {
  content: "";
  width: 7px;
  height: 7px;
  flex: 0 0 auto;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
  transition: transform 0.15s ease;
}

.nav-dropdown[open] summary::after {
  transform: rotate(-135deg);
}

.nav-dropdown summary:hover {
  background: var(--primary-soft);
  color: var(--primary-dark);
}

.nav-dropdown-menu {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.25rem 0 0.25rem 0.75rem;
}

.nav-dropdown-menu a {
  padding: 0.5rem 0.7rem;
  border-radius: var(--radius-sm);
  color: var(--heading);
  text-decoration: none;
  font-weight: 600;
  font-size: 0.92rem;
}

.nav-dropdown-menu a:hover {
  background: var(--primary-soft);
  color: var(--primary-dark);
}

/* Pending-submissions count next to "Review Submissions" in the Admin
   nav (header.php) -- same small red "there's something waiting on you"
   treatment as the moderation hub badges this was modeled on. */
.nav-badge {
  display: inline-block;
  min-width: 1.1rem;
  margin-left: 0.3rem;
  padding: 0.05rem 0.35rem;
  border-radius: 999px;
  background: var(--primary);
  color: var(--primary-contrast);
  font-size: 0.72rem;
  font-weight: 700;
  text-align: center;
  line-height: 1.3;
}

/* admin_review_submissions.php's type filter -- marks which filter is
   currently active. */
.is-current-filter {
  text-decoration: underline;
  font-weight: 700;
}

@media (max-width: 640px) {
  .site-nav {
    right: -0.6rem;
    min-width: 220px;
    max-width: calc(100vw - 2rem);
  }
}

.site-main,
.wrap {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0 1.1rem 2.5rem;
}

.hero {
  padding: 1.4rem;
  margin-bottom: 1.2rem;
}

.hero h1 {
  margin: 0 0 0.35rem;
  font-size: clamp(1.6rem, 2.5vw, 2.2rem);
  line-height: 1.15;
  color: var(--heading);
}

.hero p {
  margin: 0;
  color: var(--muted);
}

.route-disclaimer {
  margin-top: 0.5rem;
  /* No max-width here on purpose (every other .hero p on the site wraps
     at the hero's full width -- this one used to be capped at 60ch for
     "readable line length", but on a laptop/desktop-width screen the
     .hero card is much wider than 60ch, so the text ended up looking
     like an orphaned narrow column stuck to the left with a big empty
     gap next to it instead of a normal paragraph. Letting it wrap at
     the hero's own width (same as the H1 above it) fixes that. */
}

/* Keeps text in the page (readable by search engines and screen
   readers) without showing it on screen -- standard accessible-hiding
   technique, not display:none (which some crawlers discount) and not
   visibility:hidden (which still reserves layout space). Used for the
   long intro paragraphs on the homepage and Anti-Black List search page
   so that SEO copy doesn't eat into limited above-the-fold space. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.search {
  max-width: 640px;
  margin-left: auto;
  margin-right: auto;
  padding: 1rem;
  margin-bottom: 1.2rem;
}

/* The primary text box + the Search submit button -- the one prominent
   row every visitor is meant to use first. */
.search-main {
  display: flex;
  gap: 0.75rem;
}

.search-main input[type="text"] {
  flex: 1;
  margin-bottom: 0;
}

/* Secondary refinements (danger level / status, radius, Near Me) --
   deliberately smaller and a muted gray-pink tone (var(--surface-alt) /
   var(--muted), the same "quiet" tokens used elsewhere on the site, e.g.
   the map's filter panel) so they read as optional filters rather than
   competing with the main Search button for attention. Sits below the
   main row rather than crammed into the same line. */
.search-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.75rem;
}

.search-filters select,
.search-filters .filter-btn {
  width: auto;
  min-height: 34px;
  margin-bottom: 0;
  padding: 0.35rem 0.75rem;
  font-size: 0.85rem;
  font-weight: 650;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface-alt);
  color: var(--muted);
}

.search-filters .filter-btn {
  cursor: pointer;
}

/* "Near Me" turned on -- give it a little color so it's clear the
   filter is active, without going back to the loud primary red. */
.search-filters .filter-btn.is-active {
  background: var(--primary-soft);
  color: var(--primary-dark);
  border-color: var(--border-strong);
}

@media (max-width: 480px) {
  .search-main {
    flex-direction: column;
  }
}

/* Universal spacing between a question (label) and its input box, and
   between one field and the next -- applies everywhere on the site
   (threat, anti-black list, blog, login, etc. forms) without needing to
   remember to touch every individual form file. Deliberately only adds
   margin here, not width/border/padding, so it can't conflict with the
   field styling below or with things like inline search boxes that
   aren't meant to be full-width. */
label {
  display: block;
  margin-top: 1rem;
  margin-bottom: 0.35rem;
  font-weight: 600;
  color: var(--heading);
}

input[type="text"],
input[type="search"],
input[type="email"],
input[type="tel"],
input[type="url"],
input[type="password"],
input[type="number"],
input[type="date"],
input[type="file"],
textarea,
select {
  width: 100%;
  min-height: 48px;
  margin-bottom: 0.6rem;
  padding: 0.8rem 0.95rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  font: inherit;
}

textarea {
  min-height: 140px;
  resize: vertical;
}

/* Native <select> keeps the browser's own compact sizing rather than the
   48px/full-width treatment meant for typed fields -- a dropdown reads
   oddly stretched edge-to-edge and doesn't need the extra height. */
select {
  width: auto;
  min-height: 40px;
  padding: 0.55rem 0.8rem;
}

/* Real multi-field forms (add/edit threat, add/edit anti-black list entry,
   blog editor, etc.) want their <select> dropdowns matching the
   full-width look of the text fields around them, unlike a standalone
   filter/utility dropdown (e.g. a search sort-order picker) which reads
   better compact. */
.form-card select {
  width: 100%;
  min-height: 48px;
  padding: 0.8rem 0.95rem;
}

.search input[type="text"],
.search input[type="search"],
.search-form input[type="search"],
.search-form input[type="text"] {
  margin-bottom: 0;
}

.meta,
.topbar {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  color: var(--muted);
  margin: 0 0 1rem;
}

/* On the search results pages, .meta (the "X results / page Y of Z"
   line) now sits below the pager instead of above the results -- give
   it its own top spacing without touching .topbar, which is a
   different, unrelated admin-page component that happens to share the
   base rule above. */
.meta {
  margin-top: 1.25rem;
}

.text-center {
  text-align: center;
}

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 1rem;
}

.card,
.business-card,
.form-card {
  padding: 1.15rem;
}

/* Route Planner's Start/Destination fields (route_planner.php) -- side by
   side on anything wide enough to comfortably fit both (laptop/desktop),
   stacked back to normal full-width fields below the mobile breakpoint.
   Each field keeps its own label/input exactly as a normal field would;
   this only changes how the pair of them is laid out as a group. */
.route-fields-row {
  display: flex;
  gap: 1rem;
}

.route-fields-row .route-field {
  flex: 1 1 0;
  min-width: 0;
}

/* Lines up a field with no label of its own (the International Driving
   toggle) with the bottom edge of sibling fields that do have a label
   above their control (the radius/danger-level selects). */
.route-fields-row .route-field.align-end {
  display: flex;
  align-items: flex-end;
}

@media (max-width: 640px) {
  .route-fields-row {
    flex-direction: column;
    gap: 0;
  }

  /* The "this isn't a turn-by-turn GPS" disclaimer on route_planner.php --
     worth keeping for desktop/tablet visitors planning ahead, but on a
     phone it just pushes the actual Start/Destination fields further
     down the screen, so it's dropped here rather than shown. */
  .route-disclaimer {
    display: none;
  }
}

/* Tablet widths (641-900px): wide enough that Start/Destination still
   share a row fine, but the SECOND row -- radius select, danger-level
   select, and the International Driving toggle, three equal flex items
   via .route-fields-row above -- were each getting squeezed to roughly a
   third of that width. A <select>'s text and the toggle's icon+label
   wrapped/overlapped at that width, which is what made this row look
   misaligned on a tablet specifically (not phone-narrow enough to already
   hit the stacking rule above, not wide enough for three columns to
   breathe). Stacking just this row -- not the Start/Destination one --
   fixes that without changing anything that wasn't actually broken. */
@media (min-width: 641px) and (max-width: 900px) {
  .route-filters-row {
    flex-direction: column;
    gap: 0.75rem;
  }

  .route-filters-row .route-field.align-end {
    align-items: flex-start;
  }
}

/* "Edit search" minimize toggle on route_planner.php -- shown once a
   route is already on screen, so the Start/Destination/radius/danger-
   level form (otherwise always fully expanded) doesn't just sit there
   taking up space above the map and results the person actually came
   back to look at. Starts collapsed in that case (see the PHP), with
   this one-line button to reopen it for editing. Visually matches the
   "Search & Filters" minimize button on the map pages (.map-panel-toggle
   in threat.css), but defined here instead since this page doesn't load
   that stylesheet. */
.route-search-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  min-height: 38px;
  padding: 0.5rem 0.7rem;
  margin-bottom: 0.5rem;
  border: none;
  border-radius: var(--radius-sm);
  background: var(--surface-alt);
  color: var(--heading);
  font-weight: 700;
  font-size: 0.9rem;
  cursor: pointer;
}

.route-search-body.is-collapsed {
  display: none;
}

/* "International Driving" toggle on route_planner.php -- a plain,
   visible checkbox right next to the passport icon and wording (not a
   button that fills in when checked), lined up with the radius/danger-
   level selects via .route-field.align-end. */
.passport-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  cursor: pointer;
  user-select: none;
  font-weight: 600;
  color: var(--text);
}

.passport-toggle input[type="checkbox"] {
  width: 1.2rem;
  height: 1.2rem;
  margin: 0;
  accent-color: var(--primary);
  cursor: pointer;
}

.passport-toggle .passport-icon {
  font-size: 1.2rem;
  line-height: 1;
}

.card:hover {
  border-color: var(--border-strong);
}

/* B1 Rolodex-style hover for clickable result cards specifically (the
   search/listing cards inside a .grid, not every .card site-wide --
   content cards like About/FAQ sections keep the plain border-only
   hover above). The card floats up slightly with a soft glow behind it
   via the bigger box-shadow, and the border picks up the site's accent
   color -- no title text color change, no underline. That's deliberate:
   the card itself is the whole click target and gives all the hover
   feedback on its own, so the text inside doesn't also need to react. */
.grid .card:hover {
  border-color: var(--primary);
  box-shadow: var(--shadow);
  transform: translateY(-2px);
}

.name {
  margin: 0 0 0.45rem;
  font-size: 1.15rem;
  line-height: 1.25;
}

.name a {
  color: var(--heading);
  text-decoration: none;
}

.name a:hover {
  color: var(--primary);
  text-decoration: underline;
}

.small {
  font-size: 0.95rem;
}

.muted {
  color: var(--muted);
}

.tag {
  display: inline-flex;
  align-items: center;
  min-height: 32px;
  padding: 0.2rem 0.7rem;
  margin: 0.35rem 0.35rem 0.25rem 0;
  border-radius: 999px;
  background: var(--primary-soft);
  color: var(--primary-dark);
  border: 1px solid var(--border-strong);
  font-size: 0.88rem;
  font-weight: 650;
}

.empty {
  padding: 1.2rem;
  color: var(--muted);
  border-style: dashed;
}

.pager {
  margin-top: 1.25rem;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem;
}

.pager a {
  min-width: 42px;
  min-height: 42px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.45rem 0.85rem;
  border-radius: 12px;
  text-decoration: none;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.9);
  color: var(--heading);
}

.pager a.active {
  background: var(--primary);
  color: var(--primary-contrast);
  border-color: var(--primary);
}

.pager-ellipsis {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 42px;
  min-height: 42px;
  color: var(--muted);
}

/* Cross-links shown underneath pagination -- "submit a threat", "suggest
   an adjustment", and the reciprocal link between the two search pages.
   Kept visually quiet (small, muted) since it's a secondary nudge, not
   a call to action competing with the results above it. */
.pager-links {
  margin-top: 0.9rem;
  padding-top: 0.9rem;
  border-top: 1px solid var(--border);
  color: var(--muted);
  font-size: 0.88rem;
  line-height: 1.6;
}

.pager-links p {
  margin: 0.25rem 0;
}

.site-footer {
  max-width: var(--max-width);
  margin: 0 auto 1.25rem;
  padding: 1.1rem;
  color: var(--muted);
}

.footer-top {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 2.5rem;
}

.footer-intro {
  max-width: 380px;
}

.footer-intro-title {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-weight: 800;
  font-size: 1.1rem;
  color: var(--heading);
  text-decoration: none;
}

.footer-intro-logo {
  width: 24px;
  height: 24px;
  object-fit: contain;
  flex: 0 0 auto;
}

.footer-intro-title:hover {
  color: var(--primary-dark);
}

.footer-intro p {
  margin: 0.5rem 0 1.1rem;
  color: var(--muted);
  font-size: 0.92rem;
  line-height: 1.5;
}

.footer-social {
  margin: 0;
}

/* Right-hand side: nav columns as a group, pushed to the right edge of
   the footer via the parent .footer-top's justify-content: space-between
   -- but the LINK TEXT inside each column stays left-aligned to its own
   column (not to the footer as a whole), which is what actually reads
   as tidy stacked lists rather than a ragged right edge. Matches the B1
   Rolodex site's own footer layout exactly. */
.footer-columns {
  display: flex;
  flex: 1 1 auto;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 2.5rem 3.5rem;
  text-align: left;
}

.footer-nav-group-stack {
  display: flex;
  flex-direction: column;
  gap: 1.8rem;
}

.footer-nav-column--stacked {
  gap: 0.45rem;
}

.footer-nav-column--right {
  text-align: left;
}

.footer-nav-column {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  min-width: 160px;
}

.footer-nav-column a {
  color: var(--muted);
  text-decoration: none;
  font-size: 0.92rem;
}

.footer-nav-column a:hover {
  color: var(--primary-dark);
  text-decoration: underline;
}

.social-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.footer-label {
  margin: 0 0 0.6rem;
  font-weight: 700;
  color: var(--heading);
}

.footer-label--sub {
  margin-top: 1.1rem;
}

.footer-label--follow {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--muted);
  margin-bottom: 0.5rem;
}

.social-links a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border-radius: var(--radius-sm);
  border: 1px solid var(--glass-border);
  background: var(--glass-bg);
  color: var(--heading);
  text-decoration: none;
}

.social-links a svg {
  width: 16px;
  height: 16px;
}

.social-links a:hover {
  background: var(--primary-soft);
  color: var(--primary-dark);
  border-color: var(--primary);
}

@media (max-width: 900px) {
  /* Real single-column stacking, not just wrapping -- .footer-columns
     uses justify-content:flex-end for its desktop right-aligned layout,
     and if that's still active while wrapping on a narrower screen,
     each wrapped row right-aligns independently at whatever width it
     happens to be, producing a staggered "staircase" effect (each row
     starting at a different horizontal position) instead of a clean
     stack. Once everything is flex-direction:column with align-items:
     flex-start, there's no horizontal justification left to cause that.
     900px rather than a typical mobile-only 640px breakpoint -- the
     footer's side-by-side layout (intro block + nav columns) needs
     more room than most tablets provide even in landscape, so a
     mobile-only breakpoint left tablets hitting the same staircase
     issue phones originally had. */
  .footer-top,
  .footer-columns {
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-start;
    width: 100%;
    gap: 1.75rem;
  }

  /* On desktop, .footer-nav-group-stack groups two columns together (About+
     Legal in one group, Discover+Other Resources in the other) so each
     group can be positioned as a pair. On mobile/tablet that grouping is
     exactly what was pinning Legal right after About/FBA Threat Database --
     "order" only ever reorders siblings within the SAME flex container, and
     Legal's sibling was About, not Discover or Other Resources. display:
     contents removes the group wrapper from layout entirely (it stays in
     the DOM/accessibility tree, nothing visually changes structurally) so
     all four nav columns become direct children of .footer-columns, which
     is already flex-direction:column above -- that's what lets the "order"
     values below actually reorder across the full set, not just within a
     pair. */
  .footer-nav-group-stack {
    display: contents;
  }

  .footer-nav-column {
    min-width: 0;
    width: 100%;
  }

  /* Mobile/tablet-only reading order: FBA Threat Database, Discover, Other
     Resources, Legal. Desktop keeps its own two-group side-by-side layout
     untouched -- these "order" values only apply inside this max-width:900px
     block. */
  .footer-col-about {
    order: 1;
  }

  .footer-col-discover {
    order: 2;
  }

  .footer-col-other {
    order: 3;
  }

  .footer-col-legal {
    order: 4;
  }

  .footer-intro {
    max-width: 100%;
  }
}

/* --- Share widget ------------------------------------------------------
   Small icon row (share_button.php); used both as the fixed site-wide
   sidebar below and inline wherever a page wants to share something more
   specific than "the current page." */
.share-widget {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

.share-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  min-height: 32px;
  padding: 0;
  border-radius: var(--radius-sm);
  border: 1px solid var(--glass-border);
  background: var(--glass-bg);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  color: var(--heading);
  box-shadow: var(--shadow-soft);
}

@supports not (backdrop-filter: blur(1px)) {
  .share-icon {
    background: var(--surface);
  }
}

.share-icon svg {
  width: 15px;
  height: 15px;
}

.share-icon:hover {
  background: var(--primary-soft);
  color: var(--primary-dark);
  border-color: var(--primary);
  box-shadow: var(--glow);
}

/* Site-wide fixed share sidebar (see footer.php) -- pinned to the left
   edge and vertically centered in the viewport, so it stays visible on
   scroll. Toggled by an IntersectionObserver in footer.php while the
   footer is on screen, so it never overlaps the footer's own content. */
.share-widget-fixed {
  position: fixed;
  left: 1rem;
  top: 50%;
  transform: translateY(-50%);
  z-index: 60;
  opacity: 1;
  transition: opacity 0.2s ease;
}

.share-widget-fixed.is-hidden-for-footer {
  opacity: 0;
  pointer-events: none;
}

.share-widget-fixed .share-widget {
  flex-direction: column;
}

@media (max-width: 640px) {
  .share-widget-fixed {
    left: 0.5rem;
  }
}

/* --- Cookie consent banner --------------------------------------------
   Small, dismissible, sticky at the bottom of the viewport until a
   choice is made. JS in footer.php reads/writes a single localStorage
   flag -- no cookie itself is used to remember the choice (would be a
   little on-the-nose for a banner ABOUT cookies), and nothing is set
   until the person actually clicks accept.

   Ported as-is from the B1 Rolodex's cookie banner, deliberately
   including its own internal note below: that banner went through
   several rounds chasing a real, reproducible Chrome-mobile bug (an
   oversized box with a large blank gap between the text and the
   buttons) under a few different theories (backdrop-filter, an animated
   transform, position:fixed itself), and the same symptom kept
   reappearing under completely different CSS each time, including a
   plain position:static version with no flexbox-adjacent properties
   removed at all. That ruled out every specific property those versions
   had in common except flex-wrap, so this version removes flexbox
   entirely as the next-most-conservative thing left to try: the
   paragraph and the button row are both just plain block-level
   elements, stacked top to bottom, no flex/wrap/basis anywhere. Also no
   show/hide animation (straight display:none/block toggle) -- one less
   moving part. Given how long that took to get right there, there's no
   reason to re-litigate it here instead of just reusing what works. */
.cookie-banner {
  position: fixed;
  left: 1rem;
  right: 1rem;
  bottom: 1rem;
  z-index: 200;
  max-width: 560px;
  margin: 0 auto;
  padding: 0.9rem 1rem;
  background: var(--surface);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  box-shadow: var(--glow-strong);
}

.cookie-banner.hidden {
  display: none;
}

.cookie-banner p {
  margin: 0 0 0.75rem;
  font-size: 0.85rem;
  color: var(--text);
  line-height: 1.4;
}

.cookie-banner a {
  font-weight: 600;
}

.cookie-banner-actions {
  display: block;
}

.cookie-banner-actions button {
  display: inline-block;
  min-height: 38px;
  padding: 0.5rem 0.9rem;
  font-size: 0.85rem;
  margin: 0 0.5rem 0 0;
}

.cookie-decline {
  background: transparent;
  color: var(--muted);
  border: 1px solid var(--border);
}

.cookie-decline:hover {
  background: var(--surface-alt);
  box-shadow: none;
  color: var(--text);
}

@media (max-width: 640px) {
  .cookie-banner {
    left: 0.6rem;
    right: 0.6rem;
    bottom: 0.6rem;
  }

  .cookie-banner-actions button {
    display: block;
    width: 100%;
    margin: 0 0 0.5rem;
  }

  .cookie-banner-actions button:last-child {
    margin-bottom: 0;
  }
}

.bad {
  padding: 0.9rem 1rem;
  margin-bottom: 1rem;
  border-radius: 12px;
  background: #fff1f1;
  border: 1px solid #f0b7b7;
  color: #8a1f1f;
}

.good {
  padding: 0.9rem 1rem;
  margin-bottom: 1rem;
  border-radius: 12px;
  background: #eef9f1;
  border: 1px solid #b8e0c1;
  color: #1e6a34;
}

.map-link {
  margin: 0.75rem 0 1.25rem;
}

.map-button {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0.7rem 1rem;
  border-radius: 999px;
  background: var(--primary);
  color: var(--primary-contrast);
  text-decoration: none;
  font-weight: 700;
}

/* about.php's "Submit A Threat" / "Submit An Anti-Black Business" pair --
   about.php itself always stays on the site's normal red theme (it's not
   one of the pages that gets <body class="theme-gray">), so the
   Anti-Black button needs its own color here rather than relying on that
   theme switch. Hardcoded to the same gray the theme-gray palette above
   uses for --primary, so it reads as "the gray/Anti-Black one" even
   sitting right next to the red Threat Database button. */
.map-button--antiblack {
  background: #52514f;
}

/* Wrapping row for a pair of .map-button links (currently just
   about.php) -- wraps to a stacked column on narrow screens via
   flex-wrap rather than a separate mobile-only layout. */
.form-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin: 0.5rem 0 1rem;
}

/* --- About page: "How We're Different" comparison chart ---------------
   Two side-by-side cards (flex, not a real <table>) so it reflows to a
   single stacked column on tablet/mobile automatically via flex-wrap,
   rather than needing a separate mobile-only layout or any JS to detect
   screen size. "Us" column uses the primary red + checkmarks, "Other
   sites" column uses a neutral gray + x-marks, so the contrast reads at
   a glance even before reading the text. Ported from the B1 Rolodex's
   about page, same pattern. */
.compare-chart {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
  margin: 1.25rem 0 1.75rem;
}

.compare-col {
  flex: 1 1 300px;
  border-radius: var(--radius);
  padding: 1.5rem 1.75rem;
  box-shadow: var(--shadow-soft);
}

.compare-col h3 {
  margin-top: 0;
  font-size: 1.15rem;
}

.compare-col ul {
  list-style: none;
  margin: 0.75rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
}

.compare-col li {
  padding-left: 1.75rem;
  position: relative;
  line-height: 1.45;
}

.compare-col--us {
  background: var(--primary-soft);
  border: 2px solid var(--primary);
}

.compare-col--us h3 {
  color: var(--primary-dark);
}

.compare-col--us li::before {
  content: "\2713";
  position: absolute;
  left: 0;
  top: 0;
  font-weight: 700;
  color: var(--primary-dark);
}

.compare-col--other {
  background: var(--surface-alt);
  border: 2px solid var(--border-strong);
}

.compare-col--other h3 {
  color: var(--muted);
}

.compare-col--other li {
  color: var(--muted);
}

.compare-col--other li::before {
  content: "\2715";
  position: absolute;
  left: 0;
  top: 0;
  font-weight: 700;
  color: var(--muted);
}

/* Below ~640px (site's standard mobile breakpoint) the two 300px-basis
   columns no longer fit side by side and flex-wrap already stacks them
   -- this just tightens padding so they don't feel oversized on a
   narrow phone screen. */
@media (max-width: 640px) {
  .compare-col {
    flex-basis: 100%;
    padding: 1.25rem 1.35rem;
  }
}

@media (max-width: 640px) {
  .site-header,
  .hero,
  .search,
  .card,
  .business-card,
  .site-footer,
  .form-card {
    padding: 1rem;
    border-radius: 14px;
  }

  .logo-link {
    width: 40px;
    height: 40px;
  }

  .site-title {
    font-size: 1.2rem;
  }

  /* Previously width:100% here, which (combined with the unchanged
     34px height) stretched each icon into a full-width horizontal
     bar/pill instead of a square icon. Fixed-size square icons that
     wrap onto new rows, centered as a group, like a normal icon row. */
  .social-links {
    justify-content: center;
  }

  .social-links a {
    width: 44px;
    height: 44px;
  }

  /* Earlier mobile rounds added extra left padding here to keep card/hero
     text clear of the fixed "share this page" icon sidebar
     (.share-widget-fixed), but that's what was pushing every page's
     content (header, logo included) visibly off-center to the right on
     mobile -- confirmed by comparing directly against the B1 Rolodex
     site, which uses this same fixed-sidebar share widget but does NOT
     add any compensating left padding at all, and looks correctly
     aligned. Matching that: .site-header/.site-main/.wrap go back to
     using the same plain 1.1rem side padding as desktop, no override.
     The icons are only 32px wide and vertically centered in the
     viewport, so at most they sit slightly in front of text for a
     moment while scrolled to the middle of the screen -- not worth
     shifting the entire page's layout to avoid. */

  .meta,
  .topbar {
    flex-direction: column;
    align-items: flex-start;
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    transition: none !important;
    animation: none !important;
  }
}

@media (forced-colors: active) {
  .site-header,
  .card,
  .business-card,
  .site-footer,
  .search,
  .hero,
  .form-card,
  .empty {
    border: 1px solid CanvasText;
  }
}
.map-embed {
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
}

.map-embed iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}
.google-form-embed {
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}

.google-form-embed iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* Utility classes — these replace scattered inline style="" attributes so
   the site can run a stricter Content-Security-Policy (style-src without
   'unsafe-inline'). */
.card-narrow-lg {
  max-width: 900px;
  margin: 0 auto;
}

.card-narrow-md {
  max-width: 560px;
  margin: 0 auto;
}

.card-narrow-sm {
  max-width: 420px;
  margin: 0 auto;
}

/* The manual-entry secret key shown on admin_2fa_setup.php -- monospaced
   and spaced out in groups of 4 (see chunk_split() in that file) so it's
   easy to type into an authenticator app without misreading a character,
   and wraps instead of overflowing on narrow screens. */
.totp-key-display {
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
  font-size: 1.1rem;
  letter-spacing: 0.05em;
  word-break: break-all;
  background: rgba(0, 0, 0, 0.04);
  border-radius: 6px;
  padding: 0.75rem 1rem;
  margin: 0.75rem 0;
}

.mt-1 {
  margin-top: 1rem;
}

.mb-tight {
  margin: 0 0 10px;
}

.inline-link {
  color: inherit;
  text-decoration: underline;
}

.hidden {
  display: none;
}

/* Honeypot field on the public submission forms (submit_threat.php,
   submit_antiblack.php, submit_adjustment.php) -- positioned off-screen
   rather than display:none/visibility:hidden, since some simple bots
   skip filling fields that are hidden that obviously. A real visitor
   tabbing through the form never lands on it (tabindex="-1"). */
.hp-field {
  position: absolute;
  left: -9999px;
  top: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.mt-05 {
  margin-top: 0.5rem;
}

.mb-05 {
  margin-bottom: 0.5rem;
}

.mt-06 {
  margin-top: 0.6rem;
}

.mt-025 {
  margin-top: 0.25rem;
}

.mt-075 {
  margin-top: 0.75rem;
}

.mb-1 {
  margin-bottom: 1rem;
}

.location-row-pad {
  margin-bottom: 0.75rem;
  padding: 0.85rem;
}

.inline-flex-gap {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

/* --- Blog: cards, post layout, and the add/edit block editor ---------- */

/* The blog listing card (blog.php) is one single link wrapping the whole
   card's content -- image, title, byline, excerpt, "Read more" -- rather
   than three separate links the way it used to be, so the entire card is
   clickable instead of just the title and the image. .card already gives
   the <article> its padding; the link itself adds no visual styling of
   its own (reset below) and just makes the whole block a click target. */
.blog-card {
  padding: 0;
}

.blog-card-link {
  display: block;
  padding: 1.15rem;
  color: inherit;
  text-decoration: none;
}

/* Same "whole card is one link" pattern as .blog-card-link above, used
   for the threat/anti-black result cards on index.php, search_threats.php,
   and search_antiblack.php -- clicking anywhere on the card (the danger
   level badge, the location line, the reason text) opens the entry, not
   just the title or the "View details" line. */
.search-card {
  padding: 0;
}

.search-card-link {
  display: block;
  padding: 1.15rem;
  color: inherit;
  text-decoration: none;
}

.search-card .name {
  color: var(--heading);
}

/* No title-color/underline change on hover here on purpose (ported from
   the B1 Rolodex's business result cards) -- the card itself floats up
   with a glow behind it (.grid .card:hover, above) and that's the only
   hover feedback. The title lighting up red on top of that was doubling
   up on the same signal. */

/* .name's own color normally comes from the <a> wrapped around a card's
   title (.name a, below) -- the blog card's title has no such inner
   link any more (the whole card is the link instead), so it needs that
   same heading color set directly. */
.blog-card .name {
  color: var(--heading);
}

.blog-card-thumb {
  display: block;
  /* width:100% alone resolves against .blog-card-link's content box,
     i.e. the card width MINUS its 1.15rem padding on each side -- so a
     plain 100% image is already too narrow before the negative margins
     below even get a chance to pull it outward. Adding the padding back
     via calc() sizes the image to the card's full padding box instead,
     so the negative margins below reposition a correctly-sized box
     rather than stretching an undersized one (which just shifted it
     left without ever reaching the right edge).
     On top of that, the site-wide "img { max-width: 100%; }" reset
     (near the top of this file, keeps images from overflowing their
     container anywhere else on the site) was silently capping this
     image back down to the same too-narrow width even after the fix
     above -- max-width wins over width when the two conflict. Since
     this is the one place on the site an image is deliberately sized
     WIDER than its container on purpose, it needs max-width lifted to
     match. */
  width: calc(100% + 2.3rem);
  max-width: calc(100% + 2.3rem);
  aspect-ratio: 16 / 9;
  object-fit: cover;
  /* Bleeds the image to the card's edges past the link's own padding
     above (same negative-margin trick the old .blog-card-thumb-link
     wrapper used) so a featured image still spans edge-to-edge at the
     top of the card instead of sitting inset inside it. */
  margin: -1.15rem -1.15rem 0.9rem;
  border-radius: var(--radius) var(--radius) 0 0;
}

.blog-post-title {
  font-size: 1.6rem;
  line-height: 1.2;
}

@media (min-width: 768px) {
  .blog-post-title {
    font-size: 2.2rem;
  }
}

.blog-post-featured-image {
  /* No max-height/object-fit:cover here on purpose -- this is the actual
     post page, not the cropped grid thumbnail (.blog-card-thumb below
     still crops to a fixed 16:9, which is fine for a uniform grid of
     cards). Scaling to the full container width with height left to
     follow naturally means whatever image a staff member uploads shows
     in full here, with nothing sliced off the top/bottom, regardless of
     its dimensions. */
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius);
  margin: 1rem 0;
}

.blog-post-content {
  line-height: 1.7;
}

.blog-post-text-block {
  margin-bottom: 1.25rem;
}

.blog-post-text-block h1,
.blog-post-text-block h2,
.blog-post-text-block h3,
.blog-post-text-block h4 {
  color: var(--heading);
  line-height: 1.25;
  margin: 1.2rem 0 0.5rem;
}

.blog-post-text-block ul,
.blog-post-text-block ol {
  padding-left: 1.4rem;
}

.blog-post-text-block li {
  margin-bottom: 0.35rem;
}

.blog-post-image-link {
  display: block;
}

.blog-post-block-image {
  display: block;
  height: auto;
  border-radius: var(--radius);
  margin: 0.5rem auto 1.5rem;
  object-fit: contain;
  max-width: 100%;
  transition: opacity 0.15s ease;
}

.blog-post-block-image--small {
  width: 100%;
  max-width: 320px;
}

.blog-post-block-image--medium {
  width: 100%;
  max-width: 560px;
}

.blog-post-block-image--large {
  width: 100%;
  max-width: 860px;
}

.blog-post-block-image--full {
  max-width: 100%;
  width: 100%;
}

.blog-post-image-link:hover .blog-post-block-image {
  opacity: 0.9;
}

.blog-post-video-wrap {
  position: relative;
  width: 100%;
  max-width: 860px;
  margin: 0.5rem auto 1.5rem;
  padding-top: 56.25%;
  border-radius: var(--radius);
  overflow: hidden;
  background: #000;
}

.blog-post-video-wrap iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* Block editor (add/edit blog) -- staff-only, add_blog.php/edit_blog.php
   are gated by require_role(admin/editor) before any of this renders. */
.block-editor {
  margin-bottom: 1rem;
}

.block-editor-toolbar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
}

.block-editor-block {
  position: relative;
  padding: 1rem;
  margin-bottom: 0.85rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-alt);
}

.block-editor-block--text textarea {
  margin-bottom: 0;
}

.block-editor-block--image label,
.block-editor-block--video label {
  margin-top: 0.7rem;
}

.block-editor-block--image label:first-child,
.block-editor-block--video label:first-child {
  margin-top: 0;
}

.block-editor-preview {
  display: block;
  max-width: 240px;
  max-height: 160px;
  object-fit: cover;
  border-radius: var(--radius-sm);
  margin: 0.5rem 0;
  border: 1px solid var(--border);
}

.block-editor-block-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.75rem;
}

.block-editor-block-controls .block-add-btn,
.block-editor-block-controls .block-remove-btn {
  margin-top: 0;
}

.block-move-up-btn:disabled,
.block-move-down-btn:disabled {
  opacity: 0.4;
  cursor: default;
  box-shadow: none;
}

.block-remove-btn {
  min-height: 36px;
  padding: 0.4rem 0.8rem;
  font-size: 0.85rem;
  background: transparent;
  color: var(--muted);
  border: 1px solid var(--border);
}

.block-remove-btn:hover {
  background: #fff1f1;
  color: #8a1f1f;
  border-color: #f0b7b7;
  box-shadow: none;
}

.block-editor-add-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-bottom: 1rem;
}

.block-add-btn {
  background: var(--surface);
  color: var(--primary-dark);
  border: 1px solid var(--primary);
  font-size: 0.9rem;
  min-height: 40px;
  padding: 0.5rem 0.9rem;
  border-radius: var(--radius-sm);
}

.block-add-btn:hover {
  background: var(--primary-soft);
  box-shadow: none;
}

/* --- SEO / readability panel (add_blog.php / edit_blog.php) -----------
   Traffic-light check list: reuses the site's red/green language via
   the seo-check-{red,yellow,green} status classes, plus a yellow "warn"
   tier .bad/.good don't otherwise cover. Each check is a compact card
   so a dozen of them don't read as a wall of text. */
.seo-panel {
  margin-top: 1.25rem;
}

.seo-check-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-top: 0.75rem;
}

.seo-check {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 0.6rem 0.8rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface);
}

.seo-check-dot {
  flex: 0 0 auto;
  width: 12px;
  height: 12px;
  margin-top: 0.25rem;
  border-radius: 50%;
}

.seo-check-red {
  background: #fff1f1;
  border-color: #f0b7b7;
}

.seo-check-red .seo-check-dot {
  background: #c0392b;
}

.seo-check-yellow {
  background: #fffaf0;
  border-color: #f0dfa1;
}

.seo-check-yellow .seo-check-dot {
  background: #d4a017;
}

.seo-check-green {
  background: #eef9f1;
  border-color: #b8e0c1;
}

.seo-check-green .seo-check-dot {
  background: #1e6a34;
}

.seo-check-body {
  flex: 1 1 auto;
}

.seo-check-label {
  font-weight: 650;
  font-size: 0.92rem;
}

.seo-check-detail {
  font-size: 0.86rem;
  color: var(--muted);
}

/* Overall score headline row, above the individual keyword/readability
   checks -- deliberately larger/bolder than a .seo-check row so it
   reads as a summary, not just one more item in the list. */
.seo-overall-score {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  padding: 0.9rem 1rem;
  margin-bottom: 0.9rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
}

.seo-overall-score .seo-check-dot {
  width: 18px;
  height: 18px;
  margin-top: 0.15rem;
}

.seo-overall-score-label {
  font-weight: 700;
  font-size: 1.05rem;
}

.seo-overall-score-detail {
  font-size: 0.88rem;
  color: var(--muted);
}

/* Secondary/ghost submit button -- used where a form has a primary
   action (Save) plus a lower-stakes secondary action (Preview SEO
   Score) that shouldn't visually compete with it. */
.btn-secondary {
  background: var(--surface);
  color: var(--primary-dark);
  border: 1px solid var(--border-strong);
  margin-top: 0.6rem;
  margin-left: 0.5rem;
}

.btn-secondary:hover {
  background: var(--primary-soft);
  box-shadow: none;
}

/* --- Contributors page --------------------------------------------------
   Names in a column on the left, photo alongside on the right, on
   anything wide enough for that to look intentional rather than
   cramped. Stacks (photo below the list) on mobile/tablet instead. */
.contributors-layout {
  display: flex;
  align-items: flex-start;
  gap: 2rem;
  flex-wrap: wrap;
}

.contributors-list {
  flex: 2 1 320px;
  margin: 0;
  column-count: 2;
  column-gap: 1.5rem;
}

.contributors-list li {
  break-inside: avoid;
}

.contributors-image {
  flex: 1 1 280px;
  max-width: 360px;
  width: 100%;
  height: auto;
  border-radius: var(--radius);
  display: block;
}

@media (max-width: 900px) {
  .contributors-layout {
    flex-direction: column;
    align-items: stretch;
  }

  .contributors-image {
    max-width: 100%;
    order: 2;
  }

  .contributors-list {
    order: 1;
  }
}

@media (max-width: 480px) {
  .contributors-list {
    column-count: 1;
  }
}

/* --- FAQ page (faq.php) -------------------------------------------------
   Search box + category-grouped accordion. Search re-ranks matching
   items into a flat list (see faq.php's inline script); this is just the
   visual side of both states. */
#faqSearch {
  width: 100%;
  min-height: 48px;
  margin-bottom: 0;
  padding: 0.8rem 1rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  font-size: 1rem;
}

.faq-item {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  margin-top: 0.6rem;
  padding: 0.9rem 1.1rem;
  /* Keeps a deep link (e.g. "/faqs#faq-...") from landing underneath the
     sticky .site-header (position: sticky; top: 0.75rem) -- without this,
     both the browser's own native jump-to-fragment AND the JS scrollIntoView
     fallback below measure against the raw viewport top, which the sticky
     header visually covers, so the target consistently lands a bit higher
     than the actual readable text. Comfortably clears the header's height
     (logo + title + padding) at every breakpoint rather than hand-tuning a
     different value per media query. */
  scroll-margin-top: 5.5rem;
}

.faq-item summary {
  cursor: pointer;
  font-weight: 700;
  color: var(--heading);
  list-style: none;
}

.faq-item summary::-webkit-details-marker {
  display: none;
}

.faq-item summary::before {
  content: '+';
  display: inline-block;
  width: 1.2rem;
  color: var(--primary);
  font-weight: 700;
}

.faq-item[open] summary::before {
  content: '\2212';
}

.faq-answer {
  margin-top: 0.6rem;
  padding-left: 1.2rem;
  color: var(--text);
  line-height: 1.55;
}

.faq-answer p {
  margin: 0 0 0.6rem;
}

.faq-answer p:last-child {
  margin-bottom: 0;
}

/* ---------------------------------------------------------------------
   Resource / nonprofit directory cards (Useful Gov and NGO Resources,
   Political & Social Change) and the floating feature images used on
   those pages plus The B1 Rolodex page.
   ------------------------------------------------------------------- */

/* Small logo shown above the search bar on pages that have one (e.g.
   search_antiblack.php) -- distinct from .page-feature-image below,
   which is sized/framed for a feature image floated inside a card,
   not a small mark centered above a form. */
.search-page-logo {
  display: block;
  width: 72px;
  height: auto;
  margin: 0 auto 0.9rem;
}

/* Logo switch -- the animated toggle above the search bar on
   index.php / search_threats.php / search_antiblack.php that lets
   someone slide from the Threat Database logo to the Anti-Black List
   logo (or back) and jump to that page. It's a link dressed up as a
   toggle switch, so the interaction is gated rather than instant:
   logo-switch.js arms it after a short hover-dwell on mice/trackpads
   (see .is-armed below) and requires a confirming second tap on
   touchscreens (see .is-revealed) so a passing mouse-over or a
   scroll-tap doesn't accidentally navigate someone away.
   is-hovering / is-armed / is-revealed are only ever toggled by
   logo-switch.js in footer.php. */
.logo-switch {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* ~20% bigger than this used to be (200px) -- the logo PNGs themselves
     have some built-in transparent padding around the actual circular
     mark, so the visible logo was reading smaller than the box size
     alone suggested. Scaling the whole stage up is what actually makes
     the mark itself look bigger, rather than just enlarging that
     padding along with it. */
  width: 240px;
  margin: 0 auto 1.6rem;
  text-decoration: none;
}

/* The square stage the two logos sit in. The chosen logo sits big and
   dead-center; the other one sits behind it, small, faint, and off
   to the right -- until hover/reveal swaps which one is "chosen". No
   background fill on the images themselves so each logo's own
   transparent PNG shows the page behind it rather than a white disc. */
.logo-switch-stage {
  position: relative;
  width: 204px;
  height: 204px;
}

.logo-switch-stage img {
  position: absolute;
  top: 50%;
  left: 50%;
  border-radius: 50%;
  object-fit: contain;
  transition: width 0.3s ease, height 0.3s ease, transform 0.3s ease, opacity 0.3s ease, filter 0.3s ease;
}

.logo-switch-current {
  width: 173px;
  height: 173px;
  transform: translate(-50%, -50%);
  z-index: 2;
  opacity: 1;
  filter: none;
}

.logo-switch-other {
  width: 67px;
  height: 67px;
  transform: translate(calc(-50% + 60px), calc(-50% + 12px));
  z-index: 1;
  opacity: 0.22;
  filter: grayscale(70%);
}

/* Hover-dwell (desktop/mouse) or tap-to-reveal (touch) -- the swap
   plays right away in both cases; only the click/second-tap itself
   is gated (by logo-switch.js), not this preview animation. */
.logo-switch.is-hovering .logo-switch-current,
.logo-switch.is-revealed .logo-switch-current {
  width: 67px;
  height: 67px;
  transform: translate(calc(-50% + 60px), calc(-50% + 12px));
  z-index: 1;
  opacity: 0.22;
  filter: grayscale(70%);
}

.logo-switch.is-hovering .logo-switch-other,
.logo-switch.is-revealed .logo-switch-other {
  width: 173px;
  height: 173px;
  transform: translate(-50%, -50%);
  z-index: 2;
  opacity: 1;
  filter: none;
}

/* The two logo PNGs have very different amounts of built-in transparent
   padding around their actual artwork -- antiblack-logo.png's mark fills
   almost its entire square canvas edge to edge, while
   fba-threat-database-logo.png's mark only fills about 90% of the width
   and 60% of the height of its canvas. Sizing both images to the same
   width/height (above) therefore does NOT make them look the same size --
   the Anti-Black List logo reads noticeably bigger, since there's far
   less empty canvas around its mark to begin with. Rather than trying to
   re-export the source PNGs with matching padding, this targets the
   antiblack-logo.png <img> specifically (by its src, so it's sized
   correctly in EVERY role it appears in: the big "current" logo on
   search_antiblack.php, the small "other" preview on index.php/
   search_threats.php, and both of those again mid-hover-swap) and scales
   it down about 20% from the generic sizes above -- matched to the actual
   measured difference in how much of each canvas its artwork fills, not
   just eyeballed. */
.logo-switch-current[src*="antiblack-logo.png"],
.logo-switch.is-hovering .logo-switch-other[src*="antiblack-logo.png"],
.logo-switch.is-revealed .logo-switch-other[src*="antiblack-logo.png"] {
  width: 138px;
  height: 138px;
}

.logo-switch-other[src*="antiblack-logo.png"],
.logo-switch.is-hovering .logo-switch-current[src*="antiblack-logo.png"],
.logo-switch.is-revealed .logo-switch-current[src*="antiblack-logo.png"] {
  width: 54px;
  height: 54px;
}

/* Armed = the hover-dwell timer has elapsed and a click will now
   navigate. No separate visual ring here anymore -- it used the
   page's own theme color (red on Threat Database pages, gray on
   Anti-Black List pages) regardless of which logo it was circling,
   so it clashed once the hover-swap brought up the other logo. The
   size/opacity swap plus the label are cue enough that something is
   active; .is-armed itself still gates the actual click in
   footer.php's logo-switch.js, this just removes its own styling. */

.logo-switch-label {
  margin-top: 0.5rem;
  font-size: 0.72rem;
  color: var(--muted);
  text-align: center;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.logo-switch.is-hovering .logo-switch-label,
.logo-switch.is-revealed .logo-switch-label {
  opacity: 1;
}

/* Keyboard users don't get a hover-dwell -- focusing the switch arms
   it immediately (see logo-switch.js) so Tab + Enter isn't penalized
   by a timer meant for an accidental mouse pass-over. */
.logo-switch:focus-visible .logo-switch-stage {
  outline: 2px solid var(--focus);
  outline-offset: 4px;
  border-radius: 50%;
}

.page-feature-image {
  display: block;
  float: right;
  width: 100%;
  max-width: 300px;
  height: auto;
  margin: 0 0 1rem 1.5rem;
  border-radius: var(--radius);
}

.page-feature-image--logo {
  max-width: 180px;
  background: none;
}

/* Exactly half of --logo-lg at every tier below -- for a logo placed
   inline within body copy (like sources.php's Anti-Black List section
   heading) rather than as a page's main hero image, where --logo-lg's
   size is too dominant. */
.page-feature-image--logo-sm {
  max-width: 140px;
  background: none;
}

.page-feature-image--bottom {
  float: none;
  margin: 1.5rem auto 0;
}

.page-feature-image--centered-top {
  float: none;
  margin: 0 auto 1.25rem;
}

.page-feature-image--lg {
  max-width: 440px;
}

.page-feature-image--logo-lg {
  max-width: 280px;
  background: none;
}

.page-feature-image--wide {
  max-width: 560px;
}

.page-feature-image-pair {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 1.5rem;
  margin: 0 auto 1.25rem;
}

.page-feature-image-pair-img {
  display: block;
  width: 100%;
  max-width: 260px;
  height: auto;
  border-radius: var(--radius);
}

.page-feature-image-pair-img--logo {
  max-width: 200px;
  background: none;
}

.card-has-float-image::after {
  content: "";
  display: table;
  clear: both;
}

/* Tablet tier for the wide/centered illustrations (export_data.php's
   download graphic, etc.) -- same breakpoint range the rest of the site
   uses for tablet-specific sizing (see the layout rules above). Sits
   between the capped-at-100%-width phone size below and the 560px
   laptop/desktop default above. */
@media (min-width: 641px) and (max-width: 900px) {
  .page-feature-image--wide {
    max-width: 420px;
  }
}

@media (max-width: 640px) {
  .page-feature-image {
    float: none;
    max-width: 220px;
    margin: 0 auto 1rem;
  }

  .page-feature-image--logo {
    max-width: 150px;
  }

  .page-feature-image--lg {
    max-width: 260px;
  }

  .page-feature-image--logo-lg {
    max-width: 180px;
  }

  .page-feature-image--logo-sm {
    max-width: 90px;
  }

  .page-feature-image--wide {
    max-width: 100%;
  }

  .page-feature-image-pair {
    flex-direction: column;
    gap: 0.75rem;
  }

  .page-feature-image-pair-img {
    max-width: 220px;
  }

  .page-feature-image-pair-img--logo {
    max-width: 160px;
  }
}

.resource-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 1rem;
  margin-top: 1rem;
}

.resource-card {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-soft);
  padding: 1.15rem;
  transition: box-shadow 0.2s ease, border-color 0.2s ease, transform 0.2s ease;
}

.resource-card:hover {
  border-color: var(--primary);
  box-shadow: var(--shadow);
  transform: translateY(-2px);
}

.resource-card h2 {
  margin: 0 0 0.5rem;
  font-size: 1.1rem;
  letter-spacing: -0.01em;
  color: var(--heading);
}

.resource-helps {
  color: var(--muted);
  font-size: 0.92rem;
  margin: 0 0 0.75rem;
}

.resource-contact {
  margin: 0;
  font-size: 0.92rem;
  overflow-wrap: anywhere;
}

.resource-contact a {
  overflow-wrap: anywhere;
}

/* Small helper/example text under a form label -- same look as
   threat.css's .map-help (used on add_threat.php/add_antiblack.php),
   duplicated here in the global stylesheet so the public submission
   forms (submit_threat.php, submit_antiblack.php, submit_adjustment.php)
   can use it too without loading all of threat.css's map/widget CSS
   just for this one rule. */
.map-help {
  font-size: 0.85rem;
  color: var(--muted);
  margin-top: 0.4rem;
}

/* Wraps the one-time submitter vetting questions (alias, FBA status,
   email) on the three public submission forms -- see
   render_submitter_vetting_fields() in config.php. Visually sets it
   apart from the rest of the form below it. */
.vetting-fields {
  padding: 0.9rem 1rem;
  margin-bottom: 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-alt);
}
