/* The Contractor Network — hand-written design system (zero external deps) */

:root {
  --bg: #f5f7fa;
  --bg-alt: #eaeff5;
  --card: #ffffff;
  --border: #d7dee6;
  --text: #1c2733;
  --text-dim: #5b6673;
  --accent: #2563eb;
  --accent-dim: #1d4ed8;
  --on-accent: #ffffff;
  --green: #15803d;
  --red: #dc2626;
  --warn: #b45309;
  --gold: #b45309;
  --gold-bg: #fffbeb;
  --steel: #0f1720;
  --steel-alt: #1a2531;
  --steel-text: #e2e8f0;
  --steel-text-dim: #94a3b8;
  --steel-border: rgba(255,255,255,0.12);
  --radius: 10px;
  --max: 1180px;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  line-height: 1.5;
}

a { color: inherit; text-decoration: none; }
img { max-width: 100%; display: block; }

.wrap { max-width: var(--max); margin: 0 auto; padding: 0 20px; }

h1, h2, h3, h4 {
  font-weight: 800;
  letter-spacing: 0.02em;
  margin: 0 0 12px;
  text-transform: uppercase;
}
h1 { font-size: clamp(2.2rem, 6vw, 4rem); line-height: 1.05; }
h2 { font-size: clamp(1.6rem, 3.2vw, 2.4rem); }
h3 { font-size: 1.2rem; }
p { color: var(--text-dim); margin: 0 0 12px; }

.eyebrow {
  display: inline-block;
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  font-weight: 700;
  margin-bottom: 10px;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 13px 22px;
  border-radius: 8px;
  font-weight: 700;
  font-size: 0.85rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform 0.12s ease, opacity 0.12s ease;
}
.btn:hover { opacity: 0.9; }
.btn:active { transform: scale(0.98); }
.btn-accent { background: var(--accent); color: var(--on-accent); }
.btn-outline { background: transparent; color: var(--text); border-color: var(--border); }
.btn-outline:hover { border-color: var(--accent); color: var(--accent); }
.btn-sm { padding: 9px 16px; font-size: 0.75rem; }
.btn-block { width: 100%; }

/* ---------- Title Sponsor: one consistent identity everywhere — platinum (charcoal/graphite
   with silver-white text), no red, no ribbon/tag chip. Reads as the tier above gold Sponsor
   the same way it does on credit cards / airline status, distinct from blue Featured too. */
