/* GunRanges.org — design tokens from v2/design/README.md (direction 3a)
   Plain CSS deliberately: no build step, so deploying is "upload the file". */

:root {
  --ink:        #22272A;
  --ink-2:      #3F4A47;
  --muted:      #667069;   /* never lighter than this on white — 4.5:1 */
  --rule:       #E6EAE7;
  --green:      #004D0E;
  --green-tint: #EBF2EC;
  --orange:     #FF4A00;   /* the single primary action per screen */
  /* White on #FF4A00 is 3.37:1 — AA only at large-text size, which is what
     pinned the button label to 19px. This darker tone is 4.70:1, clearing AA
     for normal text, so the label can be a sane size. Accents and rules keep
     the brighter --orange; only the filled button uses this. */
  --orange-btn: #D63A00;
  --page:       #FFFFFF;
  --shell:      #E4E4E0;

  --r-input: 10px;
  --r-card:  12px;
  --r-chip:  999px;
}

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

body {
  margin: 0;
  background: var(--shell);
  color: var(--ink);
  font-family: Figtree, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
}

/* Anchor targets (#contact on a listing, for one) would otherwise land under
   the sticky header. Applied to anything addressable rather than to the two
   ids that use it today. */
:target, [id] { scroll-margin-top: 92px; }

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

/* The v3 frame: a white content sheet on the grey page ground, with the header
   and footer breaking out to span the viewport. Square-cornered on purpose —
   rounding the body made it read as an oversized card rather than the page.
   The radius token stays for the components inside it. */
.shell { max-width: 1180px; margin: 0 auto; padding: 0 20px; }
.page {
  background: var(--page);
  box-shadow: 0 1px 3px rgba(34,39,42,.06), 0 8px 28px rgba(34,39,42,.05);
}

/* ---------------------------------------------------------------- header */
/* Sticky and translucent. Range and state pages run long — 40 listings, hours,
   reviews — and search should stay one click away the whole way down.
   backdrop-filter over a high-opacity white: at .82 the text underneath still
   reads through as motion rather than clutter, and the blur stops map tiles
   from turning the bar into noise. */
.site-head {
  /* Above Leaflet: its .leaflet-top / .leaflet-bottom control panes sit at
     z-index 1000, so at 900 the map's zoom buttons rode over the header. */
  position: sticky; top: 0; z-index: 1100;
  background: rgba(255,255,255,.82);
  /* Faint at rest so the bar is separated from the page even at the top; it
     firms up to the standard rule once content is passing underneath. */
  border-bottom: 1px solid rgba(34,39,42,.07);
  transition: border-color .2s ease, box-shadow .2s ease;
}
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .site-head { -webkit-backdrop-filter: blur(14px) saturate(150%); backdrop-filter: blur(14px) saturate(150%); }
}
/* No @supports fallback needed beyond this: without backdrop-filter the bar is
   simply a near-solid white, which is a perfectly good header. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .site-head { background: rgba(255,255,255,.97); }
}
/* Set by app.js once the page has scrolled, so the bar only grows an edge when
   there is actually content passing beneath it. */
.site-head.is-stuck { border-bottom-color: var(--rule); box-shadow: 0 1px 12px rgba(34,39,42,.06); }

.head-inner {
  max-width: 1180px; margin: 0 auto; padding: 0 34px; height: 72px;
  display: flex; align-items: center; gap: 30px;
}
.head-nav { display: flex; align-items: center; gap: 26px; flex: 1 1 auto; }
.head-nav a { font-size: 15px; font-weight: 500; color: var(--ink-2); }
.head-nav a:hover { color: var(--ink); text-decoration: none; }
.head-nav a.is-current { color: var(--green); font-weight: 600; }
.head-actions { display: flex; align-items: center; gap: 16px; flex: none; }
.head-signin { font-size: 15px; font-weight: 500; color: var(--ink-2); }

/* The standing call to action — claims are the top of the whole funnel. */
.nav-claim {
  padding: 11px 18px; border-radius: var(--r-chip);
  background: var(--green); color: #fff; font-size: 14px; font-weight: 600;
  white-space: nowrap;
}
.nav-claim:hover { background: #003A0A; text-decoration: none; }

/* The brand is an image. display:flex kills the inline-image baseline gap that
   would otherwise add a few stray pixels under the header. */
.brand { display: flex; align-items: center; flex: none; }
.brand img { display: block; height: 26px; width: auto; }

/* ---------------------------------------------------------------- footer */
/* Aligned with the content card above it: same max-width, and 20px of shell
   gutter plus the card's own 34px so the footer text lines up with the page
   text rather than the viewport edge. */
.site-foot { max-width: 1180px; margin: 0 auto; padding: 30px 54px 44px; }
.foot-inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: 24px; flex-wrap: wrap;
}
.foot-nav { display: flex; flex-wrap: wrap; gap: 22px; }
.foot-nav a { font-size: 14px; color: var(--ink-2); }
.foot-copy { font-size: 14px; color: var(--muted); }
.foot-disclosure {
  margin: 18px 0 0; max-width: 820px;
  font-size: 12.5px; line-height: 1.6; color: var(--muted);
}

/* ------------------------------------------------------------------ page */
.page { padding: 40px 34px 40px; }

.crumb { font-size: 13px; color: var(--muted); margin-bottom: 18px; }
.crumb a { color: var(--muted); }

/* Type scale from the v3 design. h1 52/800/-.03em, section heads 32/600.
   The old 44/22 pair is what direction 3a shipped with; v3 raises both. */
h1 { font-size: 52px; line-height: 1.04; letter-spacing: -.03em; font-weight: 800; margin: 0 0 14px; }
h2 { font-size: 32px; line-height: 1.15; letter-spacing: -.025em; font-weight: 600; margin: 48px 0 8px; }
h3 { font-size: 21px; line-height: 1.3; font-weight: 600; }
.lede { font-size: 18px; line-height: 1.6; color: #55605C; max-width: 620px; margin: 0 0 8px; }

.kicker {
  font-size: 13px; font-weight: 500; letter-spacing: .04em;
  color: var(--green); margin-bottom: 14px;
}

/* ----------------------------------------------------------- stat strip */
.stats { display: flex; flex-wrap: wrap; border: 1px solid var(--rule); border-radius: var(--r-card); overflow: hidden; margin: 28px 0; }
.stats > div { flex: 1 1 160px; padding: 16px 20px; border-right: 1px solid var(--rule); }
.stats > div:last-child { border-right: 0; }
.stats b { display: block; font-size: 30px; font-weight: 600; color: var(--green); letter-spacing: -.025em; }
.stats span { font-size: 13px; font-weight: 500; color: var(--muted); }

/* --------------------------------------------------------------- listing */
.listing { border-top: 1px solid var(--rule); }
.listing-row {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 20px; padding: 16px 0; border-bottom: 1px solid var(--rule);
}
.listing-name { font-size: 17px; font-weight: 650; margin-bottom: 4px; }
.listing-name a { color: var(--ink); }
.listing-meta { font-size: 13.5px; color: var(--muted); line-height: 1.5; }

/* Small caps label, reused for tags and categories. */
.chip {
  display: inline-block; font-size: 11px; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--green); background: var(--green-tint);
  padding: 3px 9px; border-radius: var(--r-chip); margin: 6px 5px 0 0;
}