.title-sponsor-strip {
  display: block; text-decoration: none;
  background: linear-gradient(90deg, #27272a, #3f3f46 45%, #27272a);
  border-bottom: 1px solid rgba(212,212,216,0.35);
}
.title-sponsor-strip-inner {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  padding: 8px 20px; flex-wrap: wrap; text-align: center;
}
.title-sponsor-label {
  font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.1em; font-weight: 800;
  color: #d4d4d8;
}
.title-sponsor-strip strong { color: #fff; font-size: 0.9rem; font-weight: 800; }
.title-sponsor-logo { height: 20px; width: auto; max-width: 90px; object-fit: contain; border-radius: 3px; }
.title-sponsor-cta { font-size: 0.75rem; color: #d4d4d8; font-weight: 700; }
.title-sponsor-strip:hover .title-sponsor-cta { text-decoration: underline; }

/* Homepage/sponsors-page Title Sponsor showcase: a compact banner, not a full hero-sized
   section — same platinum identity, small and to the point rather than an oversized repeat of
   the strip above it. */
.title-sponsor-showcase { padding: 0; background: linear-gradient(135deg, #27272a, #18181b 70%); border-bottom: 1px solid rgba(212,212,216,0.3); }
.title-sponsor-showcase-inner {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 12px 20px; text-decoration: none;
}
.title-sponsor-showcase-name { color: #fff; font-size: 1.05rem; font-weight: 800; margin: 0; }
.title-sponsor-showcase-sub { color: rgba(255,255,255,0.65); font-size: 0.8rem; margin: 0; }
.title-sponsor-showcase-logo { height: 34px; width: auto; max-width: 110px; object-fit: contain; border-radius: 5px; background: #fff; padding: 3px 6px; }
.title-sponsor-showcase-inner .btn { margin-left: auto; padding: 7px 14px; font-size: 0.7rem; }
@media (max-width: 700px) { .title-sponsor-showcase-inner { justify-content: center; text-align: center; flex-direction: column; } .title-sponsor-showcase-inner .btn { margin-left: 0; } }

/* ---------- Sponsor ad banner (site-wide, auto-rotating) ----------
   Sits directly under the header on EVERY page (see lib/layout.js page()) — user's call after
   seeing a competitor's site with much more sponsor ad space. Gold, matching the existing
   Sponsor badge identity elsewhere (distinct from Title Partner's platinum strip above the
   header) — this is explicitly partnership/ad content, so gold is the right call here even
   though it's deliberately kept OFF trade/directory contexts elsewhere on the site. */
.sponsor-ad-banner { background: var(--gold-bg); border-bottom: 1px solid rgba(180,83,9,0.25); }
.sponsor-ad-inner { display: flex; align-items: center; gap: 14px; padding: 9px 20px; flex-wrap: wrap; position: relative; }
.sponsor-ad-label {
  flex-shrink: 0; font-size: 0.64rem; text-transform: uppercase; letter-spacing: 0.09em; font-weight: 800;
  color: var(--gold); border: 1px solid var(--gold); border-radius: 4px; padding: 2px 6px;
}
.sponsor-ad-slides { position: relative; flex: 1; min-height: 26px; min-width: 0; }
.sponsor-ad-slide {
  position: absolute; inset: 0; display: none; align-items: center; gap: 10px; text-decoration: none;
  opacity: 0; transition: opacity 0.4s ease;
}
.sponsor-ad-slide.active { display: flex; opacity: 1; position: relative; }
.sponsor-ad-logo { height: 24px; width: auto; max-width: 80px; object-fit: contain; border-radius: 3px; background: #fff; padding: 2px 4px; flex-shrink: 0; }
.sponsor-ad-name { color: var(--text); font-weight: 800; font-size: 0.86rem; flex-shrink: 0; }
.sponsor-ad-tagline { color: var(--text-dim); font-size: 0.82rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sponsor-ad-cta { color: var(--gold); font-weight: 700; font-size: 0.78rem; flex-shrink: 0; margin-left: auto; white-space: nowrap; }
.sponsor-ad-slide:hover .sponsor-ad-cta { text-decoration: underline; }
.sponsor-ad-dots { display: flex; gap: 5px; flex-shrink: 0; }
.sponsor-ad-dot {
  width: 6px; height: 6px; border-radius: 50%; border: none; padding: 0; cursor: pointer;
  background: rgba(180,83,9,0.3);
}
.sponsor-ad-dot.active { background: var(--gold); }
.sponsor-ad-empty-text { color: var(--text-dim); font-size: 0.82rem; flex: 1; }
@media (max-width: 640px) {
  .sponsor-ad-tagline { display: none; }
  .sponsor-ad-inner { padding: 8px 16px; }
  /* Fixed 2026-09-06 (full mobile pass) — the CTA's white-space:nowrap + flex-shrink:0 refused
     to wrap or shrink, so on a narrow phone it got pushed past the viewport edge, causing
     horizontal scroll on the whole page. The slide itself is already a full clickable link, so
     dropping the explicit label on mobile loses nothing functional. The name also gets a safe
     truncate so an unusually long business name can't reopen the same problem on its own. */
  .sponsor-ad-cta { display: none; }
  .sponsor-ad-name { flex-shrink: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}

/* ---------- Header ---------- */
header.site {
  position: sticky; top: 0; z-index: 50;
  background: rgba(245,247,250,0.92);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--border);
}
.nav {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 0;
  /* .nav shares the .wrap class (same 1180px content cap as every page section) but measured at
     1500px viewport, logo + 7 nav links + lang/auth actions need ~1181.5px — 1.5px over that cap,
     on EVERY desktop width, not just a narrow range (a plain viewport media query can't fix an
     issue that's actually about a fixed container width). This override gives the header row
     alone a bit more room without touching --max for the rest of the site's content width. */
  max-width: 1260px;
}
.logo {
  font-weight: 900; letter-spacing: 0.02em; font-size: 1.15rem; text-transform: uppercase;
  display: inline-flex; align-items: center; gap: 8px;
  /* Extra breathing room beyond .nav's own 16px gap — added 2026-08-28, bumped from an initial
     16px after the user still saw "NETWORK" touching "Directory" on their own screen at a width
     where getBoundingClientRect() measured a clean 32px gap (16+16) with zero overlap. That
     mismatch between measured layout and what actually painted point at a font-rendering
     difference between environments (this box has no custom @font-face, so .logo falls back to
     whatever bold sans the OS provides — its exact glyph widths for "NETWORK" vary by system).
     A fixed margin-right can't be tuned against a browser this session can't reproduce, so this
     goes generous rather than exact — comfortably past any plausible fallback-font variance. */
  margin-right: 48px;
}
.logo-mark { width: 34px; height: 34px; object-fit: contain; display: block; }
.logo span { color: var(--accent); }
.nav-links { display: flex; gap: 22px; align-items: center; font-size: 0.85rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.03em; }
.nav-links a:hover { color: var(--accent); }
.nav-actions { display: flex; gap: 10px; align-items: center; flex-shrink: 0; }
.nav-actions-desktop { display: flex; gap: 10px; align-items: center; }
.lang-toggle { font-size: 0.75rem; color: var(--text-dim); border: 1px solid var(--border); border-radius: 6px; padding: 6px 10px; cursor: pointer; background: transparent; white-space: nowrap; }
.lang-toggle:hover { color: var(--accent); border-color: var(--accent); }
.nav-mobile-toggle { display: none; position: relative; }
.nav-mobile-toggle summary {
  list-style: none; cursor: pointer; font-size: 1.6rem; line-height: 1; font-weight: 700;
  padding: 8px; border: 1px solid var(--border); border-radius: 8px;
  color: var(--text); background: var(--bg-alt);
}
.nav-mobile-toggle summary:hover, .nav-mobile-toggle[open] summary { border-color: var(--accent); color: var(--accent); }
.nav-mobile-toggle summary::-webkit-details-marker { display: none; }
.nav-mobile-links {
  position: absolute; right: 0; top: calc(100% + 8px);
  background: var(--card); border: 1px solid var(--border); border-radius: 10px;
  padding: 12px; display: flex; flex-direction: column; gap: 4px; min-width: 220px; z-index: 60;
  max-width: calc(100vw - 40px);
}
.nav-mobile-links a { padding: 8px 10px; border-radius: 6px; font-size: 0.85rem; font-weight: 600; text-transform: uppercase; }
.nav-mobile-links a:hover { background: var(--bg-alt); color: var(--accent); }

.nav { gap: 16px; }

/* Desktop nav should never collapse into a hamburger menu — every link stays visible and
   clickable without an extra tap. .nav's own max-width is now 1260px (see above) instead of the
   site's usual 1180px content cap, since logo + 7 nav links + lang/auth actions need ~1181.5px —
   too tight against the shared 1180px cap at ANY desktop width, not just a narrow viewport range
   (real bug: adding "Get Competing Quotes" pushed content past the container width, and neither
   the container nor this breakpoint got widened to compensate — caught in testing). .nav reaches
   its own ~1185px-plus actual width once viewport - 40px(wrap padding) clears that, i.e. around
   1225px — this breakpoint forces the 2-row mobile-style layout below that point instead of
   letting it try (and fail) to fit on one line. Only true phone-width viewports (<750px) fall
   back to the hamburger, where a two-row header would itself get uncomfortably cramped. */
@media (max-width: 1230px) {
  .nav { flex-wrap: wrap; row-gap: 10px; }
  .nav-links {
    order: 3; flex-basis: 100%; justify-content: center;
    padding-top: 10px; border-top: 1px solid var(--border);
  }
}
@media (max-width: 750px) {
  .nav { flex-wrap: nowrap; }
  .nav-links { display: none; }
  .nav-actions-desktop { display: none; }
  .nav-mobile-toggle { display: block; }
}
@media (max-width: 420px) {
  .logo { font-size: 0.95rem; gap: 6px; }
  .logo-mark { width: 28px; height: 28px; }
}

/* Touch targets: 44px is the accepted minimum tap-target height (Apple HIG / WCAG 2.5.5).
   .btn-sm and the language toggle rendered as small as 28-38px — fine for a mouse, too easy
   to mis-tap on a phone. Only widen the hit area on touch-sized viewports, not desktop. */
@media (max-width: 700px) {
  .btn-sm { min-height: 44px; padding: 12px 16px; }
  .lang-toggle { min-height: 40px; padding: 8px 12px; }
  .nav-mobile-toggle summary { min-height: 48px; min-width: 48px; display: flex; align-items: center; justify-content: center; }
}

/* ---------- Hero ---------- */
.hero {
  padding: 70px 0 50px;
  background:
    radial-gradient(circle at 15% 0%, rgba(37,99,235,0.08), transparent 45%),
    var(--bg);
  border-bottom: 1px solid var(--border);
}
.hero-grid { display: grid; grid-template-columns: 1.1fr 0.9fr; gap: 40px; align-items: center; }
@media (max-width: 900px) { .hero-grid { grid-template-columns: 1fr; } }

/* ---------- Photo hero: full-bleed job-site photo with dark overlay for text ---------- */
.hero-photo {
  position: relative;
  padding: 100px 0 80px;
  color: #fff;
  background-size: cover;
  background-position: center;
  overflow: hidden;
}
.hero-photo::before {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(10,15,23,0.82) 0%, rgba(10,15,23,0.72) 55%, rgba(10,15,23,0.9) 100%);
}
.hero-photo .wrap { position: relative; z-index: 1; }
.hero-photo .eyebrow { color: var(--gold-light, #fcd34d); }
.hero-photo h1, .hero-photo h2 { color: #fff; }
.hero-photo p { color: rgba(255,255,255,0.86); }
.hero-photo .stat b { color: #fff; }
.hero-photo .stat span { color: rgba(255,255,255,0.65); }
@media (max-width: 700px) {
  .hero-photo { padding: 56px 0 40px; }
  .hero { padding: 48px 0 36px; }
}

/* Contractor profile: bio + sidebar. Was a raw inline grid-template-columns:2fr 1fr with no
   mobile fallback — on a 375px phone that forced two ~250-340px columns side by side and blew
   the page out to ~620px wide (real horizontal-scroll bug, not just a squeeze). */
.profile-grid { grid-template-columns: 2fr 1fr; gap: 30px; }
@media (max-width: 860px) { .profile-grid { grid-template-columns: 1fr; } }

/* ---------- Header band: gradient + diagonal texture for pages without a hero photo ---------- */
.header-band {
  position: relative;
  padding: 54px 0 46px;
  color: #fff;
  background: linear-gradient(135deg, var(--accent) 0%, #1d4ed8 55%, var(--steel) 130%);
  overflow: hidden;
  border-bottom: 1px solid var(--steel-border);
}
.header-band::after {
  content: '';
  position: absolute; inset: 0;
  opacity: 0.10;
  background-image: repeating-linear-gradient(45deg, #fff 0, #fff 2px, transparent 2px, transparent 22px);
  pointer-events: none;
}
.header-band .wrap { position: relative; z-index: 1; }
/* Direct children only — text inside a floated card (e.g. signup's .form-card) keeps its
   normal light-background styling instead of inheriting the on-dark-gradient colors below. */
.header-band > .wrap > .eyebrow { color: #bfdbfe; }
.header-band > .wrap > h1, .header-band > .wrap > h2 { color: #fff; margin-bottom: 6px; }
.header-band > .wrap > p { color: rgba(255,255,255,0.82); margin: 0; }

/* ---------- Steel: dark section for contrast/rhythm between light sections ---------- */
.section-steel {
  background: var(--steel);
  border-top: 1px solid var(--steel-border);
  border-bottom: 1px solid var(--steel-border);
}
.section-steel h2, .section-steel h3 { color: var(--steel-text); }
.section-steel p { color: var(--steel-text-dim); }
.section-steel .eyebrow { color: var(--gold-light, #fcd34d); }
.section-steel .card { background: var(--steel-alt); border-color: var(--steel-border); }
.section-steel .card p { color: var(--steel-text-dim); }
.section-steel .stat b { color: var(--steel-text); }
.section-steel .stat span { color: var(--steel-text-dim); }

/* ---------- Sponsor treatment: gold, distinct from blue "verified" ---------- */
.sponsor-badge {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.08em; font-weight: 700;
  padding: 4px 9px; border-radius: 999px;
  background: var(--gold-bg); color: var(--gold); border: 1px solid rgba(180,83,9,0.3);
}
/* Bumped from a plain floating row of small logos to individual white "cards" (bigger, framed,
   real shadow) — reads as a proper trust bar instead of an afterthought, and gives every logo a
   consistent neutral background regardless of its own art (transparent PNGs, colored SVGs,
   whatever a sponsor sends over all look intentional sitting on the same white card). */
.sponsor-strip { display: flex; flex-wrap: wrap; gap: 20px; align-items: stretch; justify-content: center; }
.sponsor-strip a {
  display: flex; align-items: center; justify-content: center;
  background: var(--card); border: 1px solid var(--border); border-radius: 12px;
  padding: 18px 28px; min-width: 140px; min-height: 88px;
  box-shadow: 0 1px 3px rgba(16,24,40,0.06);
  transition: box-shadow 0.15s ease, transform 0.15s ease, border-color 0.15s ease;
}
.sponsor-strip a:hover { box-shadow: 0 8px 20px rgba(16,24,40,0.12); transform: translateY(-3px); border-color: var(--accent-dim); }
.sponsor-strip img { height: 72px; width: auto; max-width: 190px; object-fit: contain; }
.sponsor-card { border: 1px solid rgba(180,83,9,0.35) !important; background: linear-gradient(180deg, var(--gold-bg), var(--card) 40%); }
.gc-card { border: 1px solid rgba(21,128,61,0.35) !important; background: linear-gradient(180deg, #f0fdf4, var(--card) 40%); }

/* Directory-card tiers: sponsor (gold) and featured (blue) get a visibly tinted background +
   left accent bar so they stand out from plain verified cards at a glance, not just via badge.
   Sponsor cards span the FULL row (1 / -1), not a fixed column count — spanning just 2 of 3
   grid columns left a lopsided empty gap next to each one when there were 2+ sponsors, since
   each spans independently and neither backfills the other's leftover column. Full-width rows
   stack cleanly and are all the same size regardless of how many sponsors there are. */
.pro-card.sponsor-card {
  background: linear-gradient(135deg, #fde9b8, #fffbeb 60%); border: 1px solid rgba(180,83,9,0.4) !important; border-left: 5px solid var(--gold);
  grid-column: 1 / -1; padding: 28px; display: flex; flex-direction: column; justify-content: center;
}
.pro-card.sponsor-card h3 { font-size: 1.3rem; }
.pro-card.sponsor-card .logo-thumb { width: 56px !important; height: 56px !important; font-size: 22px !important; }
.pro-card.featured-card { background: linear-gradient(135deg, #dbeafe, #f5f9ff 60%); border: 1px solid rgba(37,99,235,0.35) !important; border-left: 5px solid var(--accent); }
.featured-tag { display: inline-flex; align-items: center; gap: 5px; font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.08em; font-weight: 700; padding: 4px 9px; border-radius: 999px; background: #dbeafe; color: var(--accent-dim); border: 1px solid rgba(37,99,235,0.3); }

/* Verified General Contractor membership — deliberately its own green, not gold (that's the B2B
   Sponsor partnership) and not blue (that's the paid Trade Featured placement). No full-row
   span like sponsor-card/title-sponsor-card below: GC is a membership tier, not a paid
   placement, so it shouldn't visually crowd out the grid the way a paid spot does. */
.pro-card.gc-card { background: linear-gradient(135deg, #dcfce7, #f5fdf8 60%); border: 1px solid rgba(21,128,61,0.35) !important; border-left: 5px solid var(--green); }
.gc-tag { display: inline-flex; align-items: center; gap: 5px; font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.08em; font-weight: 700; padding: 4px 9px; border-radius: 999px; background: #dcfce7; color: var(--green); border: 1px solid rgba(21,128,61,0.3); }

/* Title Sponsor: one level above the gold Sponsor tier — platinum, matching the strip and
   showcase treatment, so it's unmistakably the top of the pyramid without reusing gold. */
.pro-card.title-sponsor-card {
  background: linear-gradient(135deg, #3f3f46, #27272a 70%); border: 1px solid rgba(212,212,216,0.4) !important; border-left: 5px solid #d4d4d8;
  grid-column: 1 / -1; padding: 30px; display: flex; flex-direction: column; justify-content: center; color: #fff;
}
.pro-card.title-sponsor-card h3 { font-size: 1.4rem; color: #fff; }
.pro-card.title-sponsor-card .meta { color: rgba(255,255,255,0.7); }
.pro-card.title-sponsor-card p { color: rgba(255,255,255,0.85); }
.pro-card.title-sponsor-card .logo-thumb { width: 60px !important; height: 60px !important; font-size: 24px !important; }
.pro-card.title-sponsor-card .tag { background: rgba(255,255,255,0.1); color: #fff; border-color: rgba(255,255,255,0.2); }
.title-sponsor-badge { background: #27272a; color: #d4d4d8; border-color: rgba(212,212,216,0.4); }
.featured-tag { display: inline-flex; align-items: center; gap: 5px; font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.08em; font-weight: 700; padding: 4px 9px; border-radius: 999px; background: #dbeafe; color: var(--accent-dim); border: 1px solid rgba(37,99,235,0.3); }

.search-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 22px;
}
/* Second card under the trade-search form, same first-screen real estate — the homeowner's
   "actually I need several trades" path, deliberately as visible as the single-trade search
   rather than buried in a footer link or a lower page section. Text color override: .hero-photo
   p is white for text over the photo background, but this card sits on the white .search-card
   surface just like its sibling — without this it renders invisible (white-on-white). */
/* Deliberately a THIRD color on the page — not the standard blue accent, not the gold reserved
   for Sponsor/partnership badges — so this card visually separates itself from both instead of
   blending into "just another blue button" (user's call: "really cool, but I did not notice that
   for a while"). Emerald also just reads as "save money," which is the actual pitch. */
.hero-quotes-card {
  margin-top: 14px; position: relative;
  border-color: #a7f3d0; background: linear-gradient(165deg, #ecfdf5 0%, var(--card) 65%);
  box-shadow: 0 4px 18px rgba(5, 150, 105, 0.12);
}
.hero-photo .hero-quotes-card p { color: var(--text); }
.hero-quotes-badge {
  display: inline-flex; align-items: center; gap: 4px; margin-bottom: 10px;
  padding: 4px 10px; border-radius: 999px; background: #059669; color: #fff;
  font-size: 0.68rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em;
}
.btn-quotes { background: #059669; border-color: #059669; color: #fff; }
.btn-quotes:hover { background: #047857; border-color: #047857; }
.search-row { display: flex; gap: 10px; flex-wrap: wrap; }
.search-row select, .search-row input {
  flex: 1; min-width: 140px;
  background: var(--bg-alt);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 12px 14px;
  border-radius: 8px;
  font-size: 0.9rem;
}
.search-row select:focus, .search-row input:focus { outline: 1px solid var(--accent); }

.stat-row { display: flex; gap: 34px; margin-top: 28px; flex-wrap: wrap; }
.stat b { display: block; font-size: 2rem; font-weight: 900; color: var(--accent); }
.stat span { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.1em; color: var(--text-dim); }

/* ---------- Sections ---------- */
section { padding: 64px 0; }
.section-alt { background: var(--bg-alt); border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
.section-head { max-width: 640px; margin-bottom: 36px; }

.grid { display: grid; gap: 20px; }
.grid-4 { grid-template-columns: repeat(4, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 900px) { .grid-4, .grid-3 { grid-template-columns: repeat(2, 1fr); } }
/* Found in the full mobile pass, 2026-09-06 — a bare `1fr` track's automatic minimum size is
   its content's min-content size, not 0 (same "auto" default the grid-item min-width fix below
   covers, just one level up at the track itself) — so a <select> with a long option (a trade
   category name, say) forced the single mobile column wider than the actual viewport, blowing
   out the entire page's scroll width, even though grid-template-columns correctly read "1fr"
   here the whole time. minmax(0, 1fr) is what actually lets the track shrink below its
   content's natural width. The item-level min-width: 0 below is still needed too — without it,
   the <select> itself remains the thing forcing width, just contained to its own cell instead
   of blowing out the page. */
@media (max-width: 600px) { .grid-4, .grid-3, .grid-2, .grid-fill { grid-template-columns: minmax(0, 1fr); } }
.grid > * { min-width: 0; }

/* For card grids whose item count varies or won't necessarily divide evenly into a fixed
   column count (the all-trades category matrix, featured pros) — columns size themselves to
   the available width, so an incomplete last row stretches to fill it instead of leaving empty
   grid tracks off to one side. */
.grid-fill { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }

.card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 22px;
}
.card:hover { border-color: var(--accent-dim); }

.badge {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.08em; font-weight: 700;
  padding: 4px 9px; border-radius: 999px;
  background: rgba(21,128,61,0.10); color: var(--green); border: 1px solid rgba(21,128,61,0.28);
}
.badge-pending { background: rgba(180,83,9,0.10); color: var(--warn); border-color: rgba(180,83,9,0.28); }
.badge-outline { background: transparent; color: var(--text-dim); border: 1px solid var(--border); }

/* Verification Queue at-a-glance progress bar — added 2026-08-28 so a VA can see how far along
   each pending applicant is without reading the whole form (see routes/admin.js queue render). */
.queue-progress-track { height: 10px; border-radius: 999px; background: var(--border); overflow: hidden; }
.queue-progress-fill { height: 100%; border-radius: 999px; transition: width 0.2s ease; }
.queue-progress-badges { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 10px; }

/* Bigger text, bolder section highlights — user's call, 2026-08-28: "small writing... I'd like
   for stuff to be highlighted better... bigger icons, brighter." Started on the Verification
   Queue (.queue-card), then extended to other admin forms (Add Existing Member, Speed to Lead)
   and the contractor's own dashboard on the user's explicit "yes, both" — .big-form is the
   shared class for all of those. Scoped rather than changing .checklist/.small globally: those
   two are also used on the public contractor-profile page (a compact trust-badge display, not
   a working form), which deliberately stays as-is. */
.queue-card, .big-form { padding: 20px 22px; }
.queue-card h3, .big-form h3 { font-size: 1.35rem; }
.queue-card .checklist label, .big-form .checklist label { font-size: 1rem; }
.queue-card .small, .big-form .small { font-size: 0.85rem; }
.queue-card .queue-progress-badges .badge, .big-form .queue-progress-badges .badge { font-size: 0.75rem; padding: 5px 11px; }
.queue-card .queue-progress-badges .small, .big-form .queue-progress-badges .small { font-size: 0.95rem; }
.queue-card .badge-pending, .big-form .badge-pending { font-size: 0.8rem; padding: 6px 13px; font-weight: 800; }
.queue-card .queue-section-label, .big-form .queue-section-label {
  font-size: 0.92rem; font-weight: 800; letter-spacing: 0.02em; text-transform: none;
  color: var(--accent-dim); margin: 0 0 10px; display: flex; align-items: center; gap: 8px;
}
.queue-card .queue-section-label .icon, .big-form .queue-section-label .icon { font-size: 1.2rem; }
.queue-card .btn-outline.btn-sm, .big-form .btn-outline.btn-sm { font-size: 0.85rem; padding: 8px 14px; }
.big-form .field label { font-size: 0.92rem; }
.big-form h2 { font-size: 1.5rem; }

.category-card { display: flex; flex-direction: column; gap: 6px; }
.category-card .count { color: var(--accent); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.08em; font-weight: 700; }

/* ---------- Contractor cards ---------- */
.pro-card { display: flex; flex-direction: column; gap: 10px; }
.pro-card .top { display: flex; justify-content: space-between; align-items: flex-start; gap: 10px; }
.pro-card .rating { color: var(--accent); font-weight: 700; font-size: 0.85rem; }
.pro-card .meta { font-size: 0.8rem; color: var(--text-dim); }
.pro-card .tags { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 4px; }
.tag { font-size: 0.68rem; background: var(--bg-alt); border: 1px solid var(--border); padding: 3px 8px; border-radius: 999px; color: var(--text-dim); }
.js-distance { color: var(--accent); font-weight: 700; }

/* ---------- Logo thumbnails ---------- */
.logo-thumb { border-radius: 50%; object-fit: cover; flex-shrink: 0; border: 1px solid var(--border); background: var(--bg-alt); }
.logo-thumb-fallback { display: flex; align-items: center; justify-content: center; background: var(--accent); color: var(--on-accent); font-weight: 800; }

/* ---------- Directory map ---------- */
.map-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 14px; }
.map-toolbar-actions { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.map-wrap { position: relative; border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; margin-bottom: 26px; }
#directoryMap { height: 420px; width: 100%; background: var(--bg-alt); }
.map-pin-popup { font-family: inherit; }
.map-pin-popup h4 { margin: 0 0 4px; font-size: 0.9rem; text-transform: none; letter-spacing: 0; }
.map-pin-popup a { color: var(--accent); font-weight: 700; font-size: 0.8rem; }
.leaflet-popup-content-wrapper { background: var(--card); color: var(--text); border-radius: 8px; }
.leaflet-popup-tip { background: var(--card); }
.locate-btn { font-size: 0.78rem; }
/* Sort-by-Distance toggle: a bare native checkbox + text was easy to lose against the page
   background (tiny checkbox, no visual boundary). Give it the same bordered-pill weight as a
   button so it reads as a real, tappable control rather than blending in. */
.sort-distance-toggle {
  display: flex; align-items: center; gap: 8px; cursor: pointer;
  padding: 8px 14px; border: 1px solid var(--border); border-radius: 999px;
  font-size: 0.78rem; font-weight: 600; color: var(--text); white-space: nowrap;
}
.sort-distance-toggle:has(input:checked) { border-color: var(--accent); background: var(--gold-bg, #eff6ff); color: var(--accent-dim); }
.sort-distance-toggle input { width: 18px; height: 18px; flex-shrink: 0; accent-color: var(--accent); cursor: pointer; }
/* Below 480px, "Sort by Distance" + "Use My Location" no longer fit on one row without
   crowding — stack them full-width instead of letting flex squeeze them into each other. */
@media (max-width: 480px) {
  .map-toolbar-actions { flex-direction: column; align-items: stretch; gap: 10px; width: 100%; }
  .map-toolbar-actions .locate-btn { width: 100%; }
  .sort-distance-toggle { justify-content: center; }
}

/* Most directory visitors are homeowners on a phone (user's call) — the map is genuinely
   useful but shouldn't be the thing between them and the actual contractor list. Under 700px
   it starts collapsed behind a button instead of always-open; desktop is untouched (the toggle
   button itself only exists there in the DOM but stays hidden, .map-wrap keeps its normal
   always-visible display). See directory-map.js for the toggle + Leaflet invalidateSize() fix. */
.map-toggle-btn { display: none; }
@media (max-width: 700px) {
  .map-wrap { display: none; }
  .map-wrap.map-visible { display: block; }
  .map-toggle-btn { display: block; width: 100%; margin-bottom: 18px; }
}

/* ---------- Application stepper ---------- */
.stepper { display: flex; align-items: center; flex-wrap: wrap; gap: 0; margin-bottom: 22px; }
.step { display: flex; align-items: center; gap: 8px; }
.step-dot {
  width: 26px; height: 26px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
  font-size: 0.75rem; font-weight: 700; background: var(--bg-alt); color: var(--text-dim); border: 1px solid var(--border);
}
.step.done .step-dot { background: var(--green); color: #fff; border-color: var(--green); }
.step span { font-size: 0.78rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em; color: var(--text-dim); }
.step.done span { color: var(--text); }
.step-line { width: 28px; height: 2px; background: var(--border); margin: 0 8px; }

/* ---------- Onboarding checklist (post-verification dashboard home) ---------- */
.onboarding-step {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border-radius: 8px; margin-bottom: 8px;
  border: 1px solid var(--border); text-decoration: none; color: var(--text);
  transition: border-color 0.12s ease, background 0.12s ease;
}
.onboarding-step:hover { border-color: var(--accent); background: var(--bg-alt); }
.onboarding-step-dot {
  width: 22px; height: 22px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 0.72rem; font-weight: 800; border: 2px solid var(--border); color: transparent;
}
.onboarding-step.done { border-color: rgba(21,128,61,0.28); background: rgba(21,128,61,0.05); color: var(--text-dim); cursor: default; }
.onboarding-step.done .onboarding-step-dot { background: var(--green); border-color: var(--green); color: #fff; }
.onboarding-step-arrow { margin-left: auto; color: var(--accent); font-weight: 700; }

/* ---------- Document rows (dashboard / admin) ---------- */
.doc-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 10px 0; border-bottom: 1px solid var(--border); font-size: 0.88rem; }
.doc-row:last-child { border-bottom: none; }
.upload-drop { border: 1px dashed var(--border); border-radius: 8px; padding: 14px; font-size: 0.85rem; color: var(--text-dim); }

/* ---------- Forms ---------- */
form.stack { display: flex; flex-direction: column; gap: 14px; max-width: 520px; }
label { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-dim); font-weight: 700; display: block; margin-bottom: 6px; }
input, select, textarea {
  width: 100%;
  background: var(--bg-alt);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 12px 14px;
  border-radius: 8px;
  font-size: 0.92rem;
  font-family: inherit;
}
textarea { resize: vertical; min-height: 110px; }
input:focus, select:focus, textarea:focus { outline: 1px solid var(--accent); }
.field { margin-bottom: 4px; }
.form-card { background: var(--card); border: 1px solid var(--border); border-radius: var(--radius); padding: 28px; max-width: 480px; margin: 0 auto; }

.alert { padding: 12px 16px; border-radius: 8px; font-size: 0.85rem; margin-bottom: 16px; }
.alert-error { background: rgba(220,38,38,0.08); color: var(--red); border: 1px solid rgba(220,38,38,0.28); }
.alert-success { background: rgba(21,128,61,0.10); color: var(--green); border: 1px solid rgba(21,128,61,0.28); }

table { width: 100%; border-collapse: collapse; font-size: 0.88rem; }
th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--border); white-space: nowrap; }
th { color: var(--text-dim); text-transform: uppercase; font-size: 0.7rem; letter-spacing: 0.06em; }
/* Admin tables (contractors/leads/events) are wide with several columns — on a phone they'd
   force the whole page to scroll sideways. Scope the scroll to just the table instead. */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; margin: 0 0 20px; }
.table-scroll table { margin-bottom: 0; }

.checklist { display: flex; flex-direction: column; gap: 8px; }
.checklist label { display: flex; align-items: center; gap: 10px; text-transform: none; font-weight: 500; color: var(--text); font-size: 0.88rem; }
.checklist input[type=checkbox], .checklist input[type=radio] { width: auto; padding: 0; background: none; border: none; border-radius: 0; }

/* Speed to Lead category picker: grouped by trade group (Roofing/Siding, Kitchen/Bath, etc.)
   with each option as a bordered chip, instead of one flat alphabetical wall of ~38 plain
   checkboxes that was easy to lose things in. Disabled (over-the-cap) items get an explicit,
   readable dim rather than whatever the browser's default disabled-control styling does. */
.lead-cat-groups { display: flex; flex-direction: column; gap: 18px; }
.lead-cat-group h4 { margin: 0 0 8px; font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-dim); border-bottom: 1px solid var(--border); padding-bottom: 6px; }
.lead-cat-group-items { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }
@media (max-width: 480px) { .lead-cat-group-items { grid-template-columns: 1fr; } }
.lead-cat-item {
  display: flex; align-items: center; gap: 8px; padding: 8px 10px;
  border: 1px solid var(--border); border-radius: 8px;
  font-weight: 500; font-size: 0.85rem; color: var(--text); cursor: pointer;
}
.lead-cat-item:has(input:checked) { border-color: var(--accent); background: #eff6ff; color: var(--accent-dim); }
.lead-cat-item input { width: 16px; height: 16px; flex-shrink: 0; accent-color: var(--accent); }
.lead-cat-item:has(input:disabled) { opacity: 0.5; cursor: not-allowed; }

/* Get Quotes: "Hire a GC" vs "Hire Trades Directly" — two big radio cards, same
   :has(input:checked) pattern as .lead-cat-item/.sort-distance-toggle above rather than a new
   JS-driven toggle. Deliberately bigger/more prominent than a lead-cat-item — this is the one
   choice that changes how the whole rest of the form gets routed. */
.hiring-path-cards { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; margin: 8px 0; }
@media (max-width: 560px) { .hiring-path-cards { grid-template-columns: 1fr; } }
.hiring-path-card {
  position: relative; display: flex; flex-direction: column; gap: 4px; padding: 14px 16px;
  border: 1.5px solid var(--border); border-radius: 10px; cursor: pointer;
}
.hiring-path-card:has(input:checked) { border-color: var(--accent); background: #eff6ff; }
.hiring-path-card input {
  position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; pointer-events: none;
}
.hiring-path-title { font-weight: 700; font-size: 0.95rem; }
.hiring-path-card:has(input:checked) .hiring-path-title { color: var(--accent-dim); }
.hiring-path-desc { font-size: 0.82rem; color: var(--text-dim); line-height: 1.4; }

/* ---------- Footer ---------- */
footer.site { border-top: 1px solid var(--border); padding: 40px 0; background: var(--bg-alt); }
.footer-grid { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 24px; }
.footer-links { display: flex; gap: 18px; font-size: 0.82rem; color: var(--text-dim); flex-wrap: wrap; }
.footer-links a:hover { color: var(--accent); }
.small { font-size: 0.78rem; color: var(--text-dim); }

.pill-nav { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 26px; }
.pill { padding: 8px 14px; border-radius: 999px; border: 1px solid var(--border); font-size: 0.78rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.03em; color: var(--text-dim); white-space: nowrap; }
.pill.active, .pill:hover { border-color: var(--accent); color: var(--accent); }

/* Homepage hero's Homeowner/Contractor toggle sits directly on the dark hero photo, not the
   page's normal light background — the default light-mode .pill (faint border, dim-gray text)
   all but disappears there. Scoped override, bigger and higher-contrast: a solid white pill for
   the active side, a translucent-white outline for the inactive side, so it reads as an obvious
   two-way switch against a busy photo instead of blending in. */
.hero-pill-nav { gap: 10px; }
.hero-pill-nav .pill {
  padding: 10px 20px; font-size: 0.85rem; border-width: 1.5px;
  border-color: rgba(255,255,255,0.55); color: #fff; background: rgba(255,255,255,0.1);
}
.hero-pill-nav .pill:hover { border-color: #fff; color: #fff; background: rgba(255,255,255,0.2); }
.hero-pill-nav .pill.active {
  background: #fff; border-color: #fff; color: var(--accent-dim, var(--accent));
  box-shadow: 0 2px 10px rgba(0,0,0,0.25);
}

/* With 8 category groups, a scrolling chip row still asked a phone user to swipe through
   options one at a time to see what's even available. A native <select> shows every option in
   one tap and is the more familiar mobile pattern, so below 700px we swap the pill row for a
   dropdown entirely rather than keep the horizontal scroller. */
.group-select-mobile { display: none; }
@media (max-width: 700px) {
  .pill-nav-desktop { display: none; }
  .group-select-mobile {
    display: block; width: 100%; margin-bottom: 22px;
    background: var(--bg-alt); border: 1px solid var(--border); color: var(--text);
    padding: 12px 14px; border-radius: 8px; font-size: 0.9rem; font-weight: 600;
  }
}

/* Sub-filter: once a group is picked, narrow further to a specific trade within it (e.g.
   Outdoor & Site Services -> just Dumpster Rentals). Visually one step down from the primary
   group filter — smaller, pulled up tighter underneath it, with an explicit "Narrowing down
   within X" label so it reads as a second, nested level rather than just another row of pills
   (user's call — this was hard to tell apart before). */
.sub-filter-label { display: flex; align-items: center; gap: 6px; margin: -6px 0 10px; font-size: 0.8rem; color: var(--text-dim); }
.sub-filter-arrow { color: var(--accent); font-weight: 700; }
.pill-nav-sub { margin-top: 0; padding-left: 14px; border-left: 2px solid var(--border); }
.pill-sub { padding: 6px 12px; font-size: 0.72rem; background: var(--bg-alt); }
.group-select-mobile-sub { margin-top: -6px; font-size: 0.82rem; font-weight: 500; }

/* Mobile directory: the filter stack (group dropdown, sub-trade dropdown, search row, map
   toolbar) used to carry full desktop spacing straight down to a phone, pushing the actual
   contractor results well below the fold before you'd scrolled at all. Tighten the gaps, not the
   controls themselves — same fields, same order, just less dead air between them (user's call:
   "not so long... make it really easy"). */
@media (max-width: 700px) {
  .header-band { padding: 32px 0 28px; }
  .group-select-mobile { margin-bottom: 14px; }
  .sub-filter-label { margin: -2px 0 6px; }
  .search-row { margin-bottom: 14px !important; }
  .map-toolbar { margin-bottom: 10px; }
  .map-toggle-btn { margin-bottom: 14px; }
}

.quote-box { display: flex; gap: 16px; flex-wrap: wrap; }
.quote-box .card { flex: 1; min-width: 260px; }

details.faq { border-bottom: 1px solid var(--border); padding: 16px 0; }
details.faq summary { cursor: pointer; font-weight: 700; list-style: none; display: flex; justify-content: space-between; }
details.faq summary::-webkit-details-marker { display: none; }
details.faq summary::after { content: '+'; color: var(--accent); font-size: 1.3rem; }
details.faq[open] summary::after { content: '–'; }
details.faq .faq-a { margin-top: 10px; }
/* Homeowner vs. Contractor answers used to be told apart only by a plain <h3> — easy to miss
   entirely on a first pass (user's call: "didn't notice that until later"). A bordered pill with
   an icon reads as a real section break instead of just another line of text, and stays sticky
   while scrolling that section so it's never ambiguous which half of the page you're in. */
.faq-section-head {
  display: flex; align-items: center; gap: 10px; margin: 36px 0 6px;
  padding: 10px 16px; border-radius: 999px; background: var(--accent-bg, #eff6ff);
  border: 1px solid var(--accent); position: sticky; top: 8px; z-index: 2;
}
.faq-section-head:first-child { margin-top: 0; }
.faq-section-icon { font-size: 1.1rem; line-height: 1; }
.faq-section-head h3 { margin: 0; font-size: 0.95rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--accent-dim, var(--accent)); }
/* Lets faq_pro_a2/a3 (cost + package differences) break out as real bullet lists instead of one
   dense paragraph — user's call: "kind of hard to read." */
.faq-list { margin: 8px 0 0; padding-left: 20px; display: flex; flex-direction: column; gap: 6px; }
.faq-list li { line-height: 1.5; }

.dash-shell { display: grid; grid-template-columns: 220px 1fr; gap: 28px; }
@media (max-width: 800px) { .dash-shell { grid-template-columns: minmax(0, 1fr); } }
/* Same fix as .grid > * above, one level higher — this is what was ACTUALLY still blowing out
   admin's mobile width after that fix: .dash-shell is its own separate grid (nav + content),
   and its content child (a plain, unclassed <div>) is itself a grid item whose default
   min-width: auto let its own content (the .grid-4 filter form, on Lead History) force it wider
   than the single mobile column, even though the column's own track was already correctly
   sized. A grid item's width doesn't stop at its track's size unless min-width: 0 says so. */
.dash-shell > * { min-width: 0; }
.dash-nav { display: flex; flex-direction: column; gap: 4px; }
.dash-nav a { padding: 10px 14px; border-radius: 8px; font-size: 0.85rem; font-weight: 600; color: var(--text-dim); }
.dash-nav a:hover, .dash-nav a.active { background: var(--card); color: var(--accent); }

.kpi-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-bottom: 28px; }
.kpi-row-5 { grid-template-columns: repeat(5, 1fr); }
@media (max-width: 900px) { .kpi-row-5 { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 700px) { .kpi-row, .kpi-row-5 { grid-template-columns: repeat(2, 1fr); } }
.kpi { background: var(--card); border: 1px solid var(--border); border-radius: var(--radius); padding: 16px; }
.kpi b { display: block; font-size: 1.6rem; color: var(--accent); }
.kpi span { font-size: 0.7rem; text-transform: uppercase; color: var(--text-dim); letter-spacing: 0.06em; }

/* Larger variant for a top-of-page "whole platform at a glance" strip — same shape as .kpi,
   bigger number, subtle accent-tinted background so it reads as the headline row rather than
   just another stat block further down the page. */
.kpi-hero { background: linear-gradient(160deg, var(--card), var(--bg-alt)); border: 1px solid var(--border); border-radius: var(--radius); padding: 18px 16px; }
.kpi-hero b { display: block; font-size: 1.9rem; color: var(--accent); font-variant-numeric: tabular-nums; }
.kpi-hero span { font-size: 0.7rem; text-transform: uppercase; color: var(--text-dim); letter-spacing: 0.06em; }

/* ---------- Admin: top-of-page banners ---------- */
/* New applicants / open payment alerts — shown on EVERY admin tab, not just Verification Queue
   or Alerts themselves, so nothing needing attention is only discoverable by clicking around.
   Sits directly under the page title, above the KPI row. Each row is its own clickable bar
   straight to the tab that handles it; the stack only exists in the DOM when there's actually
   something to show. */
.admin-banner-stack { display: flex; flex-direction: column; gap: 10px; margin-top: 16px; }
.admin-banner {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 13px 18px; border-radius: var(--radius); font-size: 0.9rem; font-weight: 600;
  text-decoration: none; color: var(--text);
}
.admin-banner span:last-child { font-size: 0.8rem; font-weight: 700; white-space: nowrap; }
.admin-banner.info { background: rgba(37,99,235,0.08); border: 1px solid rgba(37,99,235,0.3); }
.admin-banner.info span:last-child { color: var(--accent); }
.admin-banner.urgent { background: rgba(220,38,38,0.08); border: 1px solid rgba(220,38,38,0.32); }
.admin-banner.urgent span:last-child { color: #dc2626; }
.admin-banner:hover { filter: brightness(0.97); }

/* ---------- Admin metrics: section framing ---------- */
/* Each metrics section (Speed to Lead, Contractors, Quote Requests...) gets its own visually
   distinct block — icon + title + one-line subtitle, then a divider — instead of a bare <h3>
   floating in the page flow. Keeps a long metrics page scannable in sections rather than one
   undifferentiated scroll. */
.metrics-section { margin-bottom: 36px; }
.metrics-section-head { display: flex; align-items: baseline; gap: 10px; padding-bottom: 10px; margin-bottom: 16px; border-bottom: 1px solid var(--border); }
.metrics-section-head .icon { font-size: 1.15rem; line-height: 1; }
.metrics-section-head h3 { margin: 0; font-size: 1.02rem; }
.metrics-section-head p { margin: 0; font-size: 0.78rem; color: var(--text-dim); }
@media (max-width: 560px) { .metrics-section-head { flex-wrap: wrap; } }

/* ---------- Admin alerts tab ---------- */
/* Two-lane ops to-do list (revoke Facebook access / re-approve it) — a colored left rail on
   each card is the at-a-glance signal (red = pull access, green = restore it) so a VA working
   through the queue doesn't have to read every card's text to know which lane it's in. */
.alerts-summary { display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px; margin-bottom: 28px; }
@media (max-width: 600px) { .alerts-summary { grid-template-columns: 1fr; } }
.alerts-summary-card { border-radius: var(--radius); padding: 16px 18px; display: flex; align-items: center; gap: 14px; border: 1px solid var(--border); }
.alerts-summary-card .num { font-size: 1.8rem; font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1; }
.alerts-summary-card .label { font-size: 0.78rem; color: var(--text-dim); }
.alerts-summary-card.revoke { background: rgba(220,38,38,0.06); border-color: rgba(220,38,38,0.25); }
.alerts-summary-card.revoke .num { color: #dc2626; }
.alerts-summary-card.restore { background: rgba(21,128,61,0.06); border-color: rgba(21,128,61,0.25); }
.alerts-summary-card.restore .num { color: var(--green); }

.alert-card { display: flex; gap: 14px; align-items: flex-start; background: var(--card); border: 1px solid var(--border); border-radius: var(--radius); padding: 16px 18px; margin-bottom: 12px; border-left: 4px solid var(--border); }
.alert-card.revoke { border-left-color: #dc2626; }
.alert-card.restore { border-left-color: var(--green); }
.alert-card-body { flex: 1; min-width: 0; }
.alert-card-actions { display: flex; flex-direction: column; gap: 8px; align-items: stretch; flex-shrink: 0; }
.alert-card-actions form { display: contents; }
.alert-card-actions .btn { white-space: nowrap; }
@media (max-width: 560px) { .alert-card { flex-direction: column; } .alert-card-actions { flex-direction: row; width: 100%; } .alert-card-actions .btn { flex: 1; } }

/* ---------- Admin metrics: bar charts ---------- */
/* Horizontal ranked bars — leads by status/source, top categories, tier/subscription
   breakdowns. Fixed label column keeps every bar's track starting at the same x position
   regardless of label length, so the bars themselves stay visually comparable. */
.bar-chart { display: flex; flex-direction: column; gap: 10px; }
.bar-row { display: grid; grid-template-columns: 148px 1fr 46px; align-items: center; gap: 10px; }
.bar-label { font-size: 0.82rem; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bar-track { background: var(--bg-alt); border-radius: 6px; height: 16px; overflow: hidden; border: 1px solid var(--border); }
.bar-fill { height: 100%; border-radius: 5px; background: linear-gradient(90deg, var(--accent), #1d4ed8); }
.bar-value { text-align: right; font-size: 0.82rem; font-weight: 700; font-variant-numeric: tabular-nums; }
@media (max-width: 560px) { .bar-row { grid-template-columns: 100px 1fr 36px; } .bar-label { font-size: 0.74rem; } }

/* Small preset-range switcher above a chart (Metrics tab's Leads by Trade). Plain links so it
   works with no JS — each one just reloads the page with a different ?period=. */
.period-picker { display: flex; gap: 4px; flex-wrap: wrap; }
.period-picker a { font-size: 0.74rem; padding: 4px 9px; border-radius: 999px; border: 1px solid var(--border); color: var(--text-dim); text-decoration: none; white-space: nowrap; }
.period-picker a:hover { color: var(--text); border-color: var(--accent); }
.period-picker a.active { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; }

/* Vertical trend chart — daily activity over the last 7 days. */
.trend-chart { display: flex; align-items: flex-end; gap: 10px; height: 130px; padding-top: 22px; }
.trend-bar-wrap { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; height: 100%; position: relative; }
.trend-bar-value { font-size: 0.72rem; font-weight: 700; color: var(--text-dim); font-variant-numeric: tabular-nums; margin-bottom: 4px; }
.trend-bar { width: 100%; max-width: 36px; background: linear-gradient(180deg, var(--accent), #1d4ed8); border-radius: 5px 5px 0 0; min-height: 3px; }
.trend-bar-label { font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-dim); margin-top: 6px; }

.install-banner {
  display: none;
  align-items: center; justify-content: space-between; gap: 12px;
  background: var(--accent); color: var(--on-accent); font-weight: 700; font-size: 0.85rem;
  padding: 10px 16px;
}
.install-banner.show { display: flex; }

/* Events month-grid calendar (see routes/public.js's renderEventsCalendar) — plain CSS grid, no
   JS/library needed since Prev/Next just navigate to a new ?month= URL. */
.events-calendar { border: 1px solid var(--border); border-radius: var(--radius); padding: 16px; background: var(--bg-alt); }
.cal-nav { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 14px; }
.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }
.cal-grid-header { margin-bottom: 4px; }
.cal-weekday { text-align: center; font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-dim); font-weight: 700; padding: 4px 0; }
.cal-cell { min-height: 78px; background: #fff; border: 1px solid var(--border); border-radius: 6px; padding: 4px 5px; overflow: hidden; }
.cal-cell-empty { background: transparent; border-color: transparent; }
.cal-cell-has-events { border-color: var(--accent); }
.cal-daynum { display: block; font-size: 0.78rem; font-weight: 700; color: var(--text-dim); margin-bottom: 2px; }
.cal-event { display: block; font-size: 0.7rem; line-height: 1.3; color: var(--accent); text-decoration: none; margin-bottom: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cal-event:hover { text-decoration: underline; }
@media (max-width: 700px) {
  .cal-cell { min-height: 54px; }
  .cal-weekday { font-size: 0.62rem; }
  .cal-event { font-size: 0.62rem; }
}

/* Homepage real-reviews strip (see routes/public.js's homeownerReviews query) — pure CSS
   auto-scroll, no JS/library. The card list is rendered twice back-to-back in the DOM so
   translateX(-50%) loops seamlessly; hover and reduced-motion both stop the motion. */
.reviews-marquee {
  overflow: hidden; margin-top: 28px;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}
.reviews-track { display: flex; gap: 18px; width: max-content; animation: reviews-scroll 50s linear infinite; }
.reviews-marquee:hover .reviews-track { animation-play-state: paused; }
.review-card {
  flex: 0 0 320px; background: var(--card); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 18px 20px; text-decoration: none; color: var(--text); display: flex; flex-direction: column; gap: 8px;
}
.review-card:hover { border-color: var(--accent-dim); }
.review-card-stars { margin: 0; color: var(--gold, #b8860b); letter-spacing: 1px; }
.review-card-text { margin: 0; font-size: 0.92rem; line-height: 1.5; flex: 1; }
.review-card-author { margin: 0; font-size: 0.82rem; font-weight: 700; color: var(--text-dim); }
.review-card-author span { font-weight: 400; }
@keyframes reviews-scroll { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) {
  .reviews-track { animation: none; overflow-x: auto; }
  .reviews-marquee { -webkit-mask-image: none; mask-image: none; }
}

/* Sponsor/Title Partner tier comparison (/sponsors) — checkmark rows instead of a plain <ul>,
   short single-line items so the two cards (forced to equal height by the grid) actually fill
   that height evenly instead of one trailing off into empty space below the other. */
.feature-list { margin: 0 0 18px; display: flex; flex-direction: column; gap: 13px; }
.feature-row { display: flex; align-items: flex-start; gap: 11px; }
.feature-check {
  flex-shrink: 0; width: 20px; height: 20px; border-radius: 50%; margin-top: 1px;
  display: flex; align-items: center; justify-content: center;
  font-size: 0.68rem; font-weight: 700; background: var(--accent); color: #fff;
}
.feature-check.gold { background: var(--gold, #b45309); }
.feature-check.on-dark { background: rgba(255,255,255,0.16); color: #fff; }
.feature-row span:last-child { line-height: 1.45; }
.feature-caption { font-size: 0.82rem; line-height: 1.5; margin: 0 0 20px; }

/* =====================================================================================
   ADMIN REDESIGN — 2026-11-08
   Everything below is scoped to body.admin-ui (set by page({ adminChrome: true }) in
   lib/layout.js), so none of it can leak onto the public site or a contractor's own
   dashboard. Goals, per the user: easier to understand, visually better — same pages and
   features, clearer grouping, plain-English labels, status shown as colored pills instead of
   raw database words, and nothing important (Manage / Delete) pushed off the right edge.
   ===================================================================================== */
body.admin-ui { background: var(--bg); }
body.admin-ui .wrap { max-width: min(96vw, 120rem); }
body.admin-ui .card:hover { border-color: var(--border); }

/* Slim top bar (replaces the public header, sponsor banners and footer inside the admin) */
.admin-bar { background: var(--steel); color: var(--steel-text); position: sticky; top: 0; z-index: 50; }
.admin-bar-inner { max-width: min(96vw, 120rem); margin: 0 auto; padding: 0 20px; height: 52px; display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.admin-bar-brand { display: flex; align-items: center; gap: 8px; font-weight: 800; font-size: 0.82rem; letter-spacing: 0.04em; color: #fff; white-space: nowrap; }
.admin-bar-brand span { color: #60a5fa; }
.admin-bar-brand em { font-style: normal; font-weight: 700; font-size: 0.68rem; letter-spacing: 0.1em; text-transform: uppercase; background: rgba(255,255,255,0.14); padding: 3px 8px; border-radius: 999px; margin-left: 4px; }
.admin-bar .logo-mark { width: 26px; height: 26px; }
.admin-bar-links { display: flex; align-items: center; gap: 18px; font-size: 0.8rem; }
.admin-bar-links a, .admin-bar-logout { color: var(--steel-text-dim); font-weight: 600; background: none; border: 0; padding: 0; font: inherit; font-size: 0.8rem; cursor: pointer; }
.admin-bar-links a:hover, .admin-bar-logout:hover { color: #fff; }
@media (max-width: 560px) { .admin-bar-brand em { display: none; } .admin-bar-links { gap: 12px; } .admin-bar-links a:first-child { display: none; } }

/* Page header + "needs attention" + stat cards */
.admin-page { padding: 26px 0 60px; }
.admin-title-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 18px; }
.admin-title-row h1 { margin: 0; font-size: 1.6rem; }
.admin-title-row .lang-toggle { margin-left: 0 !important; }
.admin-banner-stack { margin: 0 0 20px; }
.admin-section-label { margin: 0 0 8px; font-size: 0.7rem; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-dim); }
body.admin-ui .kpi-row { margin-bottom: 26px; }
body.admin-ui a.kpi { display: block; transition: border-color 0.15s, transform 0.15s; }
body.admin-ui a.kpi:hover { border-color: var(--accent); transform: translateY(-1px); }
body.admin-ui .kpi b { font-size: 1.9rem; line-height: 1.1; font-variant-numeric: tabular-nums; }
body.admin-ui .kpi span { display: block; margin-top: 4px; font-size: 0.74rem; }

/* Sidebar, grouped */
body.admin-ui .dash-shell { grid-template-columns: 14rem minmax(0, 1fr); align-items: start; gap: 32px; }
.admin-side { position: sticky; top: 68px; gap: 2px; }
.admin-side-h { margin: 16px 0 4px 12px; font-size: 0.66rem; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-dim); opacity: 0.8; }
.admin-side-h:first-child { margin-top: 0; }
.admin-side a { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.admin-side a.active { background: rgba(37,99,235,0.1); color: var(--accent); }
.admin-side a:hover:not(.active) { background: var(--bg-alt); color: var(--text); }
.nav-count { font-size: 0.65rem; padding: 2px 7px; letter-spacing: 0; }
.admin-side-foot { margin-top: 22px; padding-top: 14px; border-top: 1px solid var(--border); }
.admin-side-foot button { background: none; border: 0; padding: 0 12px; font-size: 0.75rem; color: var(--text-dim); cursor: pointer; text-decoration: underline; }
@media (max-width: 800px) {
  body.admin-ui .dash-shell { grid-template-columns: minmax(0, 1fr); gap: 16px; }
  .admin-side { position: static; flex-direction: row; flex-wrap: nowrap; overflow-x: auto; gap: 6px; padding-bottom: 6px; -webkit-overflow-scrolling: touch; }
  .admin-side-h, .admin-side-foot { display: none; }
  .admin-side a { white-space: nowrap; background: var(--card); border: 1px solid var(--border); }
}

/* Section header used at the top of each admin screen */
.admin-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; flex-wrap: wrap; margin-bottom: 14px; }
.admin-head h2 { margin: 0; font-size: 1.35rem; }
.admin-sub { margin: 2px 0 0; font-size: 0.82rem; color: var(--text-dim); }
.admin-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.admin-note { margin: 0 0 12px; padding: 10px 14px; border-radius: var(--radius); font-size: 0.85rem; background: rgba(37,99,235,0.07); border: 1px solid rgba(37,99,235,0.22); }
.admin-note a { color: var(--accent); font-weight: 700; }
.admin-note-amber { background: rgba(180,83,9,0.08); border-color: rgba(180,83,9,0.28); }
.admin-note-red { background: rgba(220,38,38,0.07); border-color: rgba(220,38,38,0.28); color: #b91c1c; }

/* "More tools" dropdown */
.admin-menu { position: relative; }
.admin-menu summary { list-style: none; cursor: pointer; }
.admin-menu summary::-webkit-details-marker { display: none; }
.admin-menu-pop { position: absolute; right: 0; top: calc(100% + 6px); z-index: 20; min-width: 280px; background: var(--card); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: 0 10px 30px rgba(15,23,32,0.14); padding: 6px; }
.admin-menu-pop a, .admin-menu-pop button { display: block; width: 100%; text-align: left; padding: 10px 12px; border: 0; background: none; border-radius: 8px; font: inherit; font-size: 0.82rem; font-weight: 600; color: var(--text); cursor: pointer; }
.admin-menu-pop a:hover, .admin-menu-pop button:hover { background: var(--bg-alt); color: var(--accent); }
.admin-menu-pop form { margin: 0; }

/* Search + bulk bar */
.admin-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 12px; }
.admin-toolbar input[type="search"] { flex: 1 1 280px; max-width: 420px; margin: 0; }
.bulk-bar { display: flex; align-items: center; gap: 12px; font-size: 0.85rem; font-weight: 600; }
.bulk-bar[hidden] { display: none; }
.bulk-bar a { color: var(--accent); }
.btn-danger { color: var(--red); border-color: var(--red); }
.btn-danger:hover { background: rgba(220,38,38,0.08); color: var(--red); border-color: var(--red); }

/* Tables: card look, quieter header, row hover, status pills */
body.admin-ui .table-scroll { background: var(--card); border: 1px solid var(--border); border-radius: var(--radius); }
body.admin-ui table { font-size: 0.88rem; }
body.admin-ui th { background: var(--bg-alt); padding: 11px 14px; font-size: 0.68rem; }
body.admin-ui td { padding: 12px 14px; vertical-align: middle; }
body.admin-ui tr:last-child td { border-bottom: 0; }
body.admin-ui tr:hover td { background: rgba(37,99,235,0.03); }
.admin-table td { white-space: normal; }
.admin-table .col-check { width: 36px; padding-right: 0; }
.admin-table .col-main { min-width: 220px; }
.admin-table .col-price { white-space: nowrap; font-weight: 700; font-variant-numeric: tabular-nums; }
.admin-table .col-pills { display: table-cell; }
.admin-table .col-pills .pill { margin: 2px 4px 2px 0; }
.admin-table .col-actions { white-space: nowrap; text-align: right; }
.admin-table .col-actions form { display: inline; margin: 0 0 0 10px; }
.row-title { display: block; font-weight: 700; color: var(--text); }
.row-title:hover { color: var(--accent); }
.row-sub { display: block; font-size: 0.76rem; font-weight: 400; color: var(--text-dim); max-width: 340px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.col-price .row-sub { display: inline; margin-left: 2px; }
.row-ok { font-size: 0.8rem; color: var(--text-dim); white-space: nowrap; }
.link-danger { background: none; border: 0; padding: 4px 2px; font-size: 0.76rem; color: var(--text-dim); cursor: pointer; text-decoration: underline; }
.link-danger:hover { color: var(--red); }

.pill { display: inline-flex; align-items: center; gap: 4px; padding: 3px 10px; border-radius: 999px; font-size: 0.72rem; font-weight: 700; white-space: nowrap; border: 1px solid transparent; }
.pill-green { background: rgba(21,128,61,0.1); color: var(--green); border-color: rgba(21,128,61,0.25); }
.pill-amber { background: rgba(180,83,9,0.1); color: var(--warn); border-color: rgba(180,83,9,0.28); }
.pill-red { background: rgba(220,38,38,0.1); color: #b91c1c; border-color: rgba(220,38,38,0.3); }
.pill-blue { background: rgba(37,99,235,0.1); color: var(--accent-dim); border-color: rgba(37,99,235,0.28); }
.pill-gold { background: var(--gold-bg); color: var(--gold); border-color: rgba(180,83,9,0.3); }
.pill-grey { background: var(--bg-alt); color: var(--text-dim); border-color: var(--border); }

/* ---------- Manage Contractor page ---------- */
.mgr-back { font-size: 0.82rem; color: var(--accent); font-weight: 600; }
.mgr-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin: 10px 0 16px; }
.mgr-top h2 { margin: 0 0 6px; font-size: 1.6rem; }
.mgr-pills { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 6px; }
.mgr-facts { margin: 0; font-size: 0.86rem; color: var(--text-dim); }
.mgr-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; margin-bottom: 24px; }
.mgr-stat { background: var(--card); border: 1px solid var(--border); border-radius: var(--radius); padding: 14px 16px; }
.mgr-stat small { display: block; font-size: 0.68rem; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-dim); margin-bottom: 6px; }
.mgr-stat strong { display: block; font-size: 1.25rem; font-variant-numeric: tabular-nums; }
.mgr-stat span { display: block; margin-top: 2px; font-size: 0.76rem; color: var(--text-dim); }
.mgr-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 28px; align-items: start; }
@media (max-width: 980px) { .mgr-grid { grid-template-columns: minmax(0, 1fr); } }
.mgr-col > * { min-width: 0; }
.mgr-h { margin: 0 0 12px; padding-bottom: 8px; border-bottom: 2px solid var(--border); font-size: 0.78rem; font-weight: 800; letter-spacing: 0.09em; text-transform: uppercase; color: var(--text-dim); }
.mgr-col .mgr-h:not(:first-child) { margin-top: 30px; }
body.admin-ui .mgr-col .card, body.admin-ui .mgr-col details.card { max-width: none !important; width: 100%; }
body.admin-ui .mgr-col details.card > summary { cursor: pointer; font-weight: 700; }
.danger-zone { margin-top: 36px; padding: 16px 20px; border: 1px solid rgba(220,38,38,0.35); border-radius: var(--radius); background: rgba(220,38,38,0.04); display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.danger-zone p { margin: 0; font-size: 0.84rem; color: var(--text-dim); }
.danger-zone strong { color: #b91c1c; display: block; font-size: 0.9rem; }
.danger-zone form { margin: 0 !important; }

/* Sub-headings inside an admin screen + small row notes (admin redesign 2026-11-08) */
body.admin-ui .admin-subhead { margin: 26px 0 10px; font-size: 1.05rem; }
body.admin-ui .admin-subhead span { font-size: 0.78rem; font-weight: 400; color: var(--text-dim); }
.row-warn { color: var(--warn); font-weight: 600; }
.admin-bar-links a, .admin-bar-logout { white-space: nowrap; }
@media (max-width: 560px) { .admin-bar-links a[href="/dashboard"] { display: none; } .admin-bar-inner { padding: 0 14px; } }

/* Scale the whole admin up on bigger screens — everything here is sized in rem, so bumping the
   root font size grows text, buttons, tables and spacing together (and the 82rem container with
   them). Fixes "still looks small" on a large monitor, 2026-11-08. Phones/laptops are unchanged. */
@media (min-width: 1100px) { html.admin-root { font-size: 112.5%; } }
@media (min-width: 1500px) { html.admin-root { font-size: 125%; } }
@media (min-width: 1900px) { html.admin-root { font-size: 137.5%; } }
body.admin-ui table { font-size: 0.95rem; }
body.admin-ui .row-sub { font-size: 0.82rem; max-width: 22rem; }
body.admin-ui .admin-side a { font-size: 0.92rem; }
body.admin-ui .pill { font-size: 0.78rem; }

/* ---------- Admin: shorter pages (2026-11-08) ---------- */
/* Collapsible sections ("folds"): the long, rarely-touched parts of a screen start closed so the
   page isn't a mile of scrolling. Used by Categories, Speed to Lead, Metrics and Manage. */
body.admin-ui .admin-fold { background: var(--card); border: 1px solid var(--border); border-radius: var(--radius); margin: 0 0 12px; }
.admin-fold > summary { cursor: pointer; list-style: none; padding: 14px 18px; font-weight: 700; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.admin-fold > summary::-webkit-details-marker { display: none; }
.admin-fold > summary::before { content: '▸'; color: var(--text-dim); font-size: 0.9em; transition: transform 0.15s; }
.admin-fold[open] > summary::before { transform: rotate(90deg); }
.admin-fold[open] > summary { border-bottom: 1px solid var(--border); }
.admin-fold > *:not(summary) { margin-left: 18px; margin-right: 18px; }
.admin-fold > summary + * { margin-top: 16px; }
.admin-fold > :last-child { margin-bottom: 18px; }
.admin-fold-hint { font-weight: 400; font-size: 0.82rem; color: var(--text-dim); }
.admin-fold .card { background: var(--bg-alt); }
.admin-status .alert { max-width: none; }
body.admin-ui .metrics-section { margin-bottom: 12px; }
.metrics-section > summary.metrics-section-head { padding: 14px 18px; margin: 0; border-bottom: 0; align-items: center; }
.metrics-section[open] > summary.metrics-section-head { border-bottom: 1px solid var(--border); }
.metrics-section > summary.metrics-section-head::before { margin-right: 2px; }

/* Speed to Lead form: wider card, trade picker collapsed, city/state side by side */
.lead-form-card { max-width: 46rem; }
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.form-row .field { margin: 0; }
details.also-trades > summary { cursor: pointer; font-weight: 700; padding: 6px 0 10px; }
details.also-trades[open] > summary { padding-bottom: 6px; }
.admin-search { max-width: 26rem; margin: 0 0 14px; display: block; }
.cat-group > .table-scroll { border: 0; }

/* Verification Queue: info + documents on the left, the review form on the right */
.queue-cols { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 24px; align-items: start; }
@media (max-width: 1000px) { .queue-cols { grid-template-columns: minmax(0, 1fr); gap: 0; } }
.queue-cols > * { min-width: 0; }

/* Tighter header strip + sidebar so more of every screen is actual content */
body.admin-ui .kpi { padding: 10px 14px; }
body.admin-ui .kpi b { font-size: 1.6rem; }
body.admin-ui .kpi-row { margin-bottom: 18px; gap: 10px; }
.admin-title-row { margin-bottom: 12px; }
.admin-banner-stack { margin-bottom: 14px; }
body.admin-ui .admin-banner { padding: 9px 14px; }
.admin-side a { padding: 7px 12px; }
.admin-side-h { margin-top: 12px; }

/* ---------- Login / set-password: bigger and easier to see on large screens (2026-11-08) ---------- */
/* Was a 480px card with 16px text floating in a wide blue band. The card and its text now scale
   with the screen (root font bumps on big monitors, same steps as the admin), and fields and the
   button are larger tap/click targets. Only the login and set-password pages use these classes. */
@media (min-width: 1100px) { html:has(body.auth-page) { font-size: 112.5%; } }
@media (min-width: 1500px) { html:has(body.auth-page) { font-size: 125%; } }
@media (min-width: 1900px) { html:has(body.auth-page) { font-size: 137.5%; } }
.form-card.auth-card { max-width: 32rem; padding: 2.2rem 2.4rem; }
.auth-card h2 { font-size: 2rem; margin: 6px 0 18px; }
.auth-card .field input { padding: 0.9rem 1rem; font-size: 1.05rem; }
.auth-card .btn { padding: 1rem 1.2rem; font-size: 0.95rem; }
.auth-page .header-band { padding-top: 5rem !important; padding-bottom: 6rem !important; }
@media (max-width: 560px) { .form-card.auth-card { padding: 1.6rem 1.3rem; } .auth-card h2 { font-size: 1.6rem; } }
.auth-card h2 { color: var(--text); }
.auth-card .eyebrow { margin-bottom: 4px; display: inline-block; }

/* Ultra-wide monitors (2026-11-08): keep stepping the text up past 1900px so it never looks tiny
   in a sea of empty space, and let the admin container use nearly the full width (see the
   min(96vw, 120rem) container above). Login/set-password get the same steps. */
@media (min-width: 2400px) { html.admin-root, html:has(body.auth-page) { font-size: 162.5%; } }
@media (min-width: 3000px) { html.admin-root, html:has(body.auth-page) { font-size: 187.5%; } }
@media (min-width: 3600px) { html.admin-root, html:has(body.auth-page) { font-size: 212.5%; } }

/* ---------- Contractor dashboard: scale up on big screens too (2026-11-08) ---------- */
/* Same idea as the admin and login pages: the dashboard was a 1180px column of 16px text on a
   very wide monitor. Only the logged-in contractor dashboard opts in (body.dash-page); the public
   marketing pages and directory are unchanged. */
@media (min-width: 1100px) { html:has(body.dash-page) { font-size: 112.5%; } }
@media (min-width: 1500px) { html:has(body.dash-page) { font-size: 125%; } }
@media (min-width: 1900px) { html:has(body.dash-page) { font-size: 137.5%; } }
@media (min-width: 2400px) { html:has(body.dash-page) { font-size: 162.5%; } }
@media (min-width: 3000px) { html:has(body.dash-page) { font-size: 187.5%; } }
@media (min-width: 3600px) { html:has(body.dash-page) { font-size: 212.5%; } }
body.dash-page .wrap { max-width: min(96vw, 100rem); }

/* ---------- Homepage "All Trades" group cards (2026-11-08) ---------- */
/* Was an auto-fit grid of up to 5 columns, which with 11 groups left Commercial Services alone on
   a last row, left-aligned. Now 4 across with every row centered (4 / 4 / 3), so an odd last row
   sits in the middle instead of orphaned; steps down to 3, 2 and 1 across on smaller screens.
   Cards in a row stay equal height, titles and descriptions are toned down so 11 cards read as a
   clean set rather than a wall of heavy uppercase text. */
.trade-grid { display: flex; flex-wrap: wrap; justify-content: center; gap: 20px; }
.trade-grid > .category-card { flex: 0 1 calc((100% - 60px) / 4); min-width: 220px; }
@media (max-width: 1000px) { .trade-grid > .category-card { flex-basis: calc((100% - 40px) / 3); } }
@media (max-width: 720px) { .trade-grid > .category-card { flex-basis: calc((100% - 20px) / 2); min-width: 0; } }
@media (max-width: 460px) { .trade-grid > .category-card { flex-basis: 100%; } }
.trade-grid .category-card > div:last-child { flex: 1; display: flex; flex-direction: column; gap: 8px; padding: 16px 18px 18px !important; }
.trade-grid .category-card h3 { font-size: 1.02rem; line-height: 1.25; margin: 0; }
.trade-grid .category-card p { font-size: 0.88rem; line-height: 1.5; color: var(--text-dim); display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; }
.trade-grid .category-card .count { margin-top: auto; padding-top: 4px; }

/* Directory/homepage cards: the "Also serves …" line (2026-11-08) */
.pro-card .card-areas { margin: 6px 0 0; font-size: 0.82rem; color: var(--text-dim); }