/* ---------------------------------------------------------------- detail */
.detail-top { display: flex; gap: 32px; flex-wrap: wrap; align-items: flex-start; }
.detail-main { flex: 1 1 460px; }
.detail-side { flex: 0 0 300px; background: #FAFBFA; border: 1px solid var(--rule); border-radius: var(--r-card); padding: 22px; }
.detail-side h3 { margin: 0 0 4px; font-size: 13px; font-weight: 500; color: var(--muted); }
/* The sidebar's other actions are <a class="btn">, and a block-level anchor
   fills its container; a <button> sizes to its text instead. Without this the
   Save button comes out narrower than the stack it sits in. */
.detail-side form { margin: 0; }
.detail-side .btn { width: 100%; }

.btn {
  display: block; text-align: center; padding: 12px 22px; border-radius: var(--r-input);
  font-weight: 600; font-size: 16px; text-decoration: none;
  /* .btn lands on both <a> and <button>. Without these a button keeps the
     browser's native chrome — a grey bevel in Safari, a hairline elsewhere —
     and does not inherit the page font. .btn-secondary re-adds its border
     below, so ordering matters. */
  border: 0; -webkit-appearance: none; appearance: none;
  font-family: Figtree, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  cursor: pointer;
}
.btn:hover { text-decoration: none; }
/* Buttons had no hover feedback at all — only the search button did. */
.btn-primary:hover { filter: brightness(.92); }
.btn-secondary:hover { background: var(--green-tint); border-color: #C6DDC9; }
.btn:active { transform: translateY(1px); }
.btn:focus-visible { outline: 3px solid rgba(0,77,14,.35); outline-offset: 2px; }
/* A busy button is disabled; hover feedback there would imply it is clickable. */
.btn[data-busy]:hover { filter: none; transform: none; }
/* --orange-btn, not --orange: white on it is 4.70:1, so the 16px label above
   clears AA for normal text. Swapping this back to --orange would fail. */
.btn-primary { background: var(--orange-btn); color: #FFFFFF; }
.btn-secondary { background: #FFFFFF; color: var(--ink); border: 1px solid var(--rule); font-size: 15px; font-weight: 600; padding: 11px 20px; margin-top: 10px; }

.facts { display: flex; flex-wrap: wrap; border: 1px solid var(--rule); border-radius: var(--r-card); overflow: hidden; margin: 28px 0; }
.facts > div { flex: 1 1 150px; padding: 14px 18px; border-right: 1px solid var(--rule); }
.facts > div:last-child { border-right: 0; }
.facts dt { font-size: 12px; color: var(--muted); margin-bottom: 3px; }
.facts dd { margin: 0; font-size: 16px; font-weight: 600; }

.prose { font-size: 16px; line-height: 1.65; color: var(--ink-2); max-width: 660px; }

/* ------------------------------------------------------------- city grid */
.city-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 2px 26px; }
.city-grid a { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid var(--rule); font-size: 14.5px; }
.city-grid span { color: var(--muted); }

.empty { color: var(--muted); font-size: 15px; }

@media (max-width: 700px) {
  .site-head { height: auto; padding: 14px 18px; flex-wrap: wrap; }
  .page { padding: 24px 18px 48px; }
  .v3-hero { margin: 0 -18px; }
  .v3-hero:first-child { margin-top: -24px; }
  .hero-copy { padding: 32px 18px 0; }
  h1 { font-size: 32px; }
  .detail-side { flex-basis: 100%; }
}

/* ================================================================ HOMEPAGE */
/* overflow is deliberately NOT hidden here: the search box's type-ahead list
   is absolutely positioned and a clipping hero crops it. The map does its own
   corner-rounding below so the hero still looks clipped. */
.hero { display: flex; gap: 0; align-items: stretch; border: 1px solid var(--rule); border-radius: var(--r-card); margin-bottom: 8px; }
.hero-copy { flex: 1 1 460px; padding: 42px 34px; }
.hero-map { flex: 1 1 440px; min-height: 380px; overflow: hidden; border-radius: 0 var(--r-card) var(--r-card) 0; }
#map { width: 100%; height: 100%; min-height: 380px; }

.search-form { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 24px; }
.search-form input[type="text"] { flex: 1 1 240px; padding: 13px 15px; font: 400 15px Figtree, sans-serif; border: 1px solid var(--rule); border-radius: var(--r-input); outline: none; }
.search-form input[type="text"]:focus { border-color: var(--green); box-shadow: 0 0 0 3px rgba(0,77,14,.12); }
.search-form select { padding: 13px 12px; font: 400 15px Figtree, sans-serif; border: 1px solid var(--rule); border-radius: var(--r-input); background: #fff; }
/* Same tone and type scale as .btn-primary — it is the same kind of control,
   and two different oranges side by side on the homepage read as a mistake. */
.search-form button { padding: 13px 28px; font: 600 16px Figtree, sans-serif; color: #fff; background: var(--orange-btn); border: 0; border-radius: var(--r-input); cursor: pointer; }
.search-form button:hover { filter: brightness(.94); }
.search-form-top { margin: 0 0 28px; }

/* ================================================================== CARDS */
.card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px; margin-top: 24px; }
.card { display: flex; flex-direction: column; padding: 20px; border: 1px solid var(--rule); border-radius: var(--r-card); background: #fff; }
/* .card is a flex container, which blockifies its children — the category
   chip's inline-block became block and the pill stretched the full card width.
   align-self shrinks it back to its text. Same for the CTA at the bottom. */
.card > .chip { align-self: flex-start; margin: 0 0 10px; }
.card-cta { align-self: flex-start; }
.card h3 { margin: 0 0 8px; font-size: 17px; line-height: 1.3; font-weight: 650; }
.card h3 a { color: var(--green); }
.card p { margin: 0 0 16px; font-size: 14px; line-height: 1.55; color: var(--muted); flex-grow: 1; }
.card-cta a { display: inline-block; padding: 8px 18px; border: 1px solid var(--green); border-radius: 6px; color: var(--green); font-size: 14px; font-weight: 600; }
.card-cta a:hover { background: var(--green-tint); text-decoration: none; }

/* ==================================================== AMAZON PRODUCT CARD */
/* White, not grey: product photos have white baked in, so a grey card leaves
   a visible rectangle behind every image. */
.amazonCard { display: flex; gap: 20px; align-items: center; margin: 22px 0; padding: 16px; background: #fff; border: 1px solid #e3e3e3; border-radius: 8px; }
.amazonCardImg { flex: 0 0 auto; width: 130px; }
.amazonCardImg img { width: 100%; height: auto; border-radius: 5px; }
.amazonCardBody { display: flex; flex-direction: column; align-items: flex-start; gap: 12px; flex-grow: 1; }
.amazonCardName { font-weight: 600; font-size: 15pt; line-height: 1.3; color: var(--green); }
.btn-amzn { display: inline-block; padding: 8px 20px; border: 1px solid var(--green); border-radius: 6px; color: var(--green); font-size: 14px; font-weight: 600; }
.btn-amzn:hover { background: var(--green-tint); text-decoration: none; }
.amazonProduct { display: flex; justify-content: center; margin: 20px 0; }
.amazonProduct img { max-width: 260px; height: auto; border: 1px solid var(--rule); border-radius: 5px; padding: 10px; }

/* ============================================================ ARTICLE BODY */
.article-body h2 { font-size: 22px; margin: 34px 0 12px; }
.article-body h3 { font-size: 18px; margin: 26px 0 10px; font-weight: 650; }
.article-body ul, .article-body ol { padding-left: 22px; }
.article-body li { margin-bottom: 8px; }
/* The legacy grid-table markup used by the gear articles. */
.article-body .grid-table { display: grid; grid-template-columns: repeat(5, 1fr); border: 1px solid var(--green); border-radius: 6px; overflow: hidden; margin: 20px 0; font-size: 13px; }
.article-body .grid-header { background: var(--green); color: #fff; padding: 10px; font-weight: 700; text-align: center; }
.article-body .grid-cell { background: #fff; padding: 10px; text-align: center; border: .5px solid var(--rule); }
.article-body .resource-btn { display: inline-block; padding: 8px 20px; border: 1px solid var(--green); border-radius: 6px; color: var(--green); font-weight: 600; }

/* ============================================================ MISC / FOOT */
.dist { text-align: right; white-space: nowrap; }
.dist b { color: var(--green); font-size: 16px; }
.pager { margin-top: 28px; font-size: 14px; }
.pager svg { width: 16px; height: 16px; display: inline-block; vertical-align: middle; }
.pager a, .pager span { display: inline-block; padding: 6px 11px; margin-right: 4px; border: 1px solid var(--rule); border-radius: 6px; }
.pager [aria-current] { background: var(--green); color: #fff; border-color: var(--green); }


@media (max-width: 820px) {
  .hero { flex-direction: column; }
  .hero-copy { padding: 28px 20px; }
  .article-body .grid-table { grid-template-columns: repeat(2, 1fr); font-size: 12px; }
}

/* ======================================================= OWNER BENEFITS */
.step-num {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--green-tint); color: var(--green);
  font-weight: 700; font-size: 15px;
}

.plan-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px; margin-top: 24px; max-width: 760px; }
.plan { padding: 26px; border: 1px solid var(--rule); border-radius: var(--r-card); background: #fff; }
.plan-featured { border-color: var(--green); }
.plan h3 { margin: 0; font-size: 15px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; color: var(--green); }
.plan-price { margin: 6px 0 18px; font-size: 34px; font-weight: 800; letter-spacing: -.02em; }
.plan-price span { font-size: 15px; font-weight: 500; color: var(--muted); letter-spacing: 0; }
.plan-note { margin: 0 0 10px; font-size: 14px; color: var(--muted); }
.plan ul { margin: 0 0 22px; padding-left: 20px; font-size: 14.5px; line-height: 1.7; color: var(--ink-2); }

/* The CTA is a block button everywhere else; inline it when it sits in a
   paragraph rather than a sidebar. */
.btn-inline { display: inline-block; }

.faq { max-width: 700px; margin-top: 20px; }
.faq details { border-bottom: 1px solid var(--rule); padding: 14px 0; }
.faq summary { cursor: pointer; font-weight: 600; font-size: 16px; list-style: none; }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::before { content: "+"; display: inline-block; width: 18px; color: var(--green); font-weight: 700; }
.faq details[open] summary::before { content: "\2212"; }
.faq p { margin: 10px 0 2px 18px; font-size: 15px; line-height: 1.65; color: var(--ink-2); }

/* ================================================================== AUTH */
.auth-card { max-width: 420px; margin: 0 auto; }
.auth-card h1 { font-size: 30px; margin-bottom: 22px; }
.auth-card label { display: block; margin: 16px 0 6px; font-size: 14px; font-weight: 600; }
.auth-card input[type="email"],
.auth-card input[type="text"],
.auth-card input[type="password"] {
  width: 100%; padding: 12px 14px; font: 400 15px Figtree, sans-serif;
  border: 1px solid var(--rule); border-radius: var(--r-input); outline: none;
}
.auth-card input:focus { border-color: var(--green); box-shadow: 0 0 0 3px rgba(0,77,14,.12); }
.auth-card .check { display: flex; align-items: center; gap: 8px; font-weight: 400; font-size: 14.5px; margin: 18px 0; }
.auth-card .check input { width: auto; }
.auth-card .btn { width: 100%; border: 0; cursor: pointer; font-family: Figtree, sans-serif; }
.auth-alt { margin: 14px 0 0; font-size: 14.5px; color: var(--muted); text-align: center; }
.auth-alt a { color: var(--green); font-weight: 600; }

.alert { padding: 12px 14px; border-radius: var(--r-input); font-size: 14.5px; line-height: 1.5; margin-bottom: 18px; }
.alert-error { background: #FDF0EC; border: 1px solid #F3C6B8; color: #8A2C0D; }
.alert-error a { color: #8A2C0D; font-weight: 600; text-decoration: underline; }
.alert-ok { background: var(--green-tint); border: 1px solid #C6DDC9; color: var(--green); }
.field-error { color: #8A2C0D; font-size: 13.5px; margin: 6px 0 0; }

/* Auth links sit in the same nav row; the logout form must not break the flex. */
.site-head nav { align-items: center; }
.nav-logout { margin: 0; }
.nav-logout button {
  padding: 0; border: 0; background: none; cursor: pointer;
  font: 500 15px Figtree, sans-serif; color: var(--ink-2);
}
.nav-logout button:hover { text-decoration: underline; }
.field-hint { margin: 6px 0 0; font-size: 13px; color: var(--muted); }

/* ================================================== FORM SUBMIT FEEDBACK */
/* Submit buttons sat flush against the field above them. The login form got
   away with it only because the "keep me logged in" row supplied the gap. */
.auth-card form .btn { margin-top: 24px; }
/* The login form's "keep me logged in" row already supplies the gap, so the
   button must not add a second one. Needs to out-specify the rule above. */
.auth-card form .check + .btn { margin-top: 0; }

button[data-busy] { cursor: progress; opacity: .85; }
button:disabled { cursor: not-allowed; }

.spinner {
  display: inline-block; width: 14px; height: 14px; margin-right: 9px;
  vertical-align: -2px; border-radius: 50%;
  border: 2px solid currentColor; border-top-color: transparent;
  animation: spin .6s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Respect a reduced-motion preference: pulse instead of spin. */
@media (prefers-reduced-motion: reduce) {
  .spinner { animation: pulse 1.2s ease-in-out infinite; }
  @keyframes pulse { 50% { opacity: .35; } }
}

/* ============================================================== ACCOUNT */
.account-meta { display: flex; flex-wrap: wrap; border: 1px solid var(--rule); border-radius: var(--r-card); overflow: hidden; margin: 24px 0; max-width: 760px; }
.account-meta > div { flex: 1 1 160px; padding: 14px 18px; border-right: 1px solid var(--rule); }
.account-meta > div:last-child { border-right: 0; }
.account-meta dt { font-size: 12px; color: var(--muted); margin-bottom: 4px; }
.account-meta dd { margin: 0; font-size: 15px; font-weight: 600; }
.chip-warn { color: #8A2C0D; background: #FDF0EC; }

.panel-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; margin-top: 10px; }
.panel { padding: 22px; border: 1px solid var(--rule); border-radius: var(--r-card); background: #fff; }
.panel h2 { margin: 0 0 4px; font-size: 17px; }
.panel-note { margin: 0 0 6px; font-size: 13.5px; color: var(--muted); line-height: 1.5; }
.panel label { display: block; margin: 14px 0 6px; font-size: 14px; font-weight: 600; }
/* Every text-like input, listed by exclusion rather than by name — adding a
   field type should not mean remembering to extend a selector list, which is
   how the url and date inputs on the premium editors ended up unstyled. */
.panel input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="submit"]) {
  width: 100%; padding: 11px 13px; font: 400 15px Figtree, sans-serif;
  border: 1px solid var(--rule); border-radius: var(--r-input); outline: none;
  background: #fff; color: var(--ink);
}
.panel input:focus { border-color: var(--green); box-shadow: 0 0 0 3px rgba(0,77,14,.12); }
.panel .btn { margin-top: 20px; width: 100%; cursor: pointer; font-family: Figtree, sans-serif; }

/* Panels stacked down a form rather than laid out by .panel-grid. The grid
   supplies its own gap, so the spacing has to live here, not on .panel. */
.panel-stack { display: grid; gap: 18px; }

/* Adjacent panels space themselves. .panel carries no margin of its own, so
   any set of panels NOT inside a grid container used to sit flush against each
   other — it caught the amenities editor and then the admin range editor. The
   two grid containers below supply their own gap, so they opt out. */
.panel + .panel { margin-top: 18px; }
.panel-grid > .panel + .panel,
.panel-stack > .panel + .panel { margin-top: 0; }

/* A form's submit sits hard against whatever precedes it otherwise — the
   panels, the hours grid, a textarea. */
.form-actions { margin-top: 24px; }

.inline-form { margin: 0 0 26px; }
.inline-form .empty { margin: 0 0 10px; }

.btn-link { border: 0; background: none; padding: 0; cursor: pointer; font: 600 14px Figtree, sans-serif; color: #8A2C0D; }
.btn-link:hover { text-decoration: underline; }

/* Claim verification code: wide tracking so six digits are easy to check. */
.code-input {
  font: 600 22px/1 Figtree, sans-serif !important;
  letter-spacing: .34em; text-align: center;
}

/* ================================================================= HOURS */
.hours { border-collapse: collapse; margin: 8px 0 28px; font-size: 15px; min-width: 300px; }
.hours th { text-align: left; font-weight: 500; color: var(--muted); padding: 8px 28px 8px 0; border-bottom: 1px solid var(--rule); }
.hours td { padding: 8px 0; border-bottom: 1px solid var(--rule); font-weight: 600; }
.hours .is-closed { color: var(--muted); font-weight: 400; }

.claim-cta { margin-top: 36px; padding: 24px; border: 1px solid var(--rule); border-radius: var(--r-card); background: #FAFBFA; max-width: 620px; }
.claim-cta h2 { margin: 0 0 6px; font-size: 19px; }

/* ==================================================== OWNERSHIP STATUS */
.status-line { margin: 10px 0 0; }

/* A link, so it needs more affordance than the plain .chip label. */
.chip-claim {
  border: 1px solid #C6DDC9; cursor: pointer;
  margin: 0; padding: 5px 12px; font-size: 12px;
}
.chip-claim:hover { background: var(--green); color: #fff; text-decoration: none; }

.chip-verified { margin: 0; padding: 5px 12px; font-size: 12px; }
.chip-verified::before { content: "\2713"; margin-right: 6px; font-weight: 700; }

/* Sidebar reinforcement: deliberately quiet — it sits under Call and
   Directions and must not compete with them. */
.side-claim { margin: 16px 0 0; font-size: 13.5px; color: var(--muted); text-align: center; }
.side-claim a { color: var(--green); font-weight: 600; text-decoration: underline; }

/* Textareas were never styled — the only multi-line field on the site until
   the description editor arrived, so inputs had all the attention. */
/* min-height is a floor for a single-row field, not a size — anything taller
   comes from the element's own rows attribute. */
textarea {
  display: block; width: 100%; box-sizing: border-box; min-height: 76px;
  padding: 12px 14px; font: 400 15px/1.65 Figtree, sans-serif; color: var(--ink);
  border: 1px solid var(--rule); border-radius: var(--r-input);
  outline: none; resize: vertical; background: #fff;
}
textarea:focus { border-color: var(--green); box-shadow: 0 0 0 3px rgba(0,77,14,.12); }
textarea::placeholder { color: var(--muted); }

/* ============================================== OWNER LISTING EDITORS */
/* Screen-reader-only labels: the hours grid is self-evident visually, but
   seven unlabelled pairs of time inputs are not navigable without these. */
.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;
}

.hours-editor { border: 1px solid var(--rule); border-radius: var(--r-card); overflow: hidden; }
.hours-row {
  display: grid; grid-template-columns: 110px 1fr auto; align-items: center;
  gap: 14px; padding: 12px 16px; border-bottom: 1px solid var(--rule);
}
.hours-row:last-child { border-bottom: 0; }
.hours-row:nth-child(odd) { background: #FAFBFA; }
.hours-day { font-weight: 600; font-size: 15px; }
.hours-times { display: flex; align-items: center; gap: 10px; }
.hours-times input[type="time"] {
  padding: 7px 10px; border: 1px solid var(--rule); border-radius: 6px;
  font: inherit; font-size: 14px; background: #fff;
}
.hours-sep { color: var(--muted); font-size: 14px; }
.hours-closed { display: flex; align-items: center; gap: 7px; font-size: 14px; cursor: pointer; }
.hours-closed input { width: 17px; height: 17px; accent-color: var(--green); cursor: pointer; }

/* A day marked closed keeps its times, but they should read as inactive. */
.hours-row:has(.hours-closed input:checked) .hours-times { opacity: .45; }

.check-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 9px; }

/* Scoped through .check-grid deliberately: these labels sit inside .panel on
   the amenities screen, and `.panel label` (0,1,1) outranks a bare `.check-item`
   (0,1,0) — it was overriding the flex layout, the margins and the weight. */
.check-grid .check-item {
  display: flex; align-items: center; gap: 10px; margin: 0; padding: 10px 13px;
  border: 1px solid var(--rule); border-radius: 6px; cursor: pointer;
  font-size: 14.5px; font-weight: 400; line-height: 1.3;
}
.check-grid .check-item:hover { border-color: #C6DDC9; }
.check-grid .check-item input { width: 17px; height: 17px; accent-color: var(--green); cursor: pointer; flex: none; }
.check-grid .check-item:has(input:checked) { background: #F1F7F2; border-color: #C6DDC9; }

@media (max-width: 640px) {
  .hours-row { grid-template-columns: 1fr auto; row-gap: 10px; }
  .hours-day { grid-column: 1 / -1; }
  .check-grid { grid-template-columns: 1fr; }
}

/* ===================================================== OWNER PHOTO EDITOR */
.photo-upload { margin: 4px 0 30px; }
.photo-upload label { display: block; margin-bottom: 8px; font-size: 14px; font-weight: 600; }
.photo-upload input[type="file"] {
  display: block; width: 100%; box-sizing: border-box; padding: 16px;
  border: 2px dashed var(--rule); border-radius: var(--r-card);
  background: #FAFBFA; font: 400 14px Figtree, sans-serif; cursor: pointer;
}
.photo-upload input[type="file"]:hover { border-color: #C6DDC9; }

.photo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 18px; margin-top: 8px; }
.photo-item { margin: 0; border: 1px solid var(--rule); border-radius: var(--r-card); overflow: hidden; background: #fff; }
.photo-item img { display: block; width: 100%; height: 165px; object-fit: cover; background: var(--shell); }
.photo-item figcaption {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; padding: 10px 13px; border-top: 1px solid var(--rule);
}
/* Destructive, so it should not read the same as "Make primary". */
.photo-delete { color: #A3252A; }

/* ======================================================= PREMIUM TOOLS */
/* Checkbox on its own line inside a panel form. .panel label is display:block
   with margins, which is right for field labels and wrong here. */
.panel .check-inline {
  display: flex; align-items: center; gap: 9px; margin: 16px 0 0;
  font-size: 14.5px; font-weight: 400; cursor: pointer;
}
.panel .check-inline input { width: 17px; height: 17px; accent-color: var(--green); cursor: pointer; }

.panel select {
  width: 100%; padding: 11px 13px; font: 400 15px Figtree, sans-serif;
  border: 1px solid var(--rule); border-radius: var(--r-input); background: #fff;
}
.date-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }

/* Destructive action, separated from the save button above it. */
.panel-delete { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--rule); }

.plan-list { margin: 14px 0 20px; padding-left: 20px; font-size: 15px; line-height: 1.9; color: var(--ink-2); }

/* ------------------------------------------------------------- leads */

@media (max-width: 640px) {
  .date-pair { grid-template-columns: 1fr; }
  .lead-head { flex-direction: column; }
}

/* ============================================ RANGE DETAIL — PUBLIC EXTRAS */
.rating-line { display: flex; align-items: center; gap: 9px; margin: 0 0 8px; font-size: 15px; }
.stars { color: #C77A2E; letter-spacing: 1px; }
.rating-count { color: var(--muted); font-size: 14px; }

.open-badge {
  display: inline-block; font-size: 12px; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; padding: 4px 11px; border-radius: var(--r-chip);
}
.open-badge.is-open { color: var(--green); background: var(--green-tint); }
.open-badge.is-shut { color: #8A2C0D; background: #FDF0EC; }

/* -------------------------------------------------------- owner CTAs */
.owner-ctas { display: flex; flex-wrap: wrap; gap: 12px; margin: 26px 0 4px; }
.cta-primary { background: var(--orange-btn); color: #fff; }
.cta-secondary { background: var(--green); color: #fff; }
.cta-outline { background: #fff; color: var(--green); border: 1px solid var(--green); }
.cta-outline:hover { background: var(--green-tint); }

/* ------------------------------------------------------------ offers */
.promo-bar { display: grid; gap: 14px; margin: 26px 0 4px; }
.promo { display: flex; gap: 16px; padding: 18px 20px; border: 1px solid #E4D9C4; border-radius: var(--r-card); background: #FFFBF2; }
.promo-badge {
  flex: none; align-self: flex-start; padding: 7px 13px; border-radius: 6px;
  background: var(--orange-btn); color: #fff; font-size: 14px; font-weight: 700;
}
.promo-title { font-size: 17px; font-weight: 650; }
.promo-text { margin: 6px 0 0; font-size: 15px; line-height: 1.55; color: var(--ink-2); }
.promo-meta { margin: 8px 0 0; font-size: 13.5px; color: var(--muted); }
.promo-meta code { background: #fff; border: 1px solid var(--rule); border-radius: 4px; padding: 2px 7px; font-size: 13px; }
.promo-terms { margin: 8px 0 0; font-size: 12.5px; color: var(--muted); }

/* ----------------------------------------------------------- gallery */
.range-gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 14px; margin-bottom: 8px; }
.range-gallery img { width: 100%; height: 180px; object-fit: cover; border-radius: var(--r-card); border: 1px solid var(--rule); background: var(--shell); }

/* ------------------------------------------------------------ events */
.event-list { display: grid; gap: 14px; max-width: 700px; }
.event { display: flex; gap: 18px; padding: 18px 20px; border: 1px solid var(--rule); border-radius: var(--r-card); }
.event-date { flex: none; width: 54px; text-align: center; padding-top: 2px; }
.event-month { display: block; font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--orange-btn); }
.event-day { display: block; font-size: 26px; font-weight: 800; line-height: 1.1; letter-spacing: -.02em; }
.event-body h3 { margin: 0 0 4px; font-size: 17px; font-weight: 650; }
.event-meta { margin: 0; font-size: 13.5px; color: var(--muted); }
.event-text { margin: 8px 0 0; font-size: 15px; line-height: 1.55; color: var(--ink-2); }

/* ----------------------------------------------------------- reviews */
.review-list { display: grid; gap: 16px; max-width: 700px; }
.review { padding: 18px 20px; border: 1px solid var(--rule); border-radius: var(--r-card); }
.review-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; font-size: 15px; }
.review-date { color: var(--muted); font-size: 13px; }
.review-body { margin: 10px 0 0; font-size: 15px; line-height: 1.6; color: var(--ink-2); white-space: pre-line; }
.review-reply { margin: 14px 0 0; padding: 14px 16px; border-left: 3px solid var(--green); background: #FAFBFA; border-radius: 0 6px 6px 0; }
.review-reply-head { display: flex; align-items: center; gap: 10px; }
.review-reply .review-body { margin-top: 6px; }

@media (max-width: 640px) {
  .promo { flex-direction: column; gap: 10px; }
  .event { gap: 12px; }
}

/* ================================================== MAPS AND PUBLIC FORMS */
.range-map { height: 320px; border: 1px solid var(--rule); border-radius: var(--r-card); margin: 26px 0 8px; }
.state-map { height: 420px; border: 1px solid var(--rule); border-radius: var(--r-card); margin: 26px 0 8px; }
.map-note { margin: 0 0 8px; font-size: 13px; color: var(--muted); }
.map-note a { color: var(--green); font-weight: 600; }
/* Leaflet panes sit above everything by default and would cover the header. */
.leaflet-pane, .leaflet-top, .leaflet-bottom { z-index: 400; }

/* Honeypot: off-screen rather than display:none, which some bots skip. */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.review-form, .report-form { max-width: 700px; }
/* The empty-state panel spans the column rather than the form's reading width. */
.review-form:has(> .reviews-empty) { max-width: none; }
.review-form:has(> .reviews-empty) > form { max-width: 700px; }
.review-form { margin-bottom: 22px; }
.review-form > summary, .report-form > summary {
  cursor: pointer; font-size: 14.5px; font-weight: 600; color: var(--green);
  padding: 8px 0; list-style: none;
}
.review-form > summary::-webkit-details-marker, .report-form > summary::-webkit-details-marker { display: none; }
.review-form > summary::before, .report-form > summary::before {
  content: "+"; display: inline-block; width: 16px; font-weight: 700;
}
.review-form[open] > summary::before, .report-form[open] > summary::before { content: "\2013"; }
.review-form > form { margin-top: 10px; }

/* Reporting is a quiet, secondary action inside a review card. */
.report-form > summary { font-size: 13px; font-weight: 500; color: var(--muted); }
.report-form > form { margin-top: 8px; }
.report-form textarea { font-size: 14px; }
.report-form .btn { width: auto; display: inline-block; }
.dispute { margin-top: 30px; }

/* ================================================ USER MENU (header) */
.user-menu { position: relative; }
.user-menu > summary {
  cursor: pointer; list-style: none; font-size: 14.5px; font-weight: 500; color: var(--ink-2);
  display: inline-flex; align-items: center; gap: 9px;
  padding: 6px 12px 6px 6px; border: 1px solid var(--rule); border-radius: var(--r-chip);
  background: #fff;
}
.user-menu > summary:hover { border-color: #CFD6D1; }
.user-menu[open] > summary { border-color: var(--green); }
/* Initial in a filled circle. aria-hidden in the markup — it is decoration on
   top of the name, not a second reading of it. */
.avatar {
  display: flex; align-items: center; justify-content: center; flex: none;
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--green); color: #fff; font-size: 12.5px; font-weight: 700;
}
.user-menu > summary::-webkit-details-marker { display: none; }
/* Drawn from borders rather than set as a text glyph. The ▾ character renders
   at wildly different weights across fonts and was almost invisible at the size
   that kept it in proportion; two borders give a consistent chevron at any
   size. Rotates rather than swapping to ▴, so it animates. */
.user-menu > summary::after {
  content: ""; width: 7px; height: 7px; margin: -3px 1px 0 0;
  border-right: 2px solid var(--muted); border-bottom: 2px solid var(--muted);
  border-radius: 1px; transform: rotate(45deg); transition: transform .18s ease;
}
.user-menu[open] > summary::after { transform: rotate(-135deg); margin-top: 2px; }
.user-menu[open] > summary::after { transform: rotate(180deg); }
.user-menu-panel {
  position: absolute; right: 0; top: calc(100% + 10px); z-index: 500;
  min-width: 190px; padding: 6px; background: #fff;
  border: 1px solid var(--rule); border-radius: var(--r-card);
  box-shadow: 0 8px 24px rgba(34,39,42,.10);
}
.user-menu-panel a, .user-menu-panel button {
  display: block; width: 100%; text-align: left; padding: 9px 12px;
  border: 0; background: none; border-radius: 7px; cursor: pointer;
  font: 500 14.5px Figtree, sans-serif; color: var(--ink-2);
}
.user-menu-panel a:hover, .user-menu-panel button:hover { background: var(--green-tint); text-decoration: none; }
.user-menu-panel form { margin: 4px 0 0; padding-top: 4px; border-top: 1px solid var(--rule); }

/* ==================================== REVIEW PHOTOS, VOTES, REPLIES */
.review-photos { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 12px; }
.review-photos img { width: 120px; height: 90px; object-fit: cover; border-radius: 8px; border: 1px solid var(--rule); }

.vote-row { display: flex; align-items: center; gap: 10px; margin-top: 12px; }
.vote {
  border: 1px solid var(--rule); background: #fff; border-radius: var(--r-chip);
  padding: 5px 13px; font: 500 13px Figtree, sans-serif; color: var(--muted); cursor: pointer;
}
.vote:hover { border-color: #C6DDC9; color: var(--green); }
.vote.is-mine { background: var(--green-tint); border-color: #C6DDC9; color: var(--green); font-weight: 600; }
.vote-count { font-size: 13px; color: var(--muted); }

.owner-reply-link { margin: 12px 0 0; font-size: 13.5px; }
.owner-reply-link a { color: var(--green); font-weight: 600; }

.review-unanswered { border-left: 3px solid var(--orange-btn); }
.reply-form { margin-top: 14px; }
.reply-form > summary { cursor: pointer; font-size: 14px; font-weight: 600; color: var(--green); list-style: none; }
.reply-form > summary::-webkit-details-marker { display: none; }
.reply-form > form { margin-top: 10px; }
.reply-form .btn { width: auto; display: inline-block; }

/* ==================================================================== ADMIN */
.impersonation-bar {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  margin: 0 0 22px; padding: 12px 18px; border-radius: var(--r-card);
  background: #8A2C0D; color: #fff; font-size: 14.5px;
}
.impersonation-bar button {
  border: 1px solid rgba(255,255,255,.6); background: none; color: #fff;
  border-radius: 6px; padding: 6px 14px; cursor: pointer;
  font: 600 13.5px Figtree, sans-serif; flex: none;
}
.impersonation-bar button:hover { background: rgba(255,255,255,.15); }
.impersonation-bar form { margin: 0; }

.admin-head { display: flex; align-items: baseline; justify-content: space-between; gap: 20px; flex-wrap: wrap; }
.admin-nav { display: flex; gap: 18px; font-size: 14.5px; font-weight: 500; }
.admin-nav a { color: var(--muted); padding-bottom: 2px; }
.admin-nav a.is-on { color: var(--green); border-bottom: 2px solid var(--green); }

.attention { display: flex; flex-wrap: wrap; gap: 10px; margin: 4px 0 22px; }
.attention a, .attention span {
  padding: 7px 14px; border-radius: var(--r-chip); background: var(--green-tint);
  color: var(--green); font-size: 14px; font-weight: 500;
}
.attention .att-warn { background: #FDF0EC; color: #8A2C0D; }

.admin-filters { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin: 8px 0 18px; }
.admin-filters input[type="search"] {
  flex: 1 1 280px; padding: 11px 14px; font: 400 15px Figtree, sans-serif;
  border: 1px solid var(--rule); border-radius: var(--r-input); outline: none;
}
.admin-filters select {
  padding: 11px 12px; font: 400 15px Figtree, sans-serif;
  border: 1px solid var(--rule); border-radius: var(--r-input); background: #fff;
}
.admin-filters .btn { margin-top: 0; }

.admin-table { width: 100%; border-collapse: collapse; font-size: 14.5px; margin-bottom: 20px; }
.admin-table th {
  text-align: left; font-weight: 600; font-size: 12.5px; letter-spacing: .03em;
  text-transform: uppercase; color: var(--muted);
  padding: 10px 12px 10px 0; border-bottom: 1px solid var(--rule);
}
.admin-table td { padding: 12px 12px 12px 0; border-bottom: 1px solid var(--rule); vertical-align: top; }
.admin-table tr:hover td { background: #FAFBFA; }
.admin-table a { color: var(--green); font-weight: 600; }
.admin-table .muted { color: var(--muted); font-weight: 400; }
.admin-row-actions { display: flex; gap: 12px; font-size: 13.5px; }

/* --------------------------------------------------------- claim queue */
.claim-list { display: grid; gap: 14px; max-width: 860px; }
.claim { display: flex; gap: 22px; padding: 18px 20px; border: 1px solid var(--rule); border-radius: var(--r-card); }
.claim.is-disputed { border-left: 3px solid #8A2C0D; background: #FFFCFB; }
.claim-main { flex: 1 1 auto; }
.claim-main h3 { margin: 0 0 6px; font-size: 17px; font-weight: 650; }
.claim-main h3 a { color: var(--green); }
.claim-addr { margin: 0 0 8px; font-size: 14.5px; line-height: 1.5; color: var(--ink-2); }
.claim-meta { margin: 0; font-size: 13px; color: var(--muted); }
.claim-dispute { margin: 10px 0 0; font-size: 13.5px; font-weight: 600; color: #8A2C0D; }
.claim-side { flex: 0 0 190px; text-align: right; }
/* The code is read aloud and typed onto a postcard, so it is set wide. */
.claim-code {
  font: 700 22px/1 Figtree, sans-serif; letter-spacing: .22em;
  color: var(--ink); background: var(--green-tint);
  padding: 10px 12px; border-radius: 8px; text-align: center;
}
.claim-status { margin-top: 8px; font-size: 12.5px; color: var(--muted); }
.claim-actions { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; margin-top: 12px; }
.claim-actions form { margin: 0; }

@media (max-width: 700px) {
  .claim { flex-direction: column; gap: 14px; }
  .claim-side { text-align: left; }
  .claim-actions { align-items: flex-start; }
}
.dispute-quote {
  margin: 10px 0 0; padding: 10px 14px; border-left: 3px solid #C99;
  background: #FFF7F5; font-size: 14px; line-height: 1.55; color: var(--ink-2);
}
.dispute-quote cite { display: block; margin-top: 6px; font-size: 12.5px; font-style: normal; color: var(--muted); }

.admin-tabs { display: flex; flex-wrap: wrap; gap: 4px; margin: 6px 0 18px; border-bottom: 1px solid var(--rule); }
.admin-tabs a {
  padding: 9px 14px; font-size: 14.5px; font-weight: 500; color: var(--muted);
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.admin-tabs a:hover { color: var(--ink); text-decoration: none; }
.admin-tabs a.is-on { color: var(--green); border-bottom-color: var(--green); font-weight: 600; }
.tab-count { display: inline-block; margin-left: 5px; font-size: 12px; color: var(--muted); }
.admin-tabs a.is-on .tab-count { color: var(--green); }

.review-actions { display: flex; flex-wrap: wrap; gap: 16px; align-items: center; margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--rule); }
.review-actions form { margin: 0; }

.admin-table tr.is-unread td { background: #FCFDFC; font-weight: 500; }
/* Coverage bar on the analytics screen. */
.bar { display: inline-block; width: 120px; height: 8px; margin-right: 8px; border-radius: 4px; background: var(--rule); vertical-align: middle; position: relative; overflow: hidden; }
.bar::after { content: ""; position: absolute; inset: 0 auto 0 0; width: var(--pct); background: var(--green); }
.admin-more { position: relative; }
.admin-more > summary { cursor: pointer; list-style: none; font-size: 14.5px; font-weight: 500; color: var(--muted); }
.admin-more > summary::-webkit-details-marker { display: none; }
.admin-more > summary::after { content: " \25BE"; font-size: 10px; }
.admin-more .user-menu-panel { top: calc(100% + 8px); }
.panel.is-inactive { opacity: .62; }
.cli-hint { max-width: 760px; padding: 14px 16px; background: #F7F8F7; border: 1px solid var(--rule); border-radius: var(--r-card); font: 400 13px/1.7 ui-monospace, SFMono-Regular, Menlo, monospace; overflow-x: auto; }

/* ================================================= SEARCH TYPE-AHEAD */
/* The wrapper is created by app.js so the list can position against the
   input rather than the flex row it usually sits in. */
.suggest-wrap { position: relative; flex: 1 1 240px; display: flex; }
.suggest-wrap > input { flex: 1 1 auto; }
.suggest-list {
  position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 600;
  margin: 0; padding: 5px; list-style: none; background: #fff;
  border: 1px solid var(--rule); border-radius: var(--r-card);
  box-shadow: 0 10px 28px rgba(34,39,42,.12); max-height: 320px; overflow-y: auto;
}
.suggest-list a {
  display: block; padding: 9px 12px; border-radius: 7px;
  font-size: 14.5px; color: var(--ink-2);
}
.suggest-list a:hover, .suggest-list a.is-active { background: var(--green-tint); color: var(--green); text-decoration: none; }
.suggest-list a.is-city { font-weight: 600; }
.suggest-list a.is-city::after { content: " · city"; font-weight: 400; font-size: 12px; color: var(--muted); }
/* Stacked hero: the map sits below the copy, so it rounds its bottom corners. */
@media (max-width: 700px) {
  .hero-map { border-radius: 0 0 var(--r-card) var(--r-card); }
}

/* ================================================== V3 — HOMEPAGE */

/* -------------------------------------------------------------- hero */
/* The map is full bleed: square-cornered, borderless, and running to the top
   and right edges of the sheet. Measured off the mockup, where the map's right
   edge is the card's right edge and its top is the top of the hero row — so the
   hero breaks out of the sheet's padding on those two sides and the copy column
   carries the inset instead. */
.v3-hero {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr);
  gap: 40px; align-items: stretch;
  margin: 0 -34px 0 0;
  /* The homepage puts a tinted band directly beneath the hero, which draws the
     boundary on its own. Everywhere else the hero ends in white against white,
     so it needs a rule of its own — kept very faint, the same weight as the
     header's. :has() is not universal, and the fallback is a barely visible
     line above the homepage band, which is harmless. */
  border-bottom: 1px solid rgba(34,39,42,.07);
}
/* The pull-up is what makes the map flush with the top of the sheet, and it
   assumed the hero was first. A flash message above it was being overlapped by
   40px rather than pushing it down, so the rule is scoped to that case. */
.v3-hero:first-child { margin-top: -40px; }
.v3-hero:has(+ .band) { border-bottom: 0; }
/* A listing with no coordinates renders no map, and the copy was left boxed
   into the narrower of two tracks with dead space beside it. Without :has()
   support the fallback is that same dead space, i.e. no worse than before. */
.v3-hero:not(:has(.hero-map-v3)) { grid-template-columns: minmax(0, 680px); }
.hero-copy { padding: 52px 0 32px; }
/* Subpages open with a breadcrumb, which is a small line of text — the 52px
   that sits well above the homepage's 52px headline is far too much above it.
   Keyed off the crumb rather than a modifier class so it applies wherever one
   appears. */
.hero-copy:has(.crumb) { padding-top: 24px; }
.hero-copy .crumb { margin-bottom: 14px; }
.v3-hero .lede { font-size: 16.5px; line-height: 1.6; max-width: 44ch; margin: 0 0 26px; }
.hero-eyebrow { margin: 0 0 14px; font-size: 13px; font-weight: 600; color: var(--green); }

.hero-search-row { display: flex; gap: 12px; margin-bottom: 14px; }
/* The dot marker from the mockup's location field: a location input that looks
   like a location input, not a generic text box. */
.hero-field { position: relative; flex: 1 1 auto; min-width: 0; }
.hero-field-dot {
  position: absolute; left: 16px; top: 50%; transform: translateY(-50%);
  width: 7px; height: 7px; border-radius: 50%; background: var(--green);
}
.hero-field input {
  width: 100%; padding: 15px 16px 15px 32px;
  font: 400 15px Figtree, sans-serif; color: var(--ink);
  border: 1px solid var(--rule); border-radius: var(--r-input);
  background: #fff; outline: none;
}
.hero-field input:focus { border-color: var(--green); box-shadow: 0 0 0 3px rgba(0,77,14,.12); }
.hero-search select {
  flex: none; padding: 15px 14px; font: 400 15px Figtree, sans-serif;
  border: 1px solid var(--rule); border-radius: var(--r-input); background: #fff;
}

/* The one orange action per screen. 19px/700 is a hard requirement: white on
   #FF4A00 is 3.37:1, which clears AA only as large text. Shrink the padding,
   never the label. Ordinary form buttons use .btn-primary and its darker tone. */
.btn-hero {
  display: block; width: 100%; padding: 16px 24px; border: 0;
  border-radius: var(--r-input); background: var(--orange); color: #fff;
  font: 700 19px Figtree, sans-serif; cursor: pointer; text-align: center;
  -webkit-appearance: none; appearance: none;
}
.btn-hero:hover { filter: brightness(.94); text-decoration: none; }
.btn-hero:active { transform: translateY(1px); }

.hero-map-v3 { min-height: 360px; overflow: hidden; position: relative; }
/* Fills whatever the hero row works out to.
   Named by class, not by id and not by "any direct child". By id it silently
   left one page's map at zero height (each page names its container
   differently); by `> div` it also matched the open-now badge sitting in the
   same container, stretching that to 100% of the map and turning its 999px
   radius into a full-height white pill. The class says what it means.
   The shared #map rule also carries a 380px min-height for the old full-bleed
   hero, which has to be cleared here. */
.hero-map-v3 > .map-fill { height: 100%; min-height: 0; }
.hero-map-v3 .open-now-badge {
  position: absolute; top: 14px; right: 14px; z-index: 500;
  padding: 7px 13px; border-radius: var(--r-chip); background: #fff;
  border: 1px solid var(--rule); font-size: 13px; font-weight: 500; color: var(--ink-2);
  box-shadow: 0 2px 8px rgba(34,39,42,.08);
}

/* ------------------------------------------------- section headings */
/* Heading on the left, an optional "see all" on the right, sharing a baseline.
   The link is optional in every use — the row collapses to just the heading. */
.section-head { display: flex; align-items: baseline; justify-content: space-between; gap: 24px; flex-wrap: wrap; margin-top: 52px; }
.section-head h2 { margin: 0; }
.section-link { font-size: 14.5px; font-weight: 500; color: var(--green); white-space: nowrap; }
.section-sub { margin: 8px 0 0; font-size: 15px; color: var(--muted); }

/* A tinted full-bleed band inside the content card, for the beginner block. */
.band {
  margin: 52px -34px 0; padding: 40px 34px 44px;
  background: #F7F8F7; border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule);
}
.band .section-head { margin-top: 0; }
/* Straight off the bottom of the full-bleed hero. The default 52px would leave
   a strip of white under the map, which reads as the map falling short of the
   hero rather than as a gap between two sections. Its own top border goes too —
   the map edge already draws the line. */
.v3-hero + .band { margin-top: 0; border-top: 0; }

/* ------------------------------------------------------- guide cards */
.guide-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 18px; margin-top: 22px; }
.guide-card { padding: 24px; border-radius: var(--r-card); background: #fff; border: 1px solid var(--rule); }
.guide-num { margin: 0 0 12px; font-size: 13px; font-weight: 600; color: var(--muted); }
.guide-card h3 { margin: 0 0 8px; font-size: 18px; }
.guide-card p { margin: 0; font-size: 14.5px; line-height: 1.6; color: var(--ink-2); }

/* --------------------------------------------------- state name grid */
/* Five columns, as the mockup has. The floor is load-bearing: auto-fill packs
   as many columns as fit at that minimum, so it decides the count. Against a
   1072px content column (1180 max-width less the 20px shell gutter and the
   sheet's 34px padding, both sides) 180px fits exactly five — 5x180+4x28=1012,
   while six would need 1220. Raising the floor drops it to four. */
.state-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 0 28px; margin-top: 22px; }
.state-grid a { display: flex; justify-content: space-between; gap: 12px; align-items: baseline; padding: 10px 0; border-bottom: 1px solid var(--rule); font-size: 14.5px; }
.state-grid a:hover { text-decoration: none; color: var(--green); }
.state-grid span { font-size: 13px; color: var(--muted); font-variant-numeric: tabular-nums; }

/* ------------------------------------------------- manufacturer strips */
/* Three centred brand rows on white. No band tint, no boxes: this is supporting
   content and it should sit quietly under the directory, not compete with it. */
.brands { margin-top: 56px; }
.brand-row { text-align: center; padding: 30px 0; }
.brand-row + .brand-row { border-top: 1px solid var(--rule); }
.brand-row h2 { margin: 0; font-size: 19px; font-weight: 600; letter-spacing: -.01em; }

/* Not links, so no hover affordance and no pointer — see home.blade.php.
   Height-locked rather than box-fitted: these marks run from square badges to
   very wide wordmarks, and capping both dimensions rendered the wordmarks at
   half the height of the badges, which made the row look ragged. Fixing height
   and letting width run gives every logo the same optical weight, with a width
   cap so one long wordmark cannot run away with the row. */
.logo-strip {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: 16px 34px; margin: 20px 0 0; padding: 0; list-style: none;
}
.logo-cell { display: flex; align-items: center; justify-content: center; height: 30px; }
.logo-cell img {
  height: 100%; width: auto; max-width: 132px; object-fit: contain;
  filter: grayscale(1); opacity: .6;
}
.logo-fallback { font-size: 13px; font-weight: 600; color: var(--muted); white-space: nowrap; }

.brand-row-link { margin: 20px 0 0; font-size: 13.5px; color: var(--muted); }
.brand-row-link a { color: var(--green); font-weight: 600; }

/* ------------------------------------------------------- owner strip */
.owner-strip {
  display: flex; align-items: center; justify-content: space-between; gap: 36px;
  flex-wrap: wrap; margin: 56px 0 8px; padding: 34px 36px;
  border-radius: var(--r-card); background: var(--green-tint);
}
.owner-strip h2 { margin: 0 0 10px; }
.owner-strip > div:first-child > p:last-child { margin: 0; max-width: 54ch; font-size: 15.5px; line-height: 1.6; color: var(--ink-2); }
.owner-strip-eyebrow { margin: 0 0 6px; font-size: 13px; font-weight: 600; color: var(--green); }
.owner-strip-cta { text-align: center; flex: none; }
.owner-strip-cta .nav-claim { display: inline-block; padding: 14px 24px; font-size: 15px; }
.owner-strip-hint { margin: 10px 0 0; font-size: 13px; color: var(--muted); }

@media (max-width: 900px) {
  /* Stacked: the map bleeds the full width of the sheet rather than one side. */
  .v3-hero { grid-template-columns: 1fr; gap: 26px; margin: 0 -34px; }
  .v3-hero:first-child { margin-top: -40px; }
  .hero-copy { padding: 40px 34px 0; }
  .hero-map-v3 { min-height: 300px; height: 300px; }
  h1 { font-size: 38px; }
  h2 { font-size: 26px; }
  .band { margin-left: -18px; margin-right: -18px; padding: 30px 18px 34px; }
  .owner-strip { padding: 26px 22px; }
  .owner-strip-cta { text-align: left; }
}

/* ------------------------------------------------- v3 listing cards */
/* The v3 result card. Rating, photo and tag rows are deliberately absent —
   see partials/range-card.blade.php for why. */
.range-list { display: grid; gap: 12px; margin-top: 18px; }
.range-card {
  display: flex; gap: 20px; align-items: flex-start; justify-content: space-between;
  padding: 20px 22px; border: 1px solid var(--rule); border-radius: var(--r-card);
  background: #fff;
}
.range-card:hover { border-color: #CFD6D1; }
.range-card-main { min-width: 0; }
.range-card-name { margin: 0 0 6px; font-size: 18px; font-weight: 600; letter-spacing: -.01em; }
.range-card-name a { color: var(--ink); }
.range-card-name a:hover { color: var(--green); }
.range-card-addr { margin: 0; font-size: 14px; line-height: 1.55; color: var(--muted); }
.range-card-facts { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; margin: 10px 0 0; font-size: 14px; }
.range-card-facts a { color: var(--ink-2); }
.range-card-side { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; flex: none; }
.range-card-distance { font-size: 14px; font-weight: 600; color: var(--ink-2); font-variant-numeric: tabular-nums; }

/* Open / closed. Never rendered when hours are unknown, so there is no third
   "unknown" state to style — an absent badge is the third state. */
.status { font-size: 13px; font-weight: 600; padding: 4px 10px; border-radius: var(--r-chip); }
.status.is-open { background: var(--green-tint); color: var(--green); }
.status.is-closed { background: #F1F2F1; color: var(--muted); }

@media (max-width: 600px) {
  .range-card { flex-direction: column; gap: 12px; }
  .range-card-side { flex-direction: row; align-items: center; }
}

/* --------------------------------------------- v3 range detail page */
/* The global h1 is the 52px homepage hero size. A range name sits in a 460px
   column and often runs to five or six words, so the detail page steps it
   down — the v3 detail mockup uses a smaller display size here too. */
.detail-main h1 { font-size: 36px; line-height: 1.12; letter-spacing: -.025em; }
.detail-main .lede { font-size: 16px; margin-bottom: 14px; }

/* Sticky action rail. Range pages are long once hours, description, events and
   reviews are all present; the call and directions buttons should not scroll
   away. `align-self` is needed because .detail-top stretches its children. */
@media (min-width: 901px) {
  /* 72px of sticky header plus a 20px gap, or the rail slides under it. */
  .detail-side { position: sticky; top: 92px; align-self: flex-start; }
}

/* Status and claim pills sit on one line rather than stacking into three
   near-empty paragraphs; any of them may be absent. */
.detail-main .status-line { display: inline-flex; margin: 0 8px 10px 0; }

/* Directions on a result card is an action, not a label. The shared .chip is a
   11px uppercase tag, which reads as metadata and is a small tap target, so the
   card overrides it into a bordered secondary button. */
.range-card-side .chip {
  margin: 0; padding: 8px 14px; font-size: 13.5px; font-weight: 500;
  letter-spacing: 0; text-transform: none;
  color: var(--ink-2); background: #fff; border: 1px solid var(--rule);
}
.range-card-side .chip:hover { border-color: var(--green); color: var(--green); text-decoration: none; }

/* ------------------------------------------------------- mobile nav */
/* The nav is a flex row of six items; at 375px "Find a range" was breaking
   across three lines. Rather than a hamburger — which would need JavaScript,
   or a <details> that pushes the whole page down — the row scrolls sideways.
   Every link stays reachable, nothing wraps, and it needs no script.

   -webkit-overflow-scrolling and the negative margins let it bleed to the
   screen edges so a partially visible link signals that there is more. */
/* -------------------------------------------------------- mobile header */
/* The nav is a row of six or seven items; at 375px "Find a range" was breaking
   across three lines. Rather than a hamburger — which needs JavaScript, or a
   <details> that shoves the page down — the link row scrolls sideways. Every
   link stays reachable, nothing wraps, no script involved. The negative margin
   bleeds it to the screen edges so a half-visible link signals there is more. */
@media (max-width: 860px) {
  .head-inner { flex-wrap: wrap; height: auto; padding: 12px 18px; gap: 10px 16px; }
  .brand { order: 1; }
  .head-actions { order: 2; margin-left: auto; gap: 12px; }
  .head-nav {
    order: 3; flex-basis: 100%; gap: 20px;
    overflow-x: auto; scrollbar-width: none;
    margin: 0 -18px; padding: 2px 18px 4px;
  }
  .head-nav::-webkit-scrollbar { display: none; }
  .head-nav > a { flex: none; white-space: nowrap; }
  .brand img { height: 22px; }
  .nav-claim { padding: 9px 14px; font-size: 13.5px; }
  /* Avatar and caret carry the control once space is tight. */
  .user-menu-label { display: none; }
  .user-menu > summary { padding: 5px 10px 5px 5px; }
  .site-foot { padding: 24px 20px 36px; }
}

/* Signed-in screens keep the pre-v3 working scale — see layouts/app.blade.php.
   The admin layout is separate and already sets its own, so it is unaffected. */
.page.is-app h1 { font-size: 32px; line-height: 1.15; }
.page.is-app h2 { font-size: 21px; line-height: 1.25; letter-spacing: -.01em; margin: 34px 0 12px; }
.page.is-app h3 { font-size: 17px; }

/* ------------------------------------------------ manufacturer pages */
.maker-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 16px; margin-top: 24px; }
.maker-card { display: flex; gap: 18px; padding: 20px; border: 1px solid var(--rule); border-radius: var(--r-card); background: #fff; }
.maker-logo { display: flex; align-items: center; justify-content: center; flex: none; width: 84px; height: 84px; padding: 8px; border-radius: var(--r-input); background: #FAFBFA; }
.maker-logo img { max-width: 100%; max-height: 100%; object-fit: contain; }
.maker-body { min-width: 0; }
.maker-name { margin: 0 0 6px; font-size: 17px; font-weight: 600; letter-spacing: -.01em; }
.maker-origin { margin: 0 0 8px; font-size: 13px; color: var(--green); font-weight: 500; }
.maker-addr { margin: 0 0 8px; font-size: 14px; line-height: 1.5; color: var(--muted); }
.maker-links { display: flex; flex-wrap: wrap; gap: 6px 16px; margin: 0; font-size: 14px; }
.maker-links a { color: var(--ink-2); }

/* Signed-in identity, inside the panel rather than on the button. */
.user-menu-who {
  margin: 0; padding: 4px 14px 10px; border-bottom: 1px solid var(--rule);
  font-size: 13px; color: var(--muted); overflow-wrap: anywhere;
}

/* ================================================ SUBPAGE + SIDEBAR */
/* Every subpage on the live site carries a sidebar — the ad unit and the two
   affiliate blocks live there, so it is revenue, not decoration. Main column
   first in the source so it is what a screen reader and a crawler reach first;
   the rail is supporting content. */
/* Padding on the wrapper rather than a margin on the first heading: the main
   column's first section-head carries 52px of its own, which left the sidebar
   starting flush against the map above it while the content began lower. This
   starts both columns on the same line.

   It only applies when something sits above — a hero on the listing pages. On a
   content page the split IS the page, and this stacked on top of .page's own
   40px for 88px of dead space above the breadcrumb. Same shape of mistake as
   the hero pull-up: a rule written for "follows a hero" applied unconditionally. */
.with-side { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 44px; align-items: start; padding-top: 48px; }
.page > .with-side:first-child { padding-top: 0; }
.with-side-main { min-width: 0; }
.with-side-main > :first-child { margin-top: 0; }

/* Pages with no sidebar still want a measure. The sheet's content column is
   1072px, and prose set that wide is roughly 150 characters a line — about
   twice a comfortable measure, so the eye loses its place returning to the left
   margin. These centre the content instead of letting it fill the sheet.

   Two widths because the two pages have different jobs: .page-measure is for
   reading and forms, .page-measure-wide is for a page carrying card grids and
   a comparison table, which 760px would cramp into a single column. */
.page-measure { max-width: 760px; margin-inline: auto; }
.page-measure-wide { max-width: 960px; margin-inline: auto; }

.sidebar { display: grid; gap: 18px; }
.side-box { padding: 20px; border: 1px solid var(--rule); border-radius: var(--r-card); background: #fff; }
.side-box h3 { margin: 0 0 8px; font-size: 16px; font-weight: 600; letter-spacing: -.01em; }
.side-box p { margin: 0 0 14px; font-size: 14px; line-height: 1.55; color: var(--ink-2); }
.side-box p:last-child { margin-bottom: 0; }
.side-note { font-size: 11.5px; color: var(--muted); }

/* Disclosed, as required, and set quietly so it reads as a label rather than a
   heading. The unit itself is third-party markup of unknown width. */
.side-ad { overflow: hidden; }
.side-ad-label { display: block; margin-bottom: 6px; text-align: right; font-size: 11px; color: var(--muted); }
.side-ad img, .side-ad iframe { max-width: 100%; height: auto; }

/* The single owner card — claim, add, benefits. Green-tinted like the other
   invitations to contribute, rather than the white of the affiliate blocks. */
.side-owner { background: var(--green-tint); border-color: transparent; text-align: center; }
.side-owner .btn { width: 100%; margin-top: 0; }
.side-owner-links {
  display: flex; flex-wrap: wrap; justify-content: center; gap: 4px 18px;
  margin-top: 12px; font-size: 13.5px;
}
.side-owner-links a { color: var(--green); font-weight: 600; }

.book-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.book { text-align: center; }
.book img { width: 100%; height: auto; border-radius: 6px; border: 1px solid var(--rule); }
.book-buy { display: block; margin-top: 7px; font-size: 12.5px; font-weight: 600; color: var(--green); }

.side-links { margin: 0; padding: 0; list-style: none; font-size: 14px; }
.side-links li { padding: 7px 0; border-bottom: 1px solid var(--rule); color: var(--muted); }
.side-links li:last-child { border-bottom: 0; }
.side-links a { color: var(--ink-2); }
.side-links a:hover { color: var(--green); }

/* Below the split the rail follows the content rather than sitting beside it. */
@media (max-width: 980px) {
  .with-side { grid-template-columns: 1fr; gap: 40px; }
  .sidebar { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); align-items: start; }
}

/* The rail is far shorter than a 40-listing main column, so it follows rather
   than leaving a screen of white. 92px clears the sticky header. */
@media (min-width: 981px) {
  .sidebar { position: sticky; top: 92px; }
}

/* Two-up listing cards, for the narrower main column beside a sidebar. At this
   width the card cannot hold its action rail alongside the address, so it
   stacks and the rail runs horizontally underneath. */
.range-list.is-cols { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); }
.range-list.is-cols .range-card { flex-direction: column; gap: 14px; }
.range-list.is-cols .range-card-side { flex-direction: row; align-items: center; gap: 14px; }

/* ---------------------------------------------------------- search modal */
.search-modal {
  width: min(560px, calc(100vw - 32px)); padding: 30px 32px 32px;
  border: 1px solid var(--rule); border-radius: var(--r-card);
  background: var(--page); color: var(--ink);
  box-shadow: 0 24px 60px rgba(34,39,42,.22);
}
.search-modal::backdrop { background: rgba(34,39,42,.42); }
@supports (backdrop-filter: blur(1px)) {
  .search-modal::backdrop { backdrop-filter: blur(3px); }
}
.search-modal h2 { margin: 0 0 20px; font-size: 26px; }
.search-modal .hero-search-row { margin-bottom: 12px; }
.search-modal-hint { margin: 16px 0 0; font-size: 14px; color: var(--muted); }
.search-modal-hint a { color: var(--green); font-weight: 500; }
/* method="dialog" closes without script, so the button works even if the
   listener below never attaches. */
.search-modal-close-form { float: right; margin: -12px -12px 0 0; }
.search-modal-close {
  width: 34px; height: 34px; padding: 0; cursor: pointer;
  border: 0; border-radius: 50%; background: transparent;
  font-size: 24px; line-height: 1; color: var(--muted);
}
.search-modal-close:hover { background: var(--rule); color: var(--ink); }


/* Compact state facts, in place of the four-across strip. */
.hero-meta { margin: 0 0 24px; font-size: 14.5px; color: var(--muted); }
.hero-meta b { color: var(--green); font-weight: 600; font-variant-numeric: tabular-nums; }
.hero-meta span { margin: 0 5px; opacity: .5; }

/* ============================================== V3 — RANGE DETAIL */
.hero-pills { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-bottom: 12px; }
.hero-pills .chip { margin: 0; }
.hero-rating { display: inline-flex; align-items: center; gap: 6px; font-size: 13.5px; color: var(--muted); }
.hero-rating .stars { color: #C77A2E; letter-spacing: 1px; }
.hero-rating b { color: var(--ink); }

/* Title row: name takes the space, save icon holds the end. align-items:start
   so a name wrapping to two lines does not strand the icon halfway down it. */
.range-title { display: flex; align-items: flex-start; justify-content: space-between; gap: 20px; }
/* The range name is the one h1 that is arbitrary-length user data — five or six
   words is common — so it steps down from the 52px display size. */
.range-title .range-h1 { font-size: 40px; line-height: 1.1; margin: 0; }
.save-form { margin: 0; flex: none; }
.save-btn {
  display: flex; align-items: center; justify-content: center; flex: none;
  width: 44px; height: 44px; padding: 0; cursor: pointer;
  border: 1px solid var(--rule); border-radius: 50%; background: #fff;
  color: var(--muted);
}
.save-btn:hover { border-color: var(--green); color: var(--green); text-decoration: none; }
/* Saved state is carried by the filled shape as well as the colour, so it is
   never colour alone. */
.save-btn[aria-pressed="true"] { color: var(--green); border-color: var(--green); background: var(--green-tint); }

.range-address { margin: 12px 0 0; font-size: 16px; line-height: 1.55; color: var(--ink-2); }
.range-hours { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 10px 0 0; font-size: 15px; }
.range-hours a { color: var(--ink-2); text-decoration: underline; text-underline-offset: 3px; }
.range-phone { margin: 10px 0 0; font-size: 19px; font-weight: 600; }
.range-phone a { color: var(--ink); }
.range-phone a:hover { color: var(--green); }

.hero-actions { margin-top: 18px; max-width: 460px; }
.hero-actions-row { display: flex; flex-wrap: wrap; gap: 10px; }
.hero-actions-row + .hero-actions-row { margin-top: 10px; }
/* .btn carries a top margin for stacked form use; inside a flex row it just
   knocks the buttons out of line. */
/* Sized to content rather than stretched. Growing looked right with three
   buttons and absurd with one — a lone "Contact" spanning the full column. */
.hero-actions-row .btn { margin-top: 0; flex: 0 1 auto; min-width: 116px; text-align: center; }
.hero-claim { margin: 12px 0 0; font-size: 13.5px; color: var(--muted); }
.hero-claim a { color: var(--green); font-weight: 600; }

/* Green rather than orange. Orange means "search" everywhere else on the site,
   and an owner's paid .cta-primary is already orange — putting a second orange
   beside it in the same row would leave neither reading as primary. */
.btn-call { background: var(--green); color: #fff; border: 1px solid var(--green); font-size: 15px; font-weight: 600; padding: 11px 20px; }
.btn-call:hover { background: #003A0A; }

/* ---------------------------------------------------- first-hour block */
.first-hour {
  margin: 44px 0; padding: 28px 30px;
  border-radius: var(--r-card); background: #F7F8F7; border: 1px solid var(--rule);
}
.first-hour-eyebrow { margin: 0 0 6px; font-size: 13px; font-weight: 600; color: var(--green); }
.first-hour h2 { margin: 0 0 18px; font-size: 24px; }
.first-hour-steps {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 14px 30px; margin: 0; padding: 0; list-style: none;
}
.first-hour-steps li { display: flex; gap: 12px; font-size: 14.5px; line-height: 1.55; color: var(--ink-2); }
.first-hour-steps span { flex: none; font-size: 12.5px; font-weight: 700; color: var(--muted); padding-top: 2px; }
.first-hour-note { margin: 20px 0 0; font-size: 13.5px; color: var(--muted); }

/* Dismissable flash. The close button is added by app.js, so the padding is
   only reserved when one is actually present. */
.alert { position: relative; transition: opacity .35s ease; }
.alert:has(.alert-close) { padding-right: 46px; }
.alert.is-going { opacity: 0; }
.alert-close {
  position: absolute; top: 50%; right: 10px; transform: translateY(-50%);
  width: 30px; height: 30px; padding: 0; cursor: pointer;
  border: 0; border-radius: 50%; background: transparent;
  font-size: 20px; line-height: 1; color: inherit; opacity: .6;
}
.alert-close:hover { opacity: 1; background: rgba(34,39,42,.06); }

/* ------------------------------------------------- reviews empty state */
/* From the mockup: panel #F4F7F4, 14px radius, 26/28 padding, no border. */
/* Also used as a <summary>, which needs display set explicitly and its native
   marker removed, or the panel renders with a disclosure triangle beside it. */
.reviews-empty {
  display: flex; align-items: center; justify-content: space-between;
  gap: 24px; flex-wrap: wrap; cursor: pointer; list-style: none;
  margin-top: 16px; padding: 26px 28px; border-radius: 14px; background: #F4F7F4;
}
.reviews-empty::-webkit-details-marker { display: none; }
/* When the panel IS the summary, the generic `.review-form > summary` rule
   (0,1,1) outranks `.reviews-empty` (0,1,0) and was flattening the panel to
   `padding: 8px 0`. Restated at matching specificity rather than with
   !important, since the whole block needs to win, not one declaration. */
.review-form > summary.reviews-empty {
  padding: 26px 28px; font-size: inherit; font-weight: 400; color: inherit;
}
/* That rule also prefixes a "+" glyph; the panel is its own affordance. */
.review-form > summary.reviews-empty::before { content: none; }
.reviews-empty::marker { content: ""; }
.review-form[open] > .reviews-empty { margin-bottom: 4px; }
.reviews-empty h3 { margin: 0 0 4px; font-size: 18px; font-weight: 600; color: var(--ink); }
.reviews-empty p { margin: 0; font-size: 15px; color: var(--muted); }

/* Outline pill, green. Used wherever an invitation should read as an action
   without carrying the weight of a filled button. */
.btn-pill {
  display: inline-block; flex: none; padding: 13px 26px;
  border: 1px solid var(--green); border-radius: var(--r-chip);
  background: #fff; color: var(--green); font-size: 15px; font-weight: 600;
}
.btn-pill:hover { background: var(--green-tint); text-decoration: none; }

/* Sidebar guide card. */
.side-guide-link { font-size: 14px; font-weight: 600; color: var(--green); }


/* ------------------------------------------------------- article list */
.post-list { display: grid; gap: 4px; margin-top: 24px; }
.post-row { display: flex; gap: 22px; padding: 22px 0; border-bottom: 1px solid var(--rule); }
.post-row:first-child { padding-top: 8px; }
.post-body { min-width: 0; }
/* Fixed box with object-fit: the images run from 900x215 panoramas to near
   square, and letting each set its own height made the list ragged. */
.post-thumb { flex: none; width: 180px; height: 120px; border-radius: 10px; overflow: hidden; background: #F4F7F4; }
.post-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.post-row h2 { margin: 0 0 6px; font-size: 22px; line-height: 1.25; }
.post-row h2 a { color: var(--ink); }
.post-row h2 a:hover { color: var(--green); }
.post-meta { margin: 0 0 8px; font-size: 13px; color: var(--muted); }
.post-excerpt { margin: 0; font-size: 15px; line-height: 1.6; color: var(--ink-2); max-width: 68ch; }

@media (max-width: 620px) {
  .post-row { flex-direction: column; gap: 14px; }
  .post-thumb { width: 100%; height: 170px; }
}

/* Header search trigger. Icon-only, so it needs a hit area of its own rather
   than inheriting a text link's. */
.nav-search {
  display: flex; align-items: center; justify-content: center; flex: none;
  width: 34px; height: 34px; margin-left: -6px; border-radius: 50%;
  color: var(--ink-2);
}
.nav-search:hover { background: var(--rule); color: var(--ink); text-decoration: none; }

/* Claim search results. */
.claim-results { display: grid; gap: 10px; margin-top: 16px; max-width: 760px; }
.claim-result {
  display: flex; align-items: center; justify-content: space-between; gap: 20px; flex-wrap: wrap;
  padding: 16px 20px; border: 1px solid var(--rule); border-radius: var(--r-card); background: #fff;
}
.claim-result-name { font-size: 16px; font-weight: 600; }
.claim-result-meta { font-size: 14px; color: var(--muted); margin-top: 2px; }
.claim-result .btn { margin-top: 0; flex: none; }
.claim-taken { font-size: 13.5px; color: var(--muted); }
.claim-taken a { color: var(--green); font-weight: 600; }

/* A hero field with no location marker reclaims the space the dot held. */
.hero-field.is-plain input { padding-left: 16px; }

/* ------------------------------------------------- printable targets */
/* The targets page stores custom elements — <targetSurround>/<targetBox> — in
   its content HTML. Unknown elements are inline by default, so both targets
   stacked full-bleed and pushed the second one below the fold. Styling them as
   a two-up card row puts both on screen at once. */
.article-body targetSurround {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 18px; margin: 24px 0;
}
.article-body targetBox {
  display: block; padding: 20px; text-align: center;
  border: 1px solid var(--rule); border-radius: var(--r-card); background: #fff;
}
.article-body targetBox h2 { margin: 0 0 4px; font-size: 17px; font-weight: 600; }
.article-body targetBox span { display: block; margin-bottom: 14px; font-size: 13px; color: var(--muted); }
.article-body targetBox a { display: block; }
/* The source images are 500x647; capped by height so the pair stays above the
   fold, and centred since the cap makes them narrower than the card. */
.article-body targetBox img {
  max-width: 100%; max-height: 300px; width: auto; height: auto; margin: 0 auto;
  display: block; border-radius: 8px;
}
.article-body targetBox a:hover img { outline: 2px solid var(--green); outline-offset: 3px; }

/* ------------------------------------------------- owner benefits page */
.owner-find { max-width: 520px; margin-top: 22px; }

/* The three steps, as a line each rather than the card grid that used to sit
   in front of the search and the pricing. */
.step-strip {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 12px 28px; margin: 26px 0 0; padding: 0; list-style: none;
  counter-reset: step;
}
.step-strip li {
  position: relative; padding-left: 30px;
  font-size: 14.5px; line-height: 1.55; color: var(--ink-2);
  counter-increment: step;
}
.step-strip li::before {
  content: counter(step);
  position: absolute; left: 0; top: 1px;
  display: flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--green-tint); color: var(--green);
  font-size: 11.5px; font-weight: 700;
}
.step-strip b { color: var(--ink); font-weight: 600; }

/* -------------------------------------------------------- modal tabs */
/* Radio-driven, so they work with scripting off. The inputs stay in the flow
   but invisible — not display:none, which would drop them from the tab order
   and lose keyboard operation. */
.search-tab-input { position: absolute; opacity: 0; width: 0; height: 0; }
.search-tablist { display: flex; gap: 4px; margin-bottom: 18px; border-bottom: 1px solid var(--rule); }
.search-tablist label {
  padding: 9px 16px; margin-bottom: -1px; cursor: pointer;
  font-size: 14.5px; font-weight: 600; color: var(--muted);
  border-bottom: 2px solid transparent;
}
.search-tablist label:hover { color: var(--ink); }
.search-pane { display: none; }
#search-tab-name:checked  ~ .search-tablist label[for="search-tab-name"],
#search-tab-place:checked ~ .search-tablist label[for="search-tab-place"] {
  color: var(--green); border-bottom-color: var(--green);
}
#search-tab-name:checked  ~ .search-pane.pane-name,
#search-tab-place:checked ~ .search-pane.pane-place { display: block; }
/* The label is the only visible part of the control, so it has to carry the
   focus ring the hidden radio would otherwise show. */
.search-tab-input:focus-visible ~ .search-tablist label[for="search-tab-name"],
.search-tab-input:focus-visible ~ .search-tablist label[for="search-tab-place"] { outline: none; }
#search-tab-name:focus-visible  ~ .search-tablist label[for="search-tab-name"],
#search-tab-place:focus-visible ~ .search-tablist label[for="search-tab-place"] {
  outline: 2px solid var(--green); outline-offset: 2px; border-radius: 4px;
}

/* A claim lodged but not yet verified. Deliberately quiet — it is a status,
   not a warning, and most readers of it are the genuine owner. */
.claim-pending {
  display: inline-block; padding: 3px 10px; margin-right: 6px;
  border-radius: var(--r-chip); background: #F1F2F1;
  font-size: 12.5px; font-weight: 600; color: var(--muted);
}

/* --------------------------------------------- signed-in area nav */
.account-nav {
  display: flex; flex-wrap: wrap; gap: 2px 4px;
  margin-bottom: 26px; border-bottom: 1px solid var(--rule);
}
.account-nav a {
  padding: 10px 16px; margin-bottom: -1px;
  font-size: 14.5px; font-weight: 600; color: var(--muted);
  border-bottom: 2px solid transparent;
}
.account-nav a:hover { color: var(--ink); text-decoration: none; }
.account-nav a.is-current { color: var(--green); border-bottom-color: var(--green); }
@media (max-width: 700px) {
  /* Scrolls rather than wraps, same as the header nav. */
  .account-nav { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; margin-inline: -18px; padding-inline: 18px; }
  .account-nav::-webkit-scrollbar { display: none; }
  .account-nav a { flex: none; white-space: nowrap; }
}

/* The search headline is user input echoed back — a long query at the 52px
   display size took three lines and buried the results under it. */
.search-h1 { font-size: 34px; line-height: 1.15; }

/* ------------------------------------------------------- admin bulk bar */
.bulk-bar {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  margin: 0 0 14px; padding: 12px 16px;
  border: 1px solid var(--rule); border-radius: var(--r-card); background: #FAFBFA;
}
.bulk-bar + .bulk-bar { margin-top: -6px; }
.bulk-bar select { padding: 8px 12px; font: 400 14px Figtree, sans-serif; border: 1px solid var(--rule); border-radius: var(--r-input); background: #fff; }
.bulk-bar .btn { margin-top: 0; }
.bulk-count { font-size: 13.5px; font-weight: 600; color: var(--muted); min-width: 132px; }
/* Set by app.js when at least one row is ticked, so the bar reads as active
   rather than as decoration. */
.bulk-bar.is-armed { border-color: var(--green); background: var(--green-tint); }
.bulk-bar.is-armed .bulk-count { color: var(--green); }

.bulk-col { width: 34px; text-align: center; }
.bulk-check { width: 17px; height: 17px; accent-color: var(--green); cursor: pointer; }
/* In the reviews list the checkbox sits in the head row rather than a cell. */
.review-head .bulk-check { margin-right: 4px; }
.bulk-all { display: inline-flex; align-items: center; gap: 7px; font-size: 13.5px; color: var(--ink-2); cursor: pointer; }
.bulk-all input { width: 16px; height: 16px; accent-color: var(--green); cursor: pointer; }

/* ------------------------------------------------- destructive panels */
/* Used only for actions that cannot be undone, so the colour stays rare enough
   to still mean something. */
.panel-danger { border-color: #E9C4B8; background: #FEF7F4; }
.panel-danger h2 { color: #8A2C0D; }
.btn-danger {
  background: #A8320F; color: #fff; border: 1px solid #A8320F;
  font-size: 15px; font-weight: 600; padding: 11px 20px;
}
.btn-danger:hover { background: #8A2C0D; }

/* Owner's contact-button switch, above the inbox it governs. */
.lead-toggle {
  display: flex; align-items: center; justify-content: space-between;
  gap: 24px; flex-wrap: wrap; max-width: 760px;
}
.lead-toggle h2 { margin: 0 0 4px; font-size: 18px; }
.lead-toggle form { margin: 0; flex: none; }
.lead-toggle .btn { margin-top: 0; }

/* ------------------------------------------------------- lead modal */
/* Rendered as <dialog open> so it lays out inline with scripting off. When JS
   is present, hide it until showModal() actually opens it — :modal only matches
   a dialog opened that way, so this needs no timing coordination with app.js.
   Without :modal support the form simply shows inline, which is the fallback. */
.has-js .lead-modal:not(:modal) { display: none; }

.lead-modal {
  width: min(560px, calc(100vw - 32px)); padding: 30px 32px 32px;
  border: 1px solid var(--rule); border-radius: var(--r-card);
  background: var(--page); color: var(--ink);
  box-shadow: 0 24px 60px rgba(34,39,42,.22);
}

.lead-modal::backdrop { background: rgba(34,39,42,.42); }
@supports (backdrop-filter: blur(1px)) {
  .lead-modal::backdrop { backdrop-filter: blur(3px); }
}
.lead-modal h2 { margin: 0 0 18px; font-size: 24px; }
.lead-modal .panel { border: 0; padding: 0; margin: 0; background: none; }

/* ------------------------------------------------------- owner leads */
/* The enquiry leads the card. Previously the visitor's name and the admin
   actions came first and the message was last in the smallest type — the one
   thing the owner opened the page to read. */
.lead-list { display: grid; gap: 14px; max-width: 760px; margin-top: 20px; }
.lead {
  padding: 22px 24px; border: 1px solid var(--rule); border-radius: var(--r-card);
  background: #fff;
}
/* Unread carries a left edge as well as the tint, so it survives being printed
   or read by someone who cannot separate the two greens. */
.lead-unread { border-left: 3px solid var(--green); background: #FCFDFC; }

.lead-top { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-bottom: 12px; }
.lead-interest { font-size: 13px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--green); }
.lead-top .chip { margin: 0; }
.lead-when { margin-left: auto; font-size: 13px; color: var(--muted); }

.lead-message {
  margin: 0 0 16px; font-size: 16px; line-height: 1.6; color: var(--ink);
  white-space: pre-line;   /* the visitor's line breaks are theirs to keep */
}
.lead-message-none { color: var(--muted); font-style: italic; font-size: 15px; }

.lead-from {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 16px;
  padding-top: 14px; border-top: 1px solid var(--rule); font-size: 14.5px;
}
.lead-name { font-weight: 600; }
.lead-from a { color: var(--ink-2); }
.lead-from a:hover { color: var(--green); }

.lead-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 18px; margin-top: 16px; }
.lead-actions form { margin: 0; }
.lead-actions .btn { margin-top: 0; margin-right: 6px; }

/* Unread count in the signed-in nav. Small, but the only thing on a listing
   screen that says an enquiry is waiting. */
.nav-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 19px; height: 19px; padding: 0 6px; margin-left: 5px;
  border-radius: var(--r-chip); background: var(--orange); color: #fff;
  font-size: 11.5px; font-weight: 700; line-height: 1;
}

/* Unread enquiries, called out at the top of the owner dashboard. */
.dash-alert {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  margin-bottom: 22px; padding: 16px 20px;
  border: 1px solid #E9C4B8; border-radius: var(--r-card); background: #FEF7F4;
  color: var(--ink);
}
.dash-alert:hover { border-color: var(--orange); text-decoration: none; }
.dash-alert-count {
  display: flex; align-items: center; justify-content: center; flex: none;
  min-width: 30px; height: 30px; padding: 0 9px; border-radius: var(--r-chip);
  background: var(--orange); color: #fff; font-size: 14px; font-weight: 700;
}
.dash-alert-go { margin-left: auto; font-size: 14px; font-weight: 600; color: var(--orange-btn); }

/* ---------------------------------------------------------- app modal */
/* Replaces the browser's alert() and confirm() in the admin bulk bars.
   Sized smaller than the lead and search modals: this is a sentence and two
   buttons, and a 560px panel around one line of text reads as a mistake. */
.app-modal {
  width: min(420px, calc(100vw - 32px)); padding: 26px 28px 24px;
  border: 1px solid var(--rule); border-radius: var(--r-card);
  background: var(--page); color: var(--ink);
  box-shadow: 0 24px 60px rgba(34,39,42,.22);
}
.app-modal::backdrop { background: rgba(34,39,42,.42); }
@supports (backdrop-filter: blur(1px)) {
  .app-modal::backdrop { backdrop-filter: blur(3px); }
}
.app-modal-text { margin: 0 0 22px; font-size: 16px; line-height: 1.5; }
/* Confirm sits right, as the primary position; cancel keeps its own weight so
   the destructive choice is never the one the hand lands on by default. */
.app-modal-actions { display: flex; gap: 10px; justify-content: flex-end; }
.app-modal-actions .btn { margin: 0; }
.app-modal-actions .btn[hidden] { display: none; }
