@charset "UTF-8";
/* ==========================================================================
   Updatesee design system
   Mobile-first: every breakpoint is min-width, so the base rules ARE the phone
   layout and wider screens progressively add columns. The previous stylesheet
   was desktop-first with max-width overrides, which is why small screens broke.
   ========================================================================== */

/* --------------------------------------------------------------- tokens -- */
:root {
  --brand-50:  #eef4ff;
  --brand-100: #dbe7ff;
  --brand-200: #bcd2ff;
  --brand-400: #5b8dff;
  /* #1769ff measured 4.42:1 on --canvas (#f7f9fc), so every brand-coloured link
     or label sitting on a canvas panel — the search controls among them — missed
     4.5:1. Darkened one notch: 4.55:1 on --canvas, 4.80:1 on --surface, and
     white-on-brand buttons improve from 4.67:1 to 4.80:1. */
  --brand:     #1667fc;
  --brand-600: #0f56db;
  --brand-700: #0d47b4;

  --green-50:  #e9f9f0;
  --green:     #10b981;
  --green-600: #059669;
  --green-700: #047857;

  --amber-50:  #fff8e6;
  --amber:     #f59e0b;
  --red-50:    #fef2f2;
  --red:       #ef4444;
  /* --red is a FILL (map pins, dots). As text it is 3.76:1 on white and only
     3.44:1 on its own --red-50 tint, so anything readable uses --red-text:
     4.50:1 on --red-50, 4.93:1 on --surface. */
  --red-text:  #cd3a3a;
  --purple:    #8b5cf6;

  --ink:     #0f172a;
  --ink-2:   #334155;
  --muted:   #64748b;
  /* --muted-2 is DECORATIVE ONLY (2.56:1 on white). Never use it for text a
     sighted user has to read — use --muted (4.76:1 on --surface, 4.51:1 on
     --canvas) instead. See WCAG 1.4.3. */
  --muted-2: #94a3b8;
  --line:    #e2e8f0;
  --line-2:  #f1f5f9;
  /* Form controls sit on --surface, which is the same white as the page, so
     their border is the ONLY thing identifying the control and must clear the
     3:1 of WCAG 1.4.11. --line (1.23:1) is fine for decorative dividers, which
     are exempt, but not for this. #909499 measures 3.05:1 on #ffffff. */
  --line-input: #909499;
  --surface: #ffffff;
  --canvas:  #f7f9fc;

  --shadow-xs: 0 1px 2px rgba(15,23,42,.06);
  --shadow-sm: 0 1px 3px rgba(15,23,42,.08), 0 1px 2px rgba(15,23,42,.04);
  --shadow:    0 4px 16px rgba(15,23,42,.08);
  --shadow-lg: 0 12px 32px rgba(15,23,42,.12);
  --shadow-xl: 0 24px 60px -12px rgba(15,23,42,.22), 0 8px 20px -8px rgba(15,23,42,.12);
  --ring:      0 0 0 3px rgba(23,105,255,.18);

  /* brand-tinted button elevation — a blue button casts a blue shadow */
  --shadow-brand:    0 1px 2px rgba(13,71,180,.28), 0 4px 12px -2px rgba(23,105,255,.36);
  --shadow-brand-lg: 0 2px 4px rgba(13,71,180,.24), 0 10px 22px -4px rgba(23,105,255,.44);

  --ease: cubic-bezier(.4, 0, .2, 1);
  --ease-out: cubic-bezier(.16, 1, .3, 1);

  --r-sm: 8px; --r: 12px; --r-lg: 16px; --r-xl: 22px; --r-full: 999px;
  --r-btn: 11px;

  /* fluid type — scales smoothly, no breakpoint jumps */
  --fs-xs:  clamp(.72rem, .70rem + .10vw, .78rem);
  --fs-sm:  clamp(.82rem, .79rem + .14vw, .90rem);
  --fs-md:  clamp(.92rem, .89rem + .16vw, 1.00rem);
  --fs-lg:  clamp(1.05rem, 1.00rem + .25vw, 1.20rem);
  --fs-xl:  clamp(1.25rem, 1.13rem + .55vw, 1.60rem);
  --fs-2xl: clamp(1.55rem, 1.30rem + 1.10vw, 2.30rem);
  --fs-3xl: clamp(2.00rem, 1.55rem + 2.00vw, 3.30rem);

  --sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px;  --sp-4: 16px;
  --sp-5: 20px; --sp-6: 24px; --sp-8: 32px;  --sp-10: 40px;
  --sp-12: 48px; --sp-16: 64px;

  --container: 1200px;
  --gutter: clamp(16px, 4vw, 28px);
  --header-h: 64px;
}

/* ----------------------------------------------------------------- base -- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 16px);
}

body {
  font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  font-size: var(--fs-md);
  line-height: 1.6;
  color: var(--ink);
  background: var(--surface);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden; /* nothing may ever scroll the page sideways */
}

img, svg, video, canvas { display: block; max-width: 100%; }
img { height: auto; object-fit: cover; }

a { color: var(--brand); text-decoration: none; }
a:hover { color: var(--brand-600); }

button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: 0; }

h1, h2, h3, h4 { line-height: 1.2; font-weight: 700; letter-spacing: -.02em; text-wrap: balance; }
h1 { font-size: var(--fs-3xl); }
h2 { font-size: var(--fs-2xl); }
h3 { font-size: var(--fs-lg); }
h4 { font-size: var(--fs-md); }
p { text-wrap: pretty; }
ul, ol { padding: 0; list-style: none; }

:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; border-radius: 4px; }
::selection { background: var(--brand-100); color: var(--brand-700); }

/* long words / URLs must never blow out a card on a narrow screen */
h1, h2, h3, h4, p, td, th, li, a, span, strong { overflow-wrap: break-word; }

svg { stroke: currentColor; fill: none; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }

/* ------------------------------------------------------------ a11y ------- */
.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip-link {
  position: absolute; left: 12px; top: -60px; z-index: 200;
  padding: 10px 16px; background: var(--brand); color: #fff;
  border-radius: var(--r-sm); transition: top .2s;
}
.skip-link:focus { top: 12px; color: #fff; }@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}


/* ---------------------------------------------------------- layout ------- */
.site-container {
  width: 100%; max-width: var(--container);
  margin-inline: auto; padding-inline: var(--gutter);
}

.section-block { padding-block: var(--sp-10); }
.section-block.compact { padding-block: var(--sp-8); }
.section-block.tint, .section-tint { background: var(--canvas); }

.section-head, .section-heading-inline {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--sp-4); flex-wrap: wrap; margin-bottom: var(--sp-5);
}
.section-head h2, .section-head h3 { margin: 0; }
.section-head > a, .section-heading-inline > a { font-size: var(--fs-sm); font-weight: 600; white-space: nowrap; }
.section-title { margin-bottom: var(--sp-6); }
.center-title { text-align: center; }

/* Auto-fit grids reflow at ANY width without a media query — this is what
   stops cards squashing on tablets and in-between viewports. */
.featured-grid, .listing-grid, .similar-grid, .collection-grid, .article-grid,
.deal-grid, .testimonial-grid, .neighborhood-grid, .menu-grid, .steps-grid,
.plan-grid, .info-grid, .metric-grid, .result-cards, .grid {
  display: grid; gap: var(--sp-4);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr));
}
.steps-grid   { grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr)); }
.metric-grid  { grid-template-columns: repeat(auto-fit, minmax(min(100%, 150px), 1fr)); gap: var(--sp-3); }
.similar-grid { grid-template-columns: repeat(auto-fill, minmax(min(100%, 200px), 1fr)); }
.info-grid    { grid-template-columns: repeat(auto-fill, minmax(min(100%, 250px), 1fr)); gap: var(--sp-5); }
.plan-grid    { grid-template-columns: repeat(auto-fit, minmax(min(100%, 275px), 1fr)); }

/* ---------------------------------------------------------- buttons ------ */
.button, .btn {
  position: relative; isolation: isolate;
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  padding: 11px 18px; border-radius: var(--r-btn);
  font-size: var(--fs-sm); font-weight: 650; letter-spacing: -.01em; line-height: 1;
  border: 1px solid transparent; white-space: nowrap; min-height: 42px;
  transition: background .18s var(--ease), color .18s var(--ease), border-color .18s var(--ease),
              box-shadow .18s var(--ease), transform .14s var(--ease);
}
.button:active, .btn:active { transform: translateY(1px) scale(.99); }
.button svg, .btn svg { width: 17px; height: 17px; flex: none; }
.button:focus-visible, .btn:focus-visible { outline: none; box-shadow: var(--ring); }

/* Gradient + layered brand-tinted shadow reads as a real raised control rather
   than a flat blue rectangle. The ::after sheen lifts the top edge on hover. */
.button-primary {
  background: linear-gradient(180deg, var(--brand-400) -40%, var(--brand) 45%, var(--brand-600) 100%);
  color: #fff; box-shadow: var(--shadow-brand);
}
.button-primary::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit; z-index: -1;
  background: linear-gradient(180deg, rgba(255,255,255,.28), rgba(255,255,255,0) 55%);
  opacity: .85; transition: opacity .18s var(--ease);
}
.button-primary:hover {
  background: linear-gradient(180deg, var(--brand) -30%, var(--brand-600) 55%, var(--brand-700) 100%);
  color: #fff; transform: translateY(-1px); box-shadow: var(--shadow-brand-lg);
}
.button-primary:hover::after { opacity: 1; }
.button-primary:active { box-shadow: var(--shadow-brand); }

.button-light {
  background: var(--surface); color: var(--ink-2);
  border-color: var(--line); box-shadow: var(--shadow-xs);
}
.button-light:hover {
  background: var(--surface); border-color: var(--brand-200); color: var(--brand-700);
  transform: translateY(-1px); box-shadow: var(--shadow-sm);
}
.button-soft { background: var(--brand-50); color: var(--brand-700); border-color: transparent; }
.button-soft:hover { background: var(--brand-100); color: var(--brand-700); transform: translateY(-1px); }
.button-ghost { background: transparent; color: var(--ink-2); }
.button-ghost:hover { background: var(--line-2); color: var(--ink); }
.button-pill { border-radius: var(--r-full); }
.button-success { background: var(--green); color: #fff; }
.button-success:hover { background: var(--green-600); color: #fff; }
.button-danger { background: var(--red); color: #fff; }
.button-danger:hover { filter: brightness(.93); color: #fff; }
.button-white { background: #fff; color: var(--brand); }
.button-white:hover { background: var(--brand-50); color: var(--brand-700); }
.button-outline-white { background: transparent; color: #fff; border-color: rgba(255,255,255,.6); }
.button-outline-white:hover { background: rgba(255,255,255,.14); color: #fff; }
.button-block { width: 100%; }
.button-sm { padding: 7px 12px; min-height: 34px; font-size: var(--fs-xs); }
.button[disabled], .btn[disabled] { opacity: .55; pointer-events: none; }
.button-row { display: flex; flex-wrap: wrap; gap: var(--sp-3); }

/* ------------------------------------------------------------ forms ------ */
input[type=text], input[type=email], input[type=password], input[type=tel],
input[type=url], input[type=number], input[type=search], input[type=date],
input[type=time], select, textarea {
  width: 100%; padding: 11px 13px; min-height: 44px;
  font-size: var(--fs-sm); color: var(--ink); background: var(--surface);
  border: 1px solid var(--line-input); border-radius: var(--r-sm);
  transition: border-color .15s, box-shadow .15s;
}
/* 16px on phones stops iOS Safari zooming the page on focus */
@media (max-width: 767px) { input, select, textarea { font-size: 16px; } }

input:focus, select:focus, textarea:focus { outline: none; border-color: var(--brand); box-shadow: var(--ring); }
/* Placeholders here carry real hints ("e.g. biryani, dentist, gym"), so they are
   content, not chrome. --muted-2 measured 2.56:1; --muted is 4.76:1 on --surface
   and 4.51:1 on --canvas, which is the background the hero/wide search controls
   use — the mid-tone #6c7686 would have passed on white but only reached 4.35:1
   on --canvas, so --muted is the one that holds everywhere these appear. */
input::placeholder, textarea::placeholder { color: var(--muted); }
textarea { min-height: 110px; resize: vertical; line-height: 1.55; }
select {
  appearance: none; padding-right: 34px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 10px center; background-size: 16px;
}

.form-grid { display: grid; gap: var(--sp-4); grid-template-columns: repeat(auto-fit, minmax(min(100%, 230px), 1fr)); }
.form-grid .full, .form-grid fieldset { grid-column: 1 / -1; }
.form-grid label, .field {
  display: flex; flex-direction: column; gap: 6px;
  font-size: var(--fs-sm); font-weight: 600; color: var(--ink-2);
}
.form-grid label small, .field small { font-weight: 400; color: var(--muted); font-size: var(--fs-xs); }
label.checkbox {
  flex-direction: row; align-items: flex-start; gap: var(--sp-2);
  font-weight: 400; color: var(--ink-2);
}
label.checkbox input { width: 18px; height: 18px; min-height: 0; margin-top: 2px; flex: none; accent-color: var(--brand); }
fieldset { border: 1px solid var(--line); border-radius: var(--r-sm); padding: var(--sp-4); }
legend { font-size: var(--fs-sm); font-weight: 600; padding-inline: 6px; }

.form-tip { padding: 12px 14px; border-radius: var(--r-sm); font-size: var(--fs-sm); background: var(--brand-50); color: var(--brand-700); border: 1px solid var(--brand-100); }
.form-tip.success { background: var(--green-50); color: var(--green-700); border-color: #bbf7d0; }
.form-errors { padding: 12px 14px; border-radius: var(--r-sm); font-size: var(--fs-sm); background: var(--red-50); color: #b91c1c; border: 1px solid #fecaca; }
.form-errors ul { margin-top: 6px; padding-left: 18px; list-style: disc; }

.alert { padding: 12px 14px; border-radius: var(--r-sm); font-size: var(--fs-sm); border: 1px solid; }
.alert-success { background: var(--green-50); color: var(--green-700); border-color: #bbf7d0; }
.alert-error   { background: var(--red-50);   color: #b91c1c;          border-color: #fecaca; }
.alert-info    { background: var(--brand-50); color: var(--brand-700); border-color: var(--brand-100); }
/* Amber, not red: an unconfirmed address is an unfinished step, not an error the
   user made. Red here would read as "something is broken with your account". */
.alert-warn    { background: #fffbeb; color: #92400e; border-color: #fde68a; }
.alert-warn a  { color: inherit; text-decoration: underline; font-weight: 600; }

/* Replaces style="padding-top:16px" in includes/header.php. Inline styles are
   what keep the Content-Security-Policy in Report-Only, so they are being
   retired site by site rather than left as a permanent blocker. */
.site-alerts   { padding-top: 16px; }
.site-alerts + .site-alerts { padding-top: 8px; }

/* -------------------------------------------------- chips / badges ------- */
.chip-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.chip-row a, .chip-row span, .chip-row button {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 8px 13px; border-radius: var(--r-full);
  font-size: var(--fs-sm); font-weight: 500; white-space: nowrap;
  background: var(--surface); color: var(--ink-2); border: 1px solid var(--line);
  transition: background .15s, border-color .15s, color .15s;
}
.chip-row a:hover, .chip-row button:hover { background: var(--brand-50); border-color: var(--brand-200); color: var(--brand-700); }
.chip-row a.active, .chip-row button.active { background: var(--brand); border-color: var(--brand); color: #fff; }

.tag-row { display: flex; flex-wrap: wrap; gap: 6px; }
/* --muted on --line-2 is 4.34:1 — just under. #627188 is 4.52:1 on that tint. */
.tag-row span { padding: 4px 9px; border-radius: var(--r-sm); font-size: var(--fs-xs); background: var(--line-2); color: #627188; white-space: nowrap; }

.badge { display: inline-flex; align-items: center; gap: 5px; padding: 4px 10px; border-radius: var(--r-full); font-size: var(--fs-xs); font-weight: 600; white-space: nowrap; }
.badge-green { background: var(--green-50); color: var(--green-700); }
.badge-amber { background: var(--amber-50); color: #b45309; }
.badge-red   { background: var(--red-50);   color: #b91c1c; }
.badge-blue  { background: var(--brand-50); color: var(--brand-700); }
.badge-grey  { background: var(--line-2);   color: var(--muted); }

.status, .status-badge, .open-tag {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 10px; border-radius: var(--r-full);
  font-size: var(--fs-xs); font-weight: 600; white-space: nowrap;
  background: var(--line-2); color: var(--muted);
}
.status.is-open, .status-badge.open, .open-tag { background: var(--green-50); color: var(--green-700); }
.status.is-soon, .status-badge.soon { background: var(--amber-50); color: #b45309; }
.status.is-closed, .status-badge.closed { background: var(--red-50); color: #b91c1c; }

.verified {
  display: inline-flex; align-items: center; gap: 4px; vertical-align: middle;
  padding: 4px 10px; border-radius: var(--r-full);
  font-size: var(--fs-xs); font-weight: 600;
  background: var(--brand-50); color: var(--brand-700);
}

.rating, .rating-line { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; font-size: var(--fs-sm); color: var(--ink-2); }
.rating small, .rating-line small, .rating-line span:not(.stars) { color: var(--muted); font-size: var(--fs-xs); }
.rating > span, .stars { display: inline-flex; gap: 1px; letter-spacing: .5px; }
.rating i, .stars i { font-style: normal; color: #d7dee8; font-size: .95em; }
.rating i.is-on, .stars i.is-on { color: var(--amber); }
.rating.big { font-size: var(--fs-md); }
.rating.big i { font-size: 1.1em; }

/* ----------------------------------------------------------- header ------ */
/* Mobile-first: the bar is brand + search + burger. The nav is an off-canvas
   drawer until 1024px, where it becomes an inline rail with hover mega-menus. */
/* The glass lives on ::before, NOT on .site-header itself. backdrop-filter
   establishes a containing block for fixed-position descendants, which would
   trap the off-canvas .primary-nav inside the 64px-tall bar instead of letting
   it fill the viewport. Pushing the filter into a pseudo-element keeps the
   frosted look while leaving the header transparent to `position: fixed`. */
.site-header {
  position: sticky; top: 0; z-index: 100;
  border-bottom: 1px solid transparent;
  box-shadow: 0 1px 0 rgba(15,23,42,.05);
  transition: box-shadow .25s var(--ease), border-color .25s var(--ease);
}
.site-header::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: rgba(255,255,255,.82);
  backdrop-filter: saturate(1.8) blur(16px);
  -webkit-backdrop-filter: saturate(1.8) blur(16px);
  transition: background .25s var(--ease);
}
/* JS adds .is-scrolled past 8px so the bar only earns its shadow once content
   is actually sliding underneath it. */
.site-header.is-scrolled {
  border-bottom-color: var(--line);
  box-shadow: 0 4px 20px -6px rgba(15,23,42,.14);
}
.site-header.is-scrolled::before { background: rgba(255,255,255,.94); }
.header-inner { display: flex; align-items: center; gap: var(--sp-3); height: var(--header-h); }

.brand {
  display: inline-flex; align-items: center; gap: 10px; margin-right: auto;
  font-size: var(--fs-lg); font-weight: 800; color: var(--ink); letter-spacing: -.03em;
}
.brand:hover { color: var(--ink); }
.brand-pin {
  position: relative; display: grid; place-items: center;
  width: 36px; height: 36px; border-radius: 11px; flex: none; color: #fff;
  background: linear-gradient(145deg, var(--brand-400), var(--brand) 45%, var(--brand-700));
  box-shadow: var(--shadow-brand), inset 0 1px 0 rgba(255,255,255,.4);
  transition: transform .3s var(--ease-out), box-shadow .3s var(--ease);
}
.brand:hover .brand-pin { transform: translateY(-2px) rotate(-6deg); box-shadow: var(--shadow-brand-lg), inset 0 1px 0 rgba(255,255,255,.4); }
.brand-pin svg { width: 19px; height: 19px; stroke-width: 2.1; }
.brand-text { display: flex; flex-direction: column; line-height: 1.05; }
.brand-text strong { font-weight: 800; }
.brand-text small {
  /* "Local discovery" is a readable tagline, not chrome — --muted-2 was 2.56:1. */
  display: none; font-size: 10.5px; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--muted);
}
.brand-light, .brand-light:hover { color: #fff; }
.brand-light .brand-text small { color: rgba(255,255,255,.65); }

/* No .header-search rules: a search field in the bar starved the nav of width
   and forced the brand lockup and "For Business" to wrap. Search lives in the
   hero (index.php) and the filter bar (search.php). */

.primary-nav, .header-actions { display: none; }

/* -------- burger -------- */
.nav-toggle {
  display: grid; place-items: center; width: 42px; height: 42px; flex: none;
  border-radius: var(--r-btn); border: 1px solid var(--line);
  background: var(--surface); color: var(--ink-2); box-shadow: var(--shadow-xs);
  transition: background .18s var(--ease), border-color .18s var(--ease), box-shadow .18s var(--ease);
}
.nav-toggle:hover { border-color: var(--brand-200); box-shadow: var(--shadow-sm); }
.nav-toggle-bars { display: grid; gap: 4px; width: 18px; }
.nav-toggle-bars i {
  display: block; height: 2px; border-radius: 2px; background: currentColor;
  transition: transform .28s var(--ease-out), opacity .18s var(--ease), width .28s var(--ease-out);
}
.nav-toggle-bars i:nth-child(2) { width: 13px; margin-left: auto; }
.nav-toggle[aria-expanded="true"] { color: var(--brand-700); border-color: var(--brand-200); background: var(--brand-50); }
.nav-toggle[aria-expanded="true"] i:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] i:nth-child(2) { opacity: 0; width: 18px; }
.nav-toggle[aria-expanded="true"] i:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* -------- off-canvas drawer (mobile / tablet) -------- */
.nav-backdrop {
  position: fixed; inset: 0; z-index: 98;
  background: rgba(15,23,42,.42); backdrop-filter: blur(3px);
  opacity: 0; transition: opacity .3s var(--ease);
}
.nav-backdrop.is-visible { opacity: 1; }

.primary-nav {
  position: fixed; inset: 0 0 0 auto; z-index: 99;
  width: min(370px, 88vw);
  flex-direction: column; gap: 0;
  padding: var(--sp-4) var(--sp-5) var(--sp-8);
  background: var(--surface); box-shadow: var(--shadow-xl);
  overflow-y: auto; overscroll-behavior: contain;
  transform: translateX(102%);
  transition: transform .34s var(--ease-out);
}
.primary-nav.is-open { display: flex; transform: translateX(0); }

.nav-drawer-head {
  display: flex; align-items: center; justify-content: space-between;
  padding-bottom: var(--sp-4); margin-bottom: var(--sp-2);
  border-bottom: 1px solid var(--line);
}
.nav-drawer-head span {
  /* Drawer title ("Menu") — real text, so 4.5:1, not the decorative --muted-2. */
  font-size: var(--fs-xs); font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--muted);
}
.nav-close {
  display: grid; place-items: center; width: 34px; height: 34px;
  border-radius: 50%; background: var(--canvas); color: var(--ink-2);
  transition: background .18s var(--ease), color .18s var(--ease), transform .18s var(--ease);
}
.nav-close:hover { background: var(--red-50); color: var(--red-text); transform: rotate(90deg); }
.nav-close svg { width: 16px; height: 16px; }

.nav-list { list-style: none; padding: 0; margin: 0; display: grid; gap: 2px; }
.nav-item { position: relative; }

.nav-link {
  position: relative;
  display: flex; align-items: center; gap: 11px; width: 100%;
  padding: 12px 12px; border-radius: var(--r);
  font-size: var(--fs-md); font-weight: 600; color: var(--ink-2);
  cursor: pointer; list-style: none;
  transition: background .18s var(--ease), color .18s var(--ease);
}
.nav-link::-webkit-details-marker { display: none; }
.nav-link-icon {
  display: grid; place-items: center; width: 32px; height: 32px; flex: none;
  border-radius: 9px; background: var(--line-2); color: var(--muted);
  transition: background .18s var(--ease), color .18s var(--ease), transform .22s var(--ease-out);
}
.nav-link-icon svg { width: 17px; height: 17px; }
.nav-link:hover { background: var(--brand-50); color: var(--brand-700); }
.nav-link:hover .nav-link-icon { background: var(--brand-100); color: var(--brand); transform: scale(1.06); }
.nav-link.active { background: var(--brand-50); color: var(--brand-700); }
.nav-link.active .nav-link-icon { background: var(--brand); color: #fff; box-shadow: var(--shadow-brand); }

.nav-caret { margin-left: auto; display: grid; place-items: center; color: var(--muted-2); transition: transform .26s var(--ease-out); }
.nav-caret svg { width: 15px; height: 15px; }
.nav-details[open] > .nav-link .nav-caret { transform: rotate(180deg); }

/* Drawer: the panel is an inline accordion body, not a floating card. */
.nav-panel { padding: var(--sp-2) 0 var(--sp-3) 44px; }
.nav-panel-head { display: none; }
.nav-panel-grid { display: grid; gap: 2px; }
.nav-tile {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 10px; border-radius: var(--r-sm);
  color: var(--ink-2);
  transition: background .16s var(--ease), color .16s var(--ease), transform .16s var(--ease-out);
}
.nav-tile:hover { background: var(--line-2); color: var(--brand-700); transform: translateX(2px); }
.nav-tile-mark {
  display: grid; place-items: center; width: 30px; height: 30px; flex: none;
  border-radius: 9px; background: var(--canvas); font-size: 15px; line-height: 1;
  border: 1px solid var(--line);
}
.nav-tile-mark-pin { color: var(--brand); }
.nav-tile-mark-pin svg { width: 15px; height: 15px; }
.nav-tile-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.nav-tile-text strong { font-size: var(--fs-sm); font-weight: 650; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* "1,204 listed" / the city's state — informative text, was 2.56:1 on --muted-2. */
.nav-tile-text small { font-size: 11px; color: var(--muted); }
.nav-panel-foot {
  display: inline-flex; align-items: center; gap: 6px;
  margin-top: var(--sp-2); padding: 8px 10px; border-radius: var(--r-sm);
  font-size: var(--fs-xs); font-weight: 700; color: var(--brand);
}
.nav-panel-foot svg { width: 15px; height: 15px; transition: transform .2s var(--ease-out); }
.nav-panel-foot:hover { background: var(--brand-50); color: var(--brand-700); }
.nav-panel-foot:hover svg { transform: translateX(3px); }

.nav-cta {
  margin-top: var(--sp-5); padding-top: var(--sp-5);
  border-top: 1px solid var(--line);
  display: grid; gap: var(--sp-2);
}

/* -------- right-side actions -------- */
.icon-button {
  display: grid; place-items: center; width: 40px; height: 40px; flex: none;
  border-radius: var(--r-btn); border: 1px solid transparent;
  color: var(--muted); background: transparent;
  transition: background .18s var(--ease), color .18s var(--ease), border-color .18s var(--ease), transform .18s var(--ease-out);
}
.icon-button:hover { background: var(--brand-50); color: var(--brand); border-color: var(--brand-100); transform: translateY(-1px); }
.icon-button svg { width: 19px; height: 19px; }

.button-cta { padding-inline: 16px; }

.user-menu { position: relative; }
.user-menu-toggle {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 5px 8px 5px 5px; border-radius: var(--r-full);
  border: 1px solid var(--line); background: var(--surface);
  font-size: var(--fs-sm); font-weight: 650; color: var(--ink-2);
  box-shadow: var(--shadow-xs);
  transition: border-color .18s var(--ease), box-shadow .18s var(--ease), color .18s var(--ease);
}
.user-menu-toggle:hover { border-color: var(--brand-200); box-shadow: var(--shadow-sm); color: var(--ink); }
.user-menu-toggle[aria-expanded="true"] { border-color: var(--brand-200); background: var(--brand-50); color: var(--brand-700); }
.user-menu-toggle .nav-caret { margin-left: 0; }
.user-menu-toggle .nav-caret svg { width: 13px; height: 13px; }
.user-menu-toggle[aria-expanded="true"] .nav-caret { transform: rotate(180deg); }
.user-menu-name { max-width: 90px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.avatar-sm {
  display: grid; place-items: center; width: 30px; height: 30px; flex: none;
  border-radius: 50%; color: #fff;
  background: linear-gradient(145deg, var(--brand-400), var(--brand) 50%, var(--brand-700));
  box-shadow: inset 0 1px 0 rgba(255,255,255,.35);
  font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0;
}
.avatar-md { width: 38px; height: 38px; font-size: var(--fs-sm); }

.user-menu-panel {
  position: absolute; right: 0; top: calc(100% + 10px); z-index: 120;
  min-width: 248px; padding: 6px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--shadow-xl);
  opacity: 0; visibility: hidden; transform: translateY(-8px) scale(.97);
  transform-origin: top right;
  transition: opacity .2s var(--ease), transform .24s var(--ease-out), visibility .2s;
}
.user-menu-panel.is-open { opacity: 1; visibility: visible; transform: none; }
.user-menu-panel a, .user-menu-panel button {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  padding: 9px 11px; border-radius: var(--r-sm);
  font-size: var(--fs-sm); font-weight: 550; color: var(--ink-2);
  transition: background .15s var(--ease), color .15s var(--ease);
}
.user-menu-panel a svg, .user-menu-panel button svg { width: 16px; height: 16px; flex: none; color: var(--muted-2); transition: color .15s var(--ease); }
.user-menu-panel a:hover, .user-menu-panel button:hover { background: var(--brand-50); color: var(--brand-700); }
.user-menu-panel a:hover svg, .user-menu-panel button:hover svg { color: var(--brand); }
/* Sign-out is a <form><button> now, not a link, so a prefetch or an <img src>
   cannot end someone's session. These rules make the button sit exactly where
   the anchor did — full width, no chrome, inheriting the row styling above. */
.user-menu-panel form.menu-signout { margin: 0; display: block; }
.user-menu-panel form.menu-signout button {
  width: 100%; text-align: left; background: none; border: 0;
  font: inherit; cursor: pointer;
}
.nav-signout { margin: 0; display: block; }
.nav-signout button { width: 100%; }

.user-menu-panel a.is-danger:hover,
.user-menu-panel button.is-danger:hover { background: var(--red-50); color: var(--red-text); }
.user-menu-panel a.is-danger:hover svg { color: var(--red-text); }
.user-menu-panel hr { border: 0; border-top: 1px solid var(--line); margin: 5px 0; }
.user-menu-head {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 11px; margin-bottom: 4px;
  border-bottom: 1px solid var(--line);
}
.user-menu-id { display: flex; flex-direction: column; min-width: 0; }
.user-menu-head strong { display: block; font-size: var(--fs-sm); color: var(--ink); }
.user-menu-head span { font-size: var(--fs-xs); color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

body.nav-locked { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
  .primary-nav, .nav-backdrop, .user-menu-panel, .nav-panel,
  .brand-pin, .nav-toggle-bars i, .nav-caret { transition-duration: .01ms !important; }
}

/* ==========================================================================
   HERO — full-bleed live map
   The map is drawn with CSS gradients + inline SVG, never a raster image, so
   it stays sharp at any DPI and costs no download. Everything in .hero-map is
   decorative and aria-hidden; content sits above it in .hero-inner.
   ========================================================================== */
.hero {
  position: relative; isolation: isolate; overflow: hidden;
  padding-block: var(--sp-12) var(--sp-16);
  background:
    radial-gradient(120% 80% at 50% -10%, #dfeaff 0%, #eef4ff 38%, #f7faff 68%, #ffffff 100%);
  /* set by the parallax script; 0 until then so nothing jumps on load */
  --tilt-x: 0deg; --tilt-y: 0deg;
}

/* The camera. perspective on the wrapper + preserve-3d on the plate is what
   turns the flat map into a scene you look *across* rather than *at*. */
.hero-scene {
  position: absolute; inset: 0; z-index: -1;
  perspective: 1500px; perspective-origin: 50% 22%;
}

/* Oversized so the drift + parallax never expose an edge, then laid down and
   spun so the road grid runs to a vanishing point. */
/* The drift keyframes restate the tilt vars rather than living on a separate
   wrapper: an animation replaces `transform` wholesale, so the parallax has to
   be *inside* the keyframes or it gets overwritten every frame. */
.hero-plate {
  position: absolute; inset: -55% -35%;
  transform-style: preserve-3d;
  /* A land tone is what makes the white road grid legible — without a base fill
     the roads were white-on-white and the whole plate read as empty gradient. */
  background: linear-gradient(180deg, #dde7f8 0%, #e9f0fc 45%, #eef4fd 100%);
  transform:
    rotateX(calc(60deg + var(--tilt-x)))
    rotateZ(calc(-15deg + var(--tilt-y)))
    scale(1.15);
  animation: mapDrift 52s ease-in-out infinite alternate;
}

/* --- roads: two gradient grids, major over minor ------------------------- */
.hero-roads {
  position: absolute; inset: 0;
  background-image:
    linear-gradient(90deg, rgba(255,255,255,.95) 0 var(--w, 10px), transparent 0),
    linear-gradient(0deg,  rgba(255,255,255,.95) 0 var(--w, 10px), transparent 0);
  background-size: 190px 190px;
  opacity: .95;
}
.hero-roads::after {
  /* thin casing either side of each road, the way real map tiles render */
  content: ""; position: absolute; inset: 0;
  background-image:
    linear-gradient(90deg, rgba(148,178,232,.35) 0 1px, transparent 0),
    linear-gradient(0deg,  rgba(148,178,232,.35) 0 1px, transparent 0);
  background-size: 190px 190px;
}
.hero-roads-minor {
  --w: 4px;
  background-size: 63px 63px;
  opacity: .5;
}
.hero-roads-minor::after { background-size: 63px 63px; }

/* --- water, parks, route ------------------------------------------------- */
.hero-features { position: absolute; inset: 0; width: 100%; height: 100%; }
.hero-water { fill: #cfe2fb; stroke: none; opacity: .85; }
.hero-park  { fill: #d6f0dd; stroke: none; opacity: .9; }
.hero-route {
  fill: none; stroke: var(--brand); stroke-width: 7;
  stroke-linecap: round; stroke-linejoin: round; opacity: .55;
  stroke-dasharray: 1400; stroke-dashoffset: 1400;
  animation: routeDraw 9s ease-in-out infinite;
}

/* --- extruded city blocks ------------------------------------------------ */
/* Each block is a roof slab lifted along the plate normal by --h. The solid
   offset box-shadow lands exactly where the front wall would be once the plate
   is tilted, so one element buys a convincing extrusion with no wall geometry. */
/* The plate is deliberately oversized (inset -55% -35%) so its edges never show.
   Laying blocks/pins out across all of it would scatter most of them off-screen,
   so both layers are inset to the band that is actually in frame. */
.hero-blocks { position: absolute; inset: 24% 20%; transform-style: preserve-3d; }
.hero-block {
  position: absolute; left: var(--x); top: var(--y);
  width: var(--w); height: var(--d);
  border-radius: 3px;
  background: linear-gradient(145deg, #ffffff 0%, #f2f6fd 55%, #e4ecf9 100%);
  /* Two offset solid shadows fake the front and side faces; the tilt puts them
     exactly where real walls would fall, so one element reads as a solid box. */
  box-shadow:
    0 0 0 1px rgba(140,172,226,.6),                        /* roof edge */
    0 var(--h) 0 -1px #9bb8de,                             /* front wall */
    calc(var(--h) * .22) calc(var(--h) * .92) 0 -3px #86a5cf, /* side wall */
    0 calc(var(--h) + 14px) 30px rgba(15,23,42,.28);       /* contact shadow */
  transform: translateZ(var(--h));
  animation: blockRise 1.1s cubic-bezier(.22,1,.36,1) backwards;
  animation-delay: calc(var(--i) * 60ms);
}

/* --- pins ---------------------------------------------------------------- */
.hero-pins { position: absolute; inset: 24% 20%; transform-style: preserve-3d; }
.map-pin {
  position: absolute; left: var(--x); top: var(--y);
  width: 0; height: 0;
  transform-style: preserve-3d;
}
/* Ellipse left flat on the ground so each pin reads as genuinely airborne. */
.map-pin-shadow {
  position: absolute; left: -13px; top: -6px; width: 26px; height: 12px;
  border-radius: 50%; background: rgba(15,23,42,.26); filter: blur(3px);
  animation: pinShadow 5s ease-in-out infinite;
  animation-delay: var(--delay, 0s);
}
/* Counter-rotating by the plate's own angles billboards the pin upright so it
   faces the camera instead of lying flat on the tilted ground. */
.map-pin-body {
  position: absolute; left: -20px; top: -40px;
  width: 40px; height: 40px;
  display: grid; place-items: center;
  border-radius: 50% 50% 50% 0;
  background: linear-gradient(150deg, color-mix(in srgb, var(--tone, var(--brand)) 78%, #fff), var(--tone, var(--brand)));
  box-shadow: 0 4px 10px rgba(15,23,42,.28), inset 0 1px 0 rgba(255,255,255,.45);
  transform:
    translateZ(var(--z, 60px))
    rotateZ(calc(15deg - var(--tilt-y)))
    rotateX(calc(-60deg - var(--tilt-x)))
    rotate(-45deg);
  transform-origin: 50% 100%;
  animation: pinFloat 5s ease-in-out infinite;
  animation-delay: var(--delay, 0s);
}
.map-pin-body i { transform: rotate(45deg); font-size: 17px; font-style: normal; line-height: 1; }
.map-pin[data-tone="orange"] { --tone: #f97316; }
.map-pin[data-tone="green"]  { --tone: var(--green); }
.map-pin[data-tone="purple"] { --tone: var(--purple); }
.map-pin[data-tone="blue"]   { --tone: var(--brand); }
.map-pin[data-tone="red"]    { --tone: #ef4444; }
.map-pin[data-tone="amber"]  { --tone: var(--amber); }

/* --- "you are here" + search radius -------------------------------------- */
.hero-radar { position: absolute; left: 50%; top: 47%; width: 0; height: 0; }
.hero-radar .dot {
  position: absolute; left: -9px; top: -9px; width: 18px; height: 18px;
  border-radius: 50%; background: var(--brand);
  box-shadow: 0 0 0 5px rgba(255,255,255,.95), 0 4px 12px rgba(23,105,255,.5);
}
.hero-radar .ring {
  position: absolute; left: 0; top: 0; width: 0; height: 0;
  border-radius: 50%; border: 2px solid rgba(23,105,255,.45);
  background: rgba(23,105,255,.07);
  animation: radarPulse 4s ease-out infinite;
}
.hero-radar .ring:nth-child(2) { animation-delay: 1.33s; }
.hero-radar .ring:nth-child(3) { animation-delay: 2.66s; }

/* Softens the map so text above it always clears contrast requirements, and
   doubles as depth fog — the far (upper) end of the plate washes out, which is
   what makes the tilt read as distance rather than a skewed picture. */
.hero-veil {
  position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background:
    /* tight, strong pool behind the headline + search box only */
    radial-gradient(52% 42% at 50% 44%, rgba(255,255,255,.94) 0%, rgba(255,255,255,.7) 55%, rgba(255,255,255,0) 100%),
    /* horizon fog at the far edge, and a soft landing into the next section */
    linear-gradient(180deg, rgba(236,243,255,.92) 0%, rgba(243,248,255,.4) 18%, rgba(255,255,255,0) 42%, rgba(255,255,255,.45) 78%, rgba(255,255,255,.92) 100%);
}

/* --- content ------------------------------------------------------------- */
.hero-inner { position: relative; display: grid; justify-items: center; text-align: center; gap: var(--sp-4); }
.hero-badge {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 15px; border-radius: var(--r-full);
  background: rgba(255,255,255,.85); backdrop-filter: blur(8px);
  border: 1px solid var(--brand-100); color: var(--brand-700);
  font-size: var(--fs-xs); font-weight: 700;
  box-shadow: var(--shadow-xs);
}
.hero-badge svg { width: 14px; height: 14px; }
.hero h1 { max-width: 16ch; }
.hero h1 span { color: var(--brand); }
.hero-sub { max-width: 54ch; color: var(--ink-2); font-size: var(--fs-lg); }

.hero .search-box {
  width: 100%; max-width: 940px; margin-block: var(--sp-2) 0;
  background: rgba(255,255,255,.92);
  backdrop-filter: saturate(1.4) blur(14px);
  border: 1px solid rgba(255,255,255,.9);
  box-shadow: 0 18px 45px rgba(15,23,42,.13), 0 2px 6px rgba(15,23,42,.05);
}
.hero .search-control { background: rgba(247,249,252,.92); text-align: left; }
.search-actions { display: grid; gap: var(--sp-2); }

.hero-chips { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: var(--sp-2); }
/* --ink-2, not --muted: over the translucent veil --muted measures 4.39:1,
   just under the 4.5:1 AA floor for text this small. */
.hero-chips-label {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: var(--fs-xs); font-weight: 700; color: var(--ink-2);
}
.hero-chips-label svg { width: 14px; height: 14px; color: var(--brand); }
.hero-chips button {
  padding: 8px 14px; border-radius: var(--r-full);
  font-size: var(--fs-xs); font-weight: 600;
  background: rgba(255,255,255,.85); backdrop-filter: blur(6px);
  border: 1px solid var(--line); color: var(--ink-2);
  transition: background .15s, border-color .15s, color .15s, transform .12s;
}
.hero-chips button:hover { background: #fff; border-color: var(--brand-200); color: var(--brand-700); transform: translateY(-1px); }
.hero-chips-ai button { border-color: var(--brand-100); background: rgba(238,244,255,.9); color: var(--brand-700); }

.hero-stats {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-3); width: 100%; max-width: 680px; margin-top: var(--sp-5);
}
.hero-stats > div {
  position: relative; display: grid; justify-items: center; gap: 2px;
  padding: var(--sp-4) var(--sp-3); border-radius: var(--r-lg);
  background: linear-gradient(160deg, rgba(255,255,255,.96), rgba(255,255,255,.76));
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255,255,255,.9);
  box-shadow: 0 10px 26px -12px rgba(15,23,42,.24), inset 0 1px 0 rgba(255,255,255,.9);
  transition: transform .28s var(--ease-out), box-shadow .28s var(--ease);
}
.hero-stats > div:hover {
  transform: translateY(-4px);
  box-shadow: 0 20px 40px -16px rgba(15,23,42,.3), inset 0 1px 0 rgba(255,255,255,.9);
}
.hero-stat-icon {
  display: grid; place-items: center; width: 32px; height: 32px; margin-bottom: 2px;
  border-radius: 10px; color: var(--brand); background: var(--brand-50);
  border: 1px solid var(--brand-100);
}
.hero-stat-icon svg { width: 16px; height: 16px; }
.hero-stats dt { font-size: var(--fs-xs); color: var(--ink-2); font-weight: 600; }
.hero-stats dd { margin: 2px 0 0; font-size: var(--fs-xl); font-weight: 800; color: var(--brand); letter-spacing: -.03em; }

/* --- floating glass cards ------------------------------------------------ */
.hero-float { display: none; }
@media (min-width: 1280px) {
  .hero-float {
    position: absolute; z-index: 2;
    display: flex; align-items: center; gap: 11px;
    padding: 11px 14px; border-radius: var(--r-lg);
    background: rgba(255,255,255,.9);
    backdrop-filter: saturate(1.5) blur(14px);
    border: 1px solid rgba(255,255,255,.95);
    box-shadow: 0 18px 40px -14px rgba(15,23,42,.3), inset 0 1px 0 rgba(255,255,255,.9);
    animation: floatCard 7s ease-in-out infinite;
  }
  /* Kept clear of the centre column: the search box runs to 940px wide and the
     stats grid to 680px, so these sit outside both bands vertically and
     horizontally rather than landing on the Search button. */
  .hero-float-left  { left: max(20px, calc(50% - 665px)); top: 25%; }
  .hero-float-right { right: max(20px, calc(50% - 665px)); top: 63%; animation-delay: 2.5s; }
  .hero-float-emoji {
    display: grid; place-items: center; width: 38px; height: 38px; flex: none;
    border-radius: 11px; background: var(--canvas); border: 1px solid var(--line); font-size: 18px;
  }
  .hero-float-ring {
    display: grid; place-items: center; width: 38px; height: 38px; flex: none;
    border-radius: 50%; color: #fff;
    background: linear-gradient(145deg, var(--brand-400), var(--brand) 55%, var(--brand-700));
    box-shadow: var(--shadow-brand);
  }
  .hero-float-ring svg { width: 18px; height: 18px; }
  .hero-float-body { display: flex; flex-direction: column; gap: 2px; text-align: left; }
  .hero-float-body strong { font-size: var(--fs-sm); font-weight: 700; color: var(--ink); }
  .hero-float-body small { display: inline-flex; align-items: center; gap: 4px; font-size: var(--fs-xs); color: var(--muted); }
  .hero-float-body small svg { width: 12px; height: 12px; color: var(--amber); fill: var(--amber); }
  .hero-float-flag {
    padding: 4px 9px; border-radius: var(--r-full);
    font-size: 10.5px; font-weight: 700; letter-spacing: .02em;
    background: var(--line-2); color: var(--muted);
  }
  .hero-float-flag.is-open { background: var(--green-50); color: var(--green-700); }
}
@keyframes floatCard {
  0%, 100% { transform: translateY(0) rotate(-.6deg); }
  50%      { transform: translateY(-12px) rotate(.6deg); }
}

/* --- motion -------------------------------------------------------------- */
@keyframes mapDrift {
  from {
    transform: rotateX(calc(60deg + var(--tilt-x))) rotateZ(calc(-15deg + var(--tilt-y)))
               scale(1.12) translate3d(-1.5%, -1%, 0);
  }
  to {
    transform: rotateX(calc(60deg + var(--tilt-x))) rotateZ(calc(-15deg + var(--tilt-y)))
               scale(1.18) translate3d(1.5%, 1%, 0);
  }
}
/* Restates the full billboard transform — an animation replaces `transform`
   outright, so the counter-rotation has to ride along in every keyframe. */
@keyframes pinFloat {
  0%, 100% {
    transform: translateZ(var(--z, 60px))
               rotateZ(calc(15deg - var(--tilt-y))) rotateX(calc(-60deg - var(--tilt-x)))
               rotate(-45deg) translateY(0);
  }
  50% {
    transform: translateZ(calc(var(--z, 60px) + 14px))
               rotateZ(calc(15deg - var(--tilt-y))) rotateX(calc(-60deg - var(--tilt-x)))
               rotate(-45deg) translateY(0);
  }
}
/* The ground shadow shrinks as its pin climbs — the cue that sells the height. */
@keyframes pinShadow {
  0%, 100% { transform: scale(1);   opacity: .26; }
  50%      { transform: scale(.78); opacity: .16; }
}
@keyframes blockRise {
  from { opacity: 0; transform: translateZ(0); }
  to   { opacity: 1; transform: translateZ(var(--h)); }
}
@keyframes radarPulse {
  0%   { width: 0; height: 0; margin: 0; opacity: .85; }
  100% { width: 460px; height: 460px; margin: -230px 0 0 -230px; opacity: 0; }
}
@keyframes routeDraw {
  0%       { stroke-dashoffset: 1400; }
  55%, 75% { stroke-dashoffset: 0; }
  100%     { stroke-dashoffset: -1400; }
}

/* --- small screens ------------------------------------------------------- */
/* On a phone the copy fills the width, so most pins would sit behind text.
   Keep only the four nearest the corners and shrink them. */
@media (max-width: 767px) {
  .map-pin { width: 32px; height: 32px; margin: -32px 0 0 -16px; }
  .map-pin i { font-size: 14px; }
  /* Keep 1, 5, 6, 8 — the four that sit nearest the corners, so the remaining
     pins frame the copy instead of bunching down one side. */
  .map-pin:nth-child(2), .map-pin:nth-child(3),
  .map-pin:nth-child(4), .map-pin:nth-child(7) { display: none; }
  .hero-roads { background-size: 130px 130px; }
  .hero-roads::after { background-size: 130px 130px; }
  .hero-roads-minor, .hero-roads-minor::after { background-size: 44px 44px; }
  .hero-radar .ring { animation-name: radarPulseSm; }
  /* A stronger veil: less map showing through behind long headline lines. */
  .hero-veil {
    background:
      radial-gradient(78% 46% at 50% 40%, rgba(255,255,255,.95) 0%, rgba(255,255,255,.78) 55%, rgba(255,255,255,.2) 100%),
      linear-gradient(180deg, rgba(255,255,255,.5) 0%, rgba(255,255,255,.14) 32%, rgba(255,255,255,.5) 72%, rgba(255,255,255,.95) 100%);
  }
}
@keyframes radarPulseSm {
  0%   { width: 0; height: 0; margin: 0; opacity: .8; }
  100% { width: 280px; height: 280px; margin: -140px 0 0 -140px; opacity: 0; }
}

/* Motion here is purely decorative — remove all of it on request, but keep the
   map itself visible so the section does not become an empty gradient. */
@media (prefers-reduced-motion: reduce) {
  /* The tilt stays — it is the composition, not the motion. Only the looping
     drift, float and draw animations are dropped. */
  .hero-plate { animation: none; transform: rotateX(60deg) rotateZ(-15deg) scale(1.15); }
  .hero-block { animation: none; transform: translateZ(var(--h)); }
  .map-pin-body {
    animation: none;
    transform: translateZ(var(--z, 60px)) rotateZ(15deg) rotateX(-60deg) rotate(-45deg);
  }
  .map-pin-shadow, .hero-float { animation: none; }
  .hero-radar .ring { animation: none; width: 300px; height: 300px; margin: -150px 0 0 -150px; opacity: .5; }
  .hero-route { animation: none; stroke-dashoffset: 0; }
}

.eyebrow, .kicker {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px; margin-bottom: var(--sp-3);
  border-radius: var(--r-full); font-size: var(--fs-xs); font-weight: 700;
  background: var(--brand-50); color: var(--brand-700);
}
.kicker svg { width: 14px; height: 14px; }

.search-box {
  display: grid; gap: var(--sp-2); padding: var(--sp-3); margin-bottom: var(--sp-4);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--shadow);
}
.search-control { display: flex; align-items: center; gap: 10px; padding: 8px 12px; border-radius: var(--r-sm); background: var(--canvas); }
.search-control svg { width: 18px; height: 18px; color: var(--muted); flex: none; }
.search-control > span { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.search-control small { font-size: var(--fs-xs); color: var(--muted); font-weight: 600; }
.search-control input { border: 0; background: none; padding: 0; min-height: 24px; font-size: var(--fs-sm); font-weight: 500; }
/* The input is borderless and deliberately drops the global focus ring so the
   indicator does not float inside the control — but something has to replace it
   or the hero search has no visible focus at all (WCAG 2.4.7). Same trick as
   .cat-filter / .select-field: hoist the ring onto the wrapper. The 2px inset
   brand line is the part that actually reads (4.55:1 against --canvas); the
   outer --ring is the soft house glow. Inset rather than a real border so
   focusing does not shift the layout by 2px. */
.search-control input:focus { box-shadow: none; }
.search-control { transition: box-shadow .16s var(--ease); }
.search-control:focus-within { box-shadow: var(--ring), inset 0 0 0 2px var(--brand); }
.search-separator { display: none; }
.search-button { width: 100%; }

.popular-row, .ai-search-strip { display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-2); font-size: var(--fs-sm); margin-bottom: var(--sp-3); }
.popular-row strong, .ai-label { font-size: var(--fs-xs); font-weight: 700; color: var(--muted); }
.popular-row button, .ai-search-strip button {
  padding: 7px 12px; border-radius: var(--r-full); font-size: var(--fs-xs); font-weight: 500;
  background: var(--surface); border: 1px solid var(--line); color: var(--ink-2);
}
.popular-row button:hover, .ai-search-strip button:hover { border-color: var(--brand-200); background: var(--brand-50); color: var(--brand-700); }
.ai-label { display: inline-flex; align-items: center; gap: 5px; color: var(--brand); }
.ai-label svg { width: 15px; height: 15px; }
.ai-search-strip button { border-color: var(--brand-100); background: var(--brand-50); color: var(--brand-700); }
.ai-search-strip button svg { width: 13px; height: 13px; }

.internal-search { padding-block: var(--sp-4); border-bottom: 1px solid var(--line); background: var(--surface); }
.wide-search {
  display: grid; gap: var(--sp-2); padding: var(--sp-2);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--shadow-xs);
}
.wide-search label { display: flex; align-items: center; gap: 9px; padding: 6px 12px; border-radius: var(--r-sm); background: var(--canvas); }
.wide-search label svg { width: 17px; height: 17px; color: var(--muted); flex: none; }
.wide-search input { border: 0; background: none; padding: 0; min-height: 30px; font-size: var(--fs-sm); }
.wide-search input:focus { box-shadow: none; }
/* Same reasoning as .search-control above — the wrapper carries the indicator. */
.wide-search label { transition: box-shadow .16s var(--ease); }
.wide-search label:focus-within { box-shadow: var(--ring), inset 0 0 0 2px var(--brand); }

/* -------------------------------------------------------- page heads ----- */
.page-heading { padding-block: var(--sp-6) var(--sp-4); }
.breadcrumbs { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; font-size: var(--fs-xs); color: var(--muted); margin-bottom: var(--sp-3); }
.breadcrumbs a { color: var(--muted); }
.breadcrumbs a:hover { color: var(--brand); }

.heading-row { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-4); flex-wrap: wrap; margin-bottom: var(--sp-4); }
.heading-row h1 { font-size: var(--fs-2xl); }
.heading-row h1 span { color: var(--green-600); }
.heading-row > div > p { color: var(--muted); font-size: var(--fs-sm); margin-top: 4px; }
.heading-actions { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
.heading-actions button, .heading-actions a {
  display: inline-flex; align-items: center; gap: 6px; padding: 8px 13px;
  border-radius: var(--r-sm); font-size: var(--fs-sm); font-weight: 600;
  color: var(--ink-2); border: 1px solid var(--line); background: var(--surface);
}
.heading-actions button:hover, .heading-actions a:hover { background: var(--canvas); }
.heading-actions svg { width: 15px; height: 15px; }

/* horizontal scroll beats wrapping into a broken pile on phones */
.filter-row {
  display: flex; gap: var(--sp-2); align-items: center;
  overflow-x: auto; padding-bottom: var(--sp-2); margin-bottom: var(--sp-4);
  scrollbar-width: thin; -webkit-overflow-scrolling: touch;
}
.filter-row::-webkit-scrollbar { height: 4px; }
.filter-row::-webkit-scrollbar-thumb { background: var(--line); border-radius: 4px; }
.filter-row a, .filter-row button {
  display: inline-flex; align-items: center; gap: 6px; flex: none;
  padding: 9px 14px; border-radius: var(--r-full);
  font-size: var(--fs-sm); font-weight: 600; white-space: nowrap;
  background: var(--surface); border: 1px solid var(--line); color: var(--ink-2);
}
.filter-row a:hover, .filter-row button:hover { border-color: var(--brand-200); background: var(--brand-50); color: var(--brand-700); }
.filter-row a.active, .filter-row button.active { background: var(--brand); border-color: var(--brand); color: #fff; }
.filter-row svg { width: 15px; height: 15px; }
.sort-spacer { flex: 1 0 auto; }

/* --- unified filter toolbar (search results) ----------------------------- */
/* One card holding every control that narrows the result set. Chips scroll
   horizontally on phones; the selects sit on their own line until there is room
   to bring them alongside. */
.filter-bar {
  display: grid; gap: var(--sp-3);
  padding: var(--sp-3); margin-bottom: var(--sp-4);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--shadow-xs);
}
.filter-bar-chips {
  display: flex; align-items: center; gap: var(--sp-2);
  overflow-x: auto; scrollbar-width: thin; -webkit-overflow-scrolling: touch;
}
.filter-bar-chips::-webkit-scrollbar { height: 4px; }
.filter-bar-chips::-webkit-scrollbar-thumb { background: var(--line); border-radius: 4px; }
.filter-group { display: flex; align-items: center; gap: 6px; flex: none; }
.filter-sep { flex: none; width: 1px; height: 22px; background: var(--line); }

.filter-bar .chip {
  display: inline-flex; align-items: center; gap: 6px; flex: none;
  padding: 8px 13px; border-radius: var(--r-full);
  font-size: var(--fs-sm); font-weight: 600; white-space: nowrap;
  background: var(--surface); border: 1px solid var(--line); color: var(--ink-2);
  transition: background .16s var(--ease), border-color .16s var(--ease),
              color .16s var(--ease), transform .16s var(--ease-out);
}
.filter-bar .chip svg { width: 14px; height: 14px; }
.filter-bar .chip:hover { border-color: var(--brand-200); background: var(--brand-50); color: var(--brand-700); transform: translateY(-1px); }
.filter-bar .chip.active {
  background: var(--brand); border-color: var(--brand); color: #fff;
  box-shadow: var(--shadow-brand);
}
.chip-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--green); flex: none; }
.chip.active .chip-dot { background: #fff; }
.chip-price { min-width: 44px; justify-content: center; font-weight: 700; letter-spacing: .04em; }

/* Sticky-right so it stays reachable while the chips scroll underneath it on
   phones; the box-shadow is the gutter that stops chips touching it. */
.filter-reset {
  position: sticky; right: 0;
  display: inline-flex; align-items: center; gap: 5px; flex: none;
  margin-left: auto; padding: 8px 12px; border-radius: var(--r-full);
  font-size: var(--fs-xs); font-weight: 700; color: var(--red-text);
  background: var(--red-50); white-space: nowrap;
  box-shadow: -10px 0 12px -4px var(--surface);
}
.filter-reset:hover { background: #fde2e2; color: #b91c1c; }
.filter-reset svg { width: 13px; height: 13px; }

.filter-bar-selects {
  display: flex; flex-wrap: wrap; gap: var(--sp-2);
  padding-top: var(--sp-3); border-top: 1px dashed var(--line);
}
/* Label sits inside the control, so three of these read as one aligned band
   instead of six loose label+select pairs. */
.select-field {
  display: flex; align-items: center; gap: 8px; flex: 1 1 190px; min-width: 0;
  padding: 4px 4px 4px 12px; border-radius: var(--r-btn);
  background: var(--canvas); border: 1px solid var(--line);
  transition: border-color .16s var(--ease), box-shadow .16s var(--ease);
}
.select-field:focus-within { border-color: var(--brand-200); box-shadow: var(--ring); }
.select-field > span {
  font-size: var(--fs-xs); font-weight: 700; color: var(--muted);
  white-space: nowrap; flex: none;
}
.select-field select {
  flex: 1 1 auto; width: auto; min-width: 0; min-height: 34px;
  padding: 4px 26px 4px 6px; border: 0; background-color: transparent;
  font-size: var(--fs-sm); font-weight: 600; color: var(--ink);
}
.select-field select:focus { box-shadow: none; }

/* Range readout above the list, replacing the old inline sort row. */
.list-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--sp-3); padding-bottom: 2px;
}
.list-head .sort-count { font-size: var(--fs-sm); font-weight: 700; color: var(--ink); }
.list-head-sort { font-size: var(--fs-xs); font-weight: 600; color: var(--muted); }

.ai-banner {
  display: flex; align-items: flex-start; gap: var(--sp-3); flex-wrap: wrap;
  padding: var(--sp-4); border-radius: var(--r);
  background: linear-gradient(135deg, var(--brand-50), #fff); border: 1px solid var(--brand-100);
}
.ai-banner > svg { width: 22px; height: 22px; color: var(--brand); flex: none; }
.ai-banner div { flex: 1 1 240px; min-width: 0; }
.ai-banner strong { display: block; font-size: var(--fs-sm); }
.ai-banner strong span { margin-left: 6px; padding: 2px 7px; border-radius: var(--r-full); font-size: 10px; background: var(--brand); color: #fff; vertical-align: middle; }
.ai-banner p { font-size: var(--fs-xs); color: var(--muted); margin-top: 2px; }
.ai-banner > button { padding: 8px 13px; border-radius: var(--r-sm); font-size: var(--fs-xs); font-weight: 600; border: 1px solid var(--line); background: var(--surface); color: var(--ink-2); }

/* ------------------------------------------------------ result cards ----- */
.search-layout { display: grid; gap: var(--sp-5); }
.search-list { display: grid; gap: var(--sp-4); min-width: 0; }
.sort-row { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; font-size: var(--fs-sm); color: var(--muted); }
.sort-row select { width: auto; min-width: 150px; min-height: 38px; padding-block: 6px; }
.open-line, .open-copy { font-size: var(--fs-xs); color: var(--muted); }

/* =========================================================================
   LISTING CARDS — text-first
   Listings carry no image (migration 002). A category glyph plus typography
   does the work, which means: one fewer request per card, no layout shift,
   no upload surface, and a list that is scannable by type at a glance.
   ========================================================================= */

/* --- category tile ------------------------------------------------------- */
/* Hue is seeded from the CATEGORY, not the business name, so every cafe shares
   a colour. That makes colour a second, redundant encoding of type; seeding
   per-name would just produce confetti.
   Shares the 3D badge treatment defined under "ICON 3D SYSTEM" below. */
.listing-avatar {
  position: relative; display: grid; place-items: center; flex: none;
  line-height: 1;
  border-radius: 30%;
  background:
    radial-gradient(120% 100% at 28% 18%, hsl(var(--hue,220) 100% 97%) 0%, transparent 55%),
    linear-gradient(160deg,
      hsl(var(--hue,220) 88% 88%) 0%,
      hsl(calc(var(--hue,220) + 20) 74% 74%) 100%);
  box-shadow:
    inset 0 1.5px 0 hsl(var(--hue,220) 100% 97%),
    inset 0 -2px 0 hsl(calc(var(--hue,220) + 16) 52% 62%),
    0 3px 0 hsl(calc(var(--hue,220) + 16) 46% 70%),
    0 6px 12px -4px hsl(var(--hue,220) 60% 45% / .45);
  transform: perspective(360px) rotateX(9deg);
  transform-style: preserve-3d;
  transition: transform .3s cubic-bezier(.2,.9,.3,1), box-shadow .3s;
}
.listing-avatar-face { position: relative; z-index: 2; transform: translateZ(12px);
  filter: drop-shadow(0 2px 1.5px hsl(var(--hue,220) 55% 34% / .45));
  transition: transform .3s cubic-bezier(.2,.9,.3,1); }
.listing-row:hover .listing-avatar-face,
.listing-tile:hover .listing-avatar-face { transform: translateZ(22px) scale(1.12); }
.listing-avatar.is-sm { width: 40px; height: 40px; font-size: 19px; }
.listing-avatar.is-md { width: 54px; height: 54px; font-size: 26px; }
.listing-avatar.is-lg { width: 62px; height: 62px; font-size: 31px; }

/* Periodic light sweep. Staggered per card so the page glints rather than
   strobing in unison. */
.listing-avatar::after {
  content: ""; position: absolute; inset: 0; z-index: 1; border-radius: inherit;
  background: linear-gradient(105deg, transparent 42%, rgba(255,255,255,.9) 50%, transparent 58%);
  background-size: 300% 100%; background-position: 160% 0;
  animation: iconFlash 7s ease-in-out infinite;
  animation-delay: var(--delay, 0s);
  pointer-events: none;
}

/* Hover on the card: the badge stands up and shakes once. */
.listing-row:hover .listing-avatar,
.listing-tile:hover .listing-avatar {
  animation: iconShake .55s ease-in-out;
  box-shadow:
    inset 0 1.5px 0 hsl(var(--hue,220) 100% 98%),
    inset 0 -2px 0 hsl(calc(var(--hue,220) + 16) 52% 60%),
    0 5px 0 hsl(calc(var(--hue,220) + 16) 46% 68%),
    0 12px 20px -6px hsl(var(--hue,220) 60% 42% / .55);
}

/* --- shared text atoms --------------------------------------------------- */
.listing-kicker { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.listing-cat {
  font-size: var(--fs-xs); font-weight: 700; letter-spacing: .02em;
  color: hsl(var(--hue, 220) 52% 38%);
}
.listing-price { font-size: var(--fs-xs); font-weight: 600; color: var(--muted); }
.listing-price::before { content: "\00B7"; margin-right: var(--sp-2); color: var(--line); }

.listing-meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); }
.listing-rating { display: inline-flex; align-items: center; gap: 5px; font-size: var(--fs-sm); }
.listing-rating b { font-weight: 800; letter-spacing: -.02em; }
.listing-rating .stars { font-size: .82em; }
.listing-rating small { color: var(--muted); font-size: var(--fs-xs); }
.listing-rating.is-new small { font-style: italic; }
.listing-distance, .listing-hours {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: var(--fs-xs); font-weight: 600; color: var(--muted);
}
.listing-distance svg { width: 13px; height: 13px; }
.listing-hours { color: var(--green-700); }
.listing-address { font-size: var(--fs-xs); color: var(--muted); }
.listing-actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: auto; padding-top: var(--sp-1); }

.verified-dot {
  display: inline-grid; place-items: center; width: 17px; height: 17px;
  border-radius: 50%; background: var(--brand); color: #fff;
  font-size: 10px; font-weight: 700; vertical-align: middle;
}

/* --- horizontal row (search results) ------------------------------------- */
/* Deliberately tighter than the tile: a results list is scanned, so vertical
   rhythm matters more than breathing room. Trimmed padding, row gaps, avatar
   and action-button height take ~55px off each card without shrinking the
   business name or losing a single field. */
.listing-row {
  position: relative; display: grid; grid-template-columns: auto 1fr;
  gap: var(--sp-3); padding: var(--sp-3) var(--sp-4);
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
  transition: border-color .18s, box-shadow .18s, transform .18s;
}
.listing-row .listing-avatar.is-md { width: 46px; height: 46px; font-size: 22px; }
.listing-row .listing-headline h2 { font-size: var(--fs-md); line-height: 1.3; }
.listing-row .listing-meta { gap: var(--sp-2) 10px; }
.listing-row .listing-address { line-height: 1.35; }
.listing-row .tag-row { gap: 5px; }
.listing-row .tag-row span { padding: 3px 8px; }
.listing-row .listing-actions { padding-top: 2px; gap: 6px; }
.listing-row .listing-actions .button {
  min-height: 34px; padding: 7px 13px; font-size: var(--fs-xs);
}
.listing-row .listing-actions .button svg { width: 15px; height: 15px; }
/* Colour rail keyed to the category — reinforces type without an image. */
.listing-row::before {
  content: ""; position: absolute; inset: 0 auto 0 0; width: 3px;
  border-radius: var(--r) 0 0 var(--r);
  background: hsl(var(--hue, 220) 70% 62%);
  opacity: 0; transition: opacity .18s;
}
.listing-row:hover { border-color: var(--brand-200); box-shadow: var(--shadow); }
.listing-row:hover::before { opacity: 1; }

.listing-row-lead { position: relative; display: grid; gap: var(--sp-2); justify-items: center; }
.listing-rank {
  display: grid; place-items: center; min-width: 22px; height: 22px; padding-inline: 6px;
  border-radius: var(--r-full); background: var(--line-2); color: var(--muted);
  font-size: var(--fs-xs); font-weight: 700;
}
.listing-row-body { display: grid; gap: 5px; min-width: 0; align-content: start; }

.listing-headline { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-2); }
.listing-headline h2 { font-size: var(--fs-lg); display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.listing-headline h2 a { color: var(--ink); }
.listing-headline h2 a:hover { color: var(--brand); }

/* --- vertical tile (grids) ----------------------------------------------- */
.listing-tile {
  display: flex; flex-direction: column; gap: 7px;
  padding: var(--sp-4); min-width: 0;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
  transition: border-color .18s, box-shadow .18s, transform .18s;
}
.listing-tile:hover { border-color: var(--brand-200); box-shadow: var(--shadow); transform: translateY(-2px); }
.listing-tile.is-featured {
  border-color: hsl(var(--hue, 220) 60% 80%);
  background: linear-gradient(180deg, hsl(var(--hue, 220) 80% 98%) 0%, var(--surface) 60%);
}
.listing-tile-top { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-2); margin-bottom: var(--sp-1); }
.listing-tile-flags { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 5px; }
.listing-tile h3 { font-size: var(--fs-md); display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.listing-tile h3 a { color: var(--ink); }
.listing-tile h3 a:hover { color: var(--brand); }

.vertical-card-body, .result-content, .featured-content { display: grid; gap: 7px; padding: var(--sp-4); flex: 1; min-width: 0; align-content: start; }
.vertical-card-body h3, .result-content h3, .featured-content h3 { font-size: var(--fs-md); }
.vertical-card-body h3 a, .result-content h3 a, .featured-content h3 a { color: var(--ink); }
.vertical-card-body h3 a:hover, .result-content h3 a:hover, .featured-content h3 a:hover { color: var(--brand); }
.vertical-card-body > p, .result-content > p, .featured-content > p { font-size: var(--fs-sm); color: var(--muted); }

.card-buttons, .result-actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: auto; padding-top: var(--sp-2); }
.card-buttons a, .card-buttons button, .result-actions a {
  display: inline-flex; align-items: center; gap: 5px; padding: 7px 12px;
  border-radius: var(--r-sm); font-size: var(--fs-xs); font-weight: 600;
  border: 1px solid var(--line); color: var(--ink-2); background: var(--surface);
}
.card-buttons a:first-child, .result-actions a:last-child { background: var(--brand); border-color: var(--brand); color: #fff; }
.card-buttons a:hover, .result-actions a:hover { border-color: var(--brand-200); }
.result-actions svg, .card-buttons svg { width: 14px; height: 14px; }
.feature-line { display: flex; flex-wrap: wrap; gap: var(--sp-2); font-size: var(--fs-xs); color: var(--muted); }
.result-summary { font-size: var(--fs-xs); color: var(--muted); text-align: center; }

.sticky-map, .results-map-card {
  position: relative; overflow: hidden; min-width: 0;
  border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--canvas);
}
.sticky-map > img, .results-map-card > img { width: 100%; height: 100%; min-height: 320px; object-fit: cover; }
.map-toolbar {
  position: absolute; inset: 10px 10px auto 10px; z-index: 2;
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); flex-wrap: wrap;
}
.map-toolbar label, .map-toolbar button {
  display: inline-flex; align-items: center; gap: 6px; padding: 8px 12px;
  border-radius: var(--r-sm); font-size: var(--fs-xs); font-weight: 600; color: var(--ink-2);
  background: rgba(255,255,255,.96); border: 1px solid var(--line); box-shadow: var(--shadow-sm);
}
.map-toolbar input { width: 16px; height: 16px; min-height: 0; accent-color: var(--brand); }

.pagination { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px; margin-top: var(--sp-4); }
.pagination a, .pagination span, .pagination button {
  display: grid; place-items: center; min-width: 40px; height: 40px; padding-inline: 12px;
  border-radius: var(--r-sm); font-size: var(--fs-sm); font-weight: 600;
  border: 1px solid var(--line); color: var(--ink-2); background: var(--surface);
}
.pagination a:hover { border-color: var(--brand-200); background: var(--brand-50); color: var(--brand-700); }
.pagination .active { background: var(--brand); border-color: var(--brand); color: #fff; }
.pagination span { border-color: transparent; background: none; color: var(--muted); }

.load-more, .view-more-results {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  width: 100%; padding: 12px; border-radius: var(--r-sm);
  font-size: var(--fs-sm); font-weight: 600; color: var(--brand);
  border: 1px solid var(--line); background: var(--surface);
}
.load-more:hover, .view-more-results:hover { background: var(--brand-50); border-color: var(--brand-200); }

.empty-state {
  display: grid; gap: var(--sp-3); justify-items: center; text-align: center;
  padding: var(--sp-12) var(--sp-4);
  border: 1px dashed var(--line); border-radius: var(--r-lg); background: var(--canvas);
}
.empty-state h1, .empty-state h2 { font-size: var(--fs-xl); }
.empty-state p { color: var(--muted); font-size: var(--fs-sm); max-width: 46ch; }

.insight-strip { padding-block: var(--sp-6); background: var(--canvas); }
.insight-grid { display: grid; gap: var(--sp-3); grid-template-columns: repeat(auto-fit, minmax(min(100%, 190px), 1fr)); }
.insight-grid > div { display: grid; gap: 3px; padding: var(--sp-4); background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); }
.insight-grid strong { display: flex; align-items: center; gap: 6px; font-size: var(--fs-sm); }
.insight-grid strong svg { width: 15px; height: 15px; color: var(--brand); }
.insight-grid span { font-size: var(--fs-xs); color: var(--muted); }
.nearby-categories { padding-block: var(--sp-8); }

/* ------------------------------------------------- category & city ------- */
.category-hero { padding-block: var(--sp-8); background: linear-gradient(180deg, var(--brand-50), rgba(255,255,255,0)); }
.category-hero-grid { display: grid; gap: var(--sp-6); align-items: center; }
.category-hero h1 { margin-bottom: var(--sp-3); }
.category-hero h1 span { color: var(--brand); }
.category-hero > div > p, .category-hero-grid > div > p { color: var(--muted); margin-bottom: var(--sp-4); }
.result-count {
  display: inline-flex; align-items: center; gap: 6px; margin-bottom: var(--sp-4);
  padding: 8px 14px; border-radius: var(--r-full);
  background: var(--green-50); color: var(--green-700); font-size: var(--fs-sm); font-weight: 600;
}
.category-map { position: relative; border-radius: var(--r-lg); overflow: hidden; border: 1px solid var(--line); box-shadow: var(--shadow); }
.category-map img { width: 100%; aspect-ratio: 4 / 3; }
.category-map a {
  position: absolute; left: 50%; bottom: 16px; transform: translateX(-50%);
  padding: 10px 18px; border-radius: var(--r-full); background: var(--surface);
  box-shadow: var(--shadow); font-size: var(--fs-sm); font-weight: 600; white-space: nowrap;
}


.city-hero { padding-block: var(--sp-8); }
.city-hero .site-container { display: grid; gap: var(--sp-6); }
.city-hero-card { min-width: 0; }
.city-hero h1 { margin-bottom: var(--sp-3); }
.city-hero h1 span { color: var(--brand); }
.city-copy > p { color: var(--muted); margin-bottom: var(--sp-5); }
.city-hero > .site-container > img { width: 100%; aspect-ratio: 16 / 10; border-radius: var(--r-lg); box-shadow: var(--shadow); }

.stat-row { display: grid; gap: var(--sp-3); grid-template-columns: repeat(auto-fit, minmax(min(50% - 8px, 120px), 1fr)); margin-bottom: var(--sp-5); list-style: none; padding: 0; }
/* `> li` as well as `> div`: index.php, contact.php and account/index.php build
   this out of <div>s, but locations.php uses a <ul>/<li> — which is the more
   correct markup for three parallel figures, and which this selector silently
   did not match, so that page alone rendered its stats as an unstyled bullet
   list. Matching both is cheaper and safer than rewriting the markup on a page
   whose stats are genuinely a list. */
.stat-row > div, .stat-row > li { padding: var(--sp-3); background: var(--canvas); border-radius: var(--r); border: 1px solid var(--line); }
.stat-row strong { display: block; font-size: var(--fs-xl); color: var(--brand); letter-spacing: -.03em; }
.stat-row span { font-size: var(--fs-xs); color: var(--muted); }

.neighborhood-chips { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.neighborhood-chips > span { font-size: var(--fs-xs); color: var(--muted); font-weight: 700; }
.neighborhood-chips a, .neighborhood-chips button {
  padding: 7px 13px; border-radius: var(--r-full); font-size: var(--fs-sm);
  background: var(--surface); border: 1px solid var(--line); color: var(--ink-2);
}
.neighborhood-chips a:hover { border-color: var(--brand-200); background: var(--brand-50); color: var(--brand-700); }

.city-panels { padding-block: var(--sp-8); background: var(--canvas); }
.two-panel { display: grid; gap: var(--sp-6); }
.trend-panel { padding: var(--sp-5); background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg); }
.trend-panel h2 { font-size: var(--fs-lg); margin-bottom: var(--sp-4); }
.trend-panel > div { display: flex; align-items: center; gap: var(--sp-3); padding: 11px 0; border-bottom: 1px solid var(--line-2); font-size: var(--fs-sm); }
.trend-panel > div:last-child { border-bottom: 0; }
.trend-panel b { display: grid; place-items: center; width: 24px; height: 24px; flex: none; border-radius: 7px; background: var(--brand-50); color: var(--brand-700); font-size: var(--fs-xs); }
.trend-panel span { flex: 1; min-width: 0; }
.trend-panel em { font-style: normal; font-size: var(--fs-xs); color: var(--muted); }

.collection-grid article, .article-grid article, .deal-grid article {
  display: grid; gap: 4px; overflow: hidden; align-content: start;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
  transition: box-shadow .18s, transform .18s;
}
.collection-grid article:hover, .article-grid article:hover, .deal-grid article:hover { box-shadow: var(--shadow); transform: translateY(-2px); }
.collection-grid img, .article-grid img, .deal-grid img { width: 100%; aspect-ratio: 16 / 10; }
.collection-grid h3, .article-grid h3 { padding: 12px 14px 0; font-size: var(--fs-md); }
.collection-grid p, .article-grid p { padding: 0 14px 14px; font-size: var(--fs-xs); color: var(--muted); }
.deal-grid > article > div { display: grid; gap: 4px; padding: var(--sp-4); }
.deal-grid strong { font-size: var(--fs-xs); color: var(--muted); }
.deal-grid h3 { font-size: var(--fs-lg); color: var(--green-600); }
.deal-grid p { font-size: var(--fs-xs); color: var(--muted); }
.deal-grid a { font-size: var(--fs-sm); font-weight: 600; }

.info-columns { padding-block: var(--sp-8); background: var(--canvas); }
.info-grid > article { padding: var(--sp-5); background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg); }
.info-grid h3 { font-size: var(--fs-md); }
.info-grid ul { display: grid; gap: 2px; }
.info-grid li { display: flex; align-items: center; gap: 8px; padding: 9px 0; border-bottom: 1px solid var(--line-2); font-size: var(--fs-sm); }
.info-grid li:last-child { border-bottom: 0; }
.info-grid li a { flex: 1; min-width: 0; color: var(--ink-2); }
.info-grid li a:hover { color: var(--brand); }
.info-grid li span { font-size: var(--fs-xs); color: var(--muted); }
.seo-card { background: linear-gradient(135deg, var(--brand-50), #fff) !important; }
.seo-card p { font-size: var(--fs-sm); color: var(--muted); margin-block: var(--sp-2) var(--sp-3); }

/* ------------------------------------------------------ business page ---- */
.business-top { padding-block: var(--sp-5); }
.business-hero-grid { display: grid; gap: var(--sp-5); align-items: start; min-width: 0; }
/* Anchor as well as button: the "+N more photos" affordance is navigation to
   the Photos section, so it must work without JS. */
.gallery-side button, .gallery-side a.more-photos {
  display: grid; place-items: center; text-align: center; aspect-ratio: 1;
  border-radius: var(--r-sm); background: var(--canvas); border: 1px solid var(--line);
  font-size: var(--fs-sm); font-weight: 700; color: var(--ink-2); line-height: 1.25;
  transition: background .15s, border-color .15s, color .15s;
}

.business-top h1 { font-size: var(--fs-2xl); display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.address { font-size: var(--fs-sm); color: var(--muted); margin-top: var(--sp-2); }
.business-actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-4); }
.business-actions a {
  display: inline-flex; align-items: center; gap: 6px; padding: 10px 15px;
  border-radius: var(--r-sm); font-size: var(--fs-sm); font-weight: 600;
  border: 1px solid var(--line); color: var(--ink-2); background: var(--surface);
}
.business-actions a:hover { background: var(--canvas); border-color: var(--muted-2); }
.business-actions a.primary { background: var(--brand); border-color: var(--brand); color: #fff; }
.business-actions a.primary:hover { background: var(--brand-600); }
.business-actions svg { width: 15px; height: 15px; }

.contact-card {
  display: grid; gap: var(--sp-2); padding: var(--sp-4); min-width: 0;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--shadow-sm);
}
.open-status {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); flex-wrap: wrap;
  padding-bottom: var(--sp-3); border-bottom: 1px solid var(--line);
  font-size: var(--fs-sm); font-weight: 700; color: var(--green-600);
}
.open-status span { font-size: var(--fs-xs); font-weight: 500; color: var(--muted); }
.contact-card > a {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 11px 13px;
  border-radius: var(--r-sm); font-size: var(--fs-sm); font-weight: 600;
  color: var(--ink-2); border: 1px solid var(--line); background: var(--surface);
}
.contact-card > a:hover { background: var(--canvas); border-color: var(--brand-200); }
.contact-card > a small { width: 100%; padding-left: 26px; font-weight: 400; font-size: var(--fs-xs); color: var(--muted); }
.contact-card > a svg { width: 16px; height: 16px; flex: none; }
.contact-card > a.book { background: var(--brand); border-color: var(--brand); color: #fff; }
.contact-card > a.book small { color: rgba(255,255,255,.85); }
.contact-card > img { width: 100%; aspect-ratio: 16 / 10; border-radius: var(--r-sm); }
.contact-card > p { font-size: var(--fs-xs); color: var(--muted); }
.map-link { font-size: var(--fs-sm); font-weight: 600; }

.business-tabs { position: sticky; top: var(--header-h); z-index: 40; background: var(--surface); border-block: 1px solid var(--line); }
.business-tabs .site-container { display: flex; gap: var(--sp-1); overflow-x: auto; scrollbar-width: none; }
.business-tabs .site-container::-webkit-scrollbar { display: none; }
.business-tabs a { padding: 14px; font-size: var(--fs-sm); font-weight: 600; color: var(--muted); white-space: nowrap; border-bottom: 2px solid transparent; }
.business-tabs a:hover { color: var(--brand); }
.business-tabs a.active { color: var(--brand); border-bottom-color: var(--brand); }

.business-content { padding-block: var(--sp-6); background: var(--canvas); }
.business-content .site-container { display: grid; gap: var(--sp-4); }
.content-card { padding: var(--sp-5); background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg); min-width: 0; }
.content-card h2 { font-size: var(--fs-xl); margin-bottom: var(--sp-3); }
.content-card h3 { margin-block: var(--sp-4) var(--sp-2); }
.content-card > p { color: var(--ink-2); font-size: var(--fs-sm); }

.attribute-grid { display: grid; gap: var(--sp-3); margin-top: var(--sp-4); grid-template-columns: repeat(auto-fit, minmax(min(50% - 6px, 140px), 1fr)); }
.attribute-grid > div { display: grid; gap: 2px; padding: var(--sp-3); background: var(--canvas); border-radius: var(--r-sm); }
.attribute-grid span { font-size: var(--fs-xs); color: var(--muted); }
.attribute-grid strong { font-size: var(--fs-sm); }

.reviews-layout { display: grid; gap: var(--sp-4); }
.rating-summary { display: grid; gap: 4px; padding: var(--sp-4); background: var(--canvas); border-radius: var(--r); align-content: start; }
.rating-summary > strong { font-size: var(--fs-3xl); line-height: 1; }
.rating-summary > p { font-size: var(--fs-xs); color: var(--muted); margin-bottom: var(--sp-2); }
.rating-summary > div { display: flex; align-items: center; gap: 8px; font-size: var(--fs-xs); }
.rating-summary b { width: 30px; flex: none; color: var(--muted); font-weight: 500; }
.rating-summary i { flex: 1; height: 7px; border-radius: var(--r-full); background: var(--line); position: relative; overflow: hidden; }
.rating-summary i::after { content: ""; position: absolute; inset: 0 auto 0 0; width: var(--w, 0%); background: var(--amber); border-radius: inherit; }
.rating-summary em { font-style: normal; color: var(--muted); min-width: 32px; text-align: right; }

.review-card { display: grid; gap: var(--sp-2); padding: var(--sp-4); border: 1px solid var(--line); border-radius: var(--r); }
.review-user { display: flex; align-items: center; gap: 10px; }
.review-user > span { display: grid; place-items: center; width: 38px; height: 38px; flex: none; border-radius: 50%; background: var(--brand-50); color: var(--brand-700); font-weight: 700; }
.review-user strong { display: grid; font-size: var(--fs-sm); }
.review-user small { font-size: var(--fs-xs); font-weight: 500; color: var(--green-600); }
.review-card > p { font-size: var(--fs-sm); color: var(--ink-2); }
.review-card blockquote { margin: 0; padding: var(--sp-3); border-left: 3px solid var(--brand-200); background: var(--canvas); border-radius: 0 var(--r-sm) var(--r-sm) 0; }
.review-card blockquote strong { font-size: var(--fs-xs); color: var(--brand-700); }
.review-card blockquote p { font-size: var(--fs-sm); color: var(--muted); }

.two-column-content { display: grid; gap: var(--sp-4); }
.hours-row { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); padding: 10px 0; border-bottom: 1px solid var(--line-2); font-size: var(--fs-sm); }
.hours-row:last-of-type { border-bottom: 0; }
.hours-row span { color: var(--muted); font-size: var(--fs-xs); }
.hours-row.is-today { font-weight: 700; }
.hours-row.is-today span { color: var(--green-600); font-weight: 600; }

.offer-row {
  display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap;
  padding: var(--sp-3); margin-bottom: var(--sp-2);
  border: 1px dashed var(--brand-200); border-radius: var(--r); background: var(--brand-50);
}
.offer-row > span { font-size: 1.3rem; flex: none; }
.offer-row > div { flex: 1 1 180px; min-width: 0; }
.offer-row strong { display: block; font-size: var(--fs-sm); }
.offer-row p, .offer-row small { font-size: var(--fs-xs); color: var(--muted); }
.offer-row button { padding: 8px 14px; border-radius: var(--r-sm); background: var(--brand); color: #fff; font-size: var(--fs-xs); font-weight: 600; }

.similar-grid a { display: grid; overflow: hidden; align-content: start; border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); transition: box-shadow .18s, transform .18s; }
.similar-grid a:hover { box-shadow: var(--shadow); transform: translateY(-2px); }
.similar-grid > a > img { width: 100%; aspect-ratio: 16 / 10; }
.similar-grid div { display: grid; gap: 2px; padding: var(--sp-3); }
.similar-grid strong { font-size: var(--fs-sm); color: var(--ink); }
.similar-grid span { font-size: var(--fs-xs); color: var(--muted); }

/* ------------------------------------------------------- add business ---- */
/*
 * add-business.php was rewritten onto its own ab-* namespace in
 * assets/css/add-business.css, which orphaned the whole hero / stepper /
 * onboarding / plans / testimonial set that used to live here. Removed:
 * .add-hero*, .onboarding*, .stepper*, .business-onboarding*, .benefits-card*,
 * .plans, .plan-layout*, .plan-card*, .popular-badge, .owner-love* — each
 * confirmed unreferenced by a repo-wide grep of *.php / *.js first.
 *
 * NOT removed, because they are still live: .faq-card* (contact.php),
 * .testimonial-grid/.testimonial-strip (index.php). Note .plan-grid near the
 * top of this file is an unrelated generic grid utility, not part of this set.
 */
.faq-card { display: grid; gap: var(--sp-2); align-content: start; padding: var(--sp-5); background: var(--canvas); border: 1px solid var(--line); border-radius: var(--r-lg); }
.faq-card h2 { font-size: var(--fs-lg); margin-bottom: var(--sp-2); }
.faq-card details { padding: 12px 14px; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-sm); }
.faq-card summary { font-size: var(--fs-sm); font-weight: 600; cursor: pointer; list-style: none; }
.faq-card summary::-webkit-details-marker { display: none; }
.faq-card summary::after { content: "+"; float: right; color: var(--muted); font-weight: 400; }
.faq-card details[open] summary::after { content: "−"; }
.faq-card details p { margin-top: 8px; font-size: var(--fs-sm); color: var(--muted); }

.testimonial-grid article, .testimonial-strip article { display: grid; gap: 6px; padding: var(--sp-4); background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); }
.testimonial-grid p, .testimonial-strip p { font-size: var(--fs-sm); color: var(--ink-2); }
.testimonial-grid strong, .testimonial-strip strong { font-size: var(--fs-sm); }
/* This span is the attribution line — "Bengaluru", "Cafe Owner" — not a star
   rating, so the star exemption does not apply to it and --amber measured
   2.15:1 on --surface. #b45309 is the amber the badges already use: 5.02:1,
   same hue family, still reads as the accent. */
.testimonial-grid > article > span, .testimonial-strip > article > span { font-size: var(--fs-xs); color: #b45309; }

/* ---------------------------------------------------- homepage extras ---- */
.results-section { padding-block: var(--sp-8); }
.results-layout { display: grid; gap: var(--sp-5); }
.results-list-panel { display: grid; gap: var(--sp-4); align-content: start; min-width: 0; }
.results-heading { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); flex-wrap: wrap; }
.results-heading h2 { font-size: var(--fs-lg); }
.results-heading select { width: auto; min-height: 38px; }

.categories-section { padding-block: var(--sp-8); background: var(--canvas); }
.how-section { padding-block: var(--sp-10); }
.step-card { position: relative; display: grid; gap: 8px; justify-items: center; text-align: center; padding: var(--sp-5) var(--sp-4); background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg); }
.step-number { display: grid; place-items: center; width: 28px; height: 28px; border-radius: 50%; background: var(--brand); color: #fff; font-size: var(--fs-xs); font-weight: 700; }
.step-icon { display: grid; place-items: center; width: 48px; height: 48px; border-radius: var(--r); background: var(--brand-50); color: var(--brand); }
.step-icon svg { width: 22px; height: 22px; }
.step-card h3 { font-size: var(--fs-md); }
.step-card p { font-size: var(--fs-xs); color: var(--muted); }

.featured-section { padding-block: var(--sp-8); }
.business-section { padding-block: var(--sp-10); background: var(--canvas); }
.business-layout { display: grid; gap: var(--sp-8); align-items: center; }
.business-copy h2 { margin-bottom: var(--sp-4); }
.business-copy h2 span { color: var(--brand); }
.business-copy ul { display: grid; gap: 10px; margin-bottom: var(--sp-5); }
.business-copy li { display: flex; align-items: center; gap: 10px; font-size: var(--fs-sm); color: var(--ink-2); }
.business-copy li svg { width: 18px; height: 18px; color: var(--green); flex: none; }
.learn-more { display: inline-flex; align-items: center; gap: 4px; font-size: var(--fs-sm); font-weight: 600; }

.dashboard-card { display: grid; overflow: hidden; min-width: 0; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg); box-shadow: var(--shadow-lg); }
.dashboard-sidebar { display: none; }
.dashboard-main { padding: var(--sp-4); min-width: 0; }
.dashboard-topline { display: flex; justify-content: flex-end; margin-bottom: var(--sp-3); }
.dashboard-topline button { padding: 6px 12px; border-radius: var(--r-sm); border: 1px solid var(--line); font-size: var(--fs-xs); font-weight: 600; color: var(--muted); }
.metric-grid article { display: grid; gap: 2px; padding: var(--sp-3); background: var(--canvas); border-radius: var(--r-sm); }
.metric-grid span { font-size: var(--fs-xs); color: var(--muted); }
.metric-grid strong { font-size: var(--fs-lg); letter-spacing: -.02em; }
.metric-grid small { font-size: var(--fs-xs); color: var(--green-600); font-weight: 600; }

.analytics-grid { display: grid; gap: var(--sp-3); margin-top: var(--sp-3); }
.line-chart-card, .source-card { padding: var(--sp-4); background: var(--canvas); border-radius: var(--r); min-width: 0; }
.line-chart-card h4, .source-card h4 { font-size: var(--fs-sm); margin-bottom: var(--sp-3); }
.line-chart-card svg { width: 100%; height: auto; }
.chart-area { fill: url(#areaFill); stroke: none; }
.chart-line { stroke: var(--brand); stroke-width: 2.5; fill: none; }
.grid-line { stroke: var(--line); stroke-width: 1; }
/* --muted, not --muted-2: these are axis labels, i.e. real text under 1.4.3.
   --muted-2 renders them at 2.56:1 on white, well under the 4.5:1 minimum. */
.line-chart-card text { font-size: 10px; fill: var(--muted); stroke: none; }
.source-card > div { display: grid; grid-template-columns: 1fr auto; gap: 4px 8px; align-items: center; margin-bottom: 10px; }
.source-card span { font-size: var(--fs-xs); color: var(--muted); }
.source-card strong { font-size: var(--fs-xs); }
.source-card i { grid-column: 1 / -1; height: 6px; border-radius: var(--r-full); background: var(--line); position: relative; overflow: hidden; }
.source-card i::after { content: ""; position: absolute; inset: 0 auto 0 0; width: var(--width, 0%); background: var(--brand); border-radius: inherit; }

.ai-section { padding-block: var(--sp-10); }
.ai-trust-layout { display: grid; gap: var(--sp-8); align-items: center; }
.ai-copy > p { color: var(--muted); margin-block: var(--sp-3) var(--sp-5); }
.testimonial-strip { display: grid; gap: var(--sp-3); }
.avatar { display: grid; place-items: center; width: 40px; height: 40px; border-radius: 50%; font-size: var(--fs-xs); font-weight: 700; color: #fff; }
.avatar-one { background: var(--brand); }
.avatar-two { background: var(--green); }
.avatar-three { background: var(--purple); }

.app-section, .app-promo { padding-block: var(--sp-10); }
.app-card, .app-promo-inner {
  position: relative; overflow: hidden;
  display: grid; gap: var(--sp-6); align-items: center; padding: var(--sp-8) var(--sp-6);
  background:
    radial-gradient(90% 120% at 12% 0%, rgba(23,105,255,.10) 0%, rgba(23,105,255,0) 55%),
    linear-gradient(135deg, var(--brand-50), #f2fbf6 65%, var(--green-50));
  border: 1px solid var(--line); border-radius: var(--r-xl);
}
.app-promo-inner > img { width: 100%; max-width: 300px; margin-inline: auto; }

/* --- CSS phone, replacing the app-phones.jpg screenshot ------------------- */
.app-stage {
  position: relative; display: grid; place-items: center;
  perspective: 1200px; padding-block: var(--sp-4);
}
/* Brand-tinted pool of light behind the device. */
.app-glow {
  position: absolute; width: 320px; height: 320px; border-radius: 50%;
  background: radial-gradient(circle, rgba(23,105,255,.28) 0%, rgba(23,105,255,0) 68%);
  filter: blur(6px);
}
.app-phone {
  position: relative; width: 236px; padding: 9px;
  border-radius: 34px;
  background: linear-gradient(155deg, #2b3648, #0f172a 45%, #1e293b);
  box-shadow:
    0 40px 70px -24px rgba(15,23,42,.55),
    0 12px 24px -10px rgba(15,23,42,.4),
    inset 0 1px 0 rgba(255,255,255,.22);
  transform: rotateX(9deg) rotateY(-14deg) rotateZ(1.5deg);
  transform-style: preserve-3d;
  animation: phoneFloat 8s ease-in-out infinite;
}
.app-phone-notch {
  position: absolute; left: 50%; top: 15px; transform: translateX(-50%);
  width: 62px; height: 5px; border-radius: 3px; background: rgba(255,255,255,.28); z-index: 3;
}
.app-phone-screen {
  display: grid; gap: 7px; padding: 22px 9px 12px;
  border-radius: 26px; background: var(--canvas); overflow: hidden;
}
.app-screen-bar {
  display: flex; align-items: center; gap: 6px;
  padding: 7px 9px; border-radius: var(--r-full);
  background: #fff; box-shadow: var(--shadow-xs);
}
.app-screen-pin { display: grid; place-items: center; color: var(--brand); }
.app-screen-pin svg { width: 13px; height: 13px; }
.app-screen-field { font-size: 10.5px; font-weight: 600; color: var(--muted); }
.app-screen-map {
  position: relative; height: 104px; border-radius: 14px; overflow: hidden;
  background-color: #e8eefb;
  background-image:
    linear-gradient(to right, rgba(255,255,255,.9) 2px, transparent 2px),
    linear-gradient(to bottom, rgba(255,255,255,.9) 2px, transparent 2px);
  background-size: 26px 26px;
}
.app-screen-route {
  position: absolute; left: 12%; top: 62%; width: 68%; height: 3px; border-radius: 3px;
  background: var(--brand); opacity: .5; transform: rotate(-16deg);
}
.app-screen-dot {
  position: absolute; left: var(--x); top: var(--y);
  width: 13px; height: 13px; margin: -13px 0 0 -6px;
  border-radius: 50% 50% 50% 0; transform: rotate(-45deg);
  background: var(--tone); border: 2px solid #fff;
  box-shadow: 0 2px 5px rgba(15,23,42,.35);
}
.app-screen-me {
  position: absolute; left: 50%; top: 74%; width: 10px; height: 10px; margin: -5px 0 0 -5px;
  border-radius: 50%; background: var(--brand); border: 2px solid #fff;
  box-shadow: 0 0 0 5px rgba(23,105,255,.22);
}
.app-screen-row {
  display: flex; align-items: center; gap: 7px;
  padding: 6px 7px; border-radius: 11px; background: #fff; box-shadow: var(--shadow-xs);
}
.app-screen-glyph {
  display: grid; place-items: center; width: 24px; height: 24px; flex: none;
  border-radius: 7px; background: var(--line-2); font-size: 12px;
}
.app-screen-text { display: flex; flex-direction: column; min-width: 0; }
.app-screen-text strong {
  font-size: 10.5px; font-weight: 700; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.app-screen-text small { font-size: 9px; color: var(--muted); }

@keyframes phoneFloat {
  0%, 100% { transform: rotateX(9deg) rotateY(-14deg) rotateZ(1.5deg) translateY(0); }
  50%      { transform: rotateX(6deg) rotateY(-9deg)  rotateZ(.5deg)  translateY(-14px); }
}

/* --- copy column --------------------------------------------------------- */
.app-copy h2 { font-size: var(--fs-2xl); }
.app-copy > p { color: var(--ink-2); margin-block: var(--sp-2) var(--sp-5); max-width: 46ch; }
.app-benefits, .check-list { display: grid; gap: 9px; }
.app-benefits span, .check-list span { display: flex; align-items: center; gap: 8px; font-size: var(--fs-sm); color: var(--ink-2); }
.app-benefits svg { width: 16px; height: 16px; color: var(--green); flex: none; }

.app-platforms {
  display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4);
  margin-top: var(--sp-5); padding-top: var(--sp-4);
  border-top: 1px solid rgba(15,23,42,.08);
}
.app-platforms span {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--fs-xs); font-weight: 600; color: var(--ink-2);
}
.app-platforms svg { width: 14px; height: 14px; color: var(--brand); flex: none; }

@media (prefers-reduced-motion: reduce) {
  .app-phone { animation: none; }
}

/* --------------------------------------------------------- CTA bands ----- */
.final-cta, .global-cta { padding-block: var(--sp-8); }
.cta-inner, .global-cta-inner {
  display: grid; gap: var(--sp-4); align-items: center; justify-items: center; text-align: center;
  padding: var(--sp-6); border-radius: var(--r-xl); color: #fff;
  background: linear-gradient(120deg, var(--brand), var(--green-600));
}
.cta-inner h2, .global-cta-inner h2 { font-size: var(--fs-xl); color: #fff; }
.cta-inner p, .global-cta-inner p { font-size: var(--fs-sm); color: rgba(255,255,255,.9); }
.cta-pin, .cta-icon { display: grid; place-items: center; width: 46px; height: 46px; border-radius: var(--r); background: rgba(255,255,255,.2); color: #fff; }
.cta-actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); justify-content: center; }

/* ------------------------------------------------------------ footer ----- */
.site-footer {
  position: relative; isolation: isolate; overflow: hidden;
  padding-block: var(--sp-12) var(--sp-5);
  background: linear-gradient(180deg, #0b1220 0%, var(--ink) 40%, #0a1020 100%);
  color: rgba(255,255,255,.72);
}
/* Two slow-drifting colour blooms give the slab depth without an image. */
.footer-aurora { position: absolute; inset: 0; z-index: -2; pointer-events: none; }
.footer-aurora i {
  position: absolute; display: block; border-radius: 50%;
  filter: blur(70px); opacity: .5;
}
.footer-aurora i:nth-child(1) {
  width: 520px; height: 520px; left: -8%; top: -40%;
  background: radial-gradient(circle, rgba(23,105,255,.62), rgba(23,105,255,0) 70%);
  animation: auroraDrift 22s ease-in-out infinite alternate;
}
.footer-aurora i:nth-child(2) {
  width: 460px; height: 460px; right: -6%; bottom: -45%;
  background: radial-gradient(circle, rgba(16,185,129,.45), rgba(16,185,129,0) 70%);
  animation: auroraDrift 27s ease-in-out infinite alternate-reverse;
}
/* The same receding grid as the hero, tying the footer back to the map product. */
.footer-grid-tex {
  position: absolute; inset: -30% -20% auto; height: 70%; z-index: -1; pointer-events: none;
  background-image:
    linear-gradient(to right, rgba(255,255,255,.05) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255,255,255,.05) 1px, transparent 1px);
  background-size: 54px 54px;
  transform: perspective(700px) rotateX(58deg);
  mask-image: linear-gradient(180deg, transparent, #000 45%, transparent);
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 45%, transparent);
}
@keyframes auroraDrift {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(60px, 30px, 0) scale(1.18); }
}

/* h3, not h4 — the CTA above the footer is an h2, and jumping straight to h4
   skips a level for screen-reader users. Styled down to look like a label. */
.site-footer h3 { color: #fff; font-size: var(--fs-sm); margin-bottom: var(--sp-3); }

/* --- brand + columns ----------------------------------------------------- */
.footer-grid { display: grid; gap: var(--sp-6); }
.footer-brand p { font-size: var(--fs-sm); margin-block: var(--sp-4); max-width: 40ch; }
.footer-brand .brand-text small { display: block; color: rgba(255,255,255,.5); }

.social-links { display: flex; gap: 10px; }
.social-links a {
  display: grid; place-items: center; width: 38px; height: 38px;
  border-radius: 12px; color: rgba(255,255,255,.85);
  background: rgba(255,255,255,.08); border: 1px solid rgba(255,255,255,.1);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.12);
  transition: transform .24s var(--ease-out), background .2s var(--ease),
              box-shadow .24s var(--ease), color .2s var(--ease);
}
.social-links a svg { width: 17px; height: 17px; }
.social-links a:hover {
  color: #fff; background: var(--brand);
  transform: translateY(-4px) rotate(-6deg);
  box-shadow: var(--shadow-brand-lg), inset 0 1px 0 rgba(255,255,255,.3);
}

.footer-column { display: grid; gap: 10px; align-content: start; }
.footer-column h3 { position: relative; padding-bottom: var(--sp-2); }
.footer-column h3::after {
  content: ''; position: absolute; left: 0; bottom: 0;
  width: 22px; height: 2px; border-radius: 2px; background: var(--brand);
}
.footer-column a {
  position: relative; width: fit-content;
  font-size: var(--fs-sm); color: rgba(255,255,255,.68);
  transition: color .18s var(--ease), transform .18s var(--ease-out);
}
.footer-column a:hover { color: #fff; transform: translateX(4px); }

.footer-bottom {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); flex-wrap: wrap;
  padding-top: var(--sp-5); margin-top: var(--sp-8);
  border-top: 1px solid rgba(255,255,255,.12); font-size: var(--fs-xs);
}
.footer-bottom-links { display: flex; gap: var(--sp-4); }
.footer-bottom-links a { color: rgba(255,255,255,.66); }
.footer-bottom-links a:hover { color: #fff; }
.language-switcher {
  display: inline-flex; align-items: center; gap: 6px; padding: 8px 13px;
  border-radius: var(--r-full); background: rgba(255,255,255,.08);
  border: 1px solid rgba(255,255,255,.12);
  color: rgba(255,255,255,.8); font-size: var(--fs-xs);
  transition: background .18s var(--ease), color .18s var(--ease);
}
.language-switcher:hover { background: rgba(255,255,255,.16); color: #fff; }
.language-switcher svg { width: 14px; height: 14px; }

@media (prefers-reduced-motion: reduce) {
  .footer-aurora i { animation: none; }
}

/* -------------------------------------------------------- claim dialog --- */
.claim-trigger {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  padding: 12px 14px; border-radius: var(--r);
  background: var(--brand-50); border: 1px dashed var(--brand-200);
  color: var(--brand-700); font-size: var(--fs-sm); font-weight: 700;
  transition: background .18s var(--ease), border-color .18s var(--ease), transform .18s var(--ease-out);
}
.claim-trigger:hover { background: var(--brand-100); border-style: solid; transform: translateY(-1px); }
.claim-trigger svg { width: 18px; height: 18px; flex: none; }
.claim-trigger small { display: block; font-size: var(--fs-xs); font-weight: 500; color: var(--brand); }

.claim-dialog {
  /* margin:auto is what centres a modal <dialog> in the top layer. The global
     `* { margin: 0 }` reset wipes the UA default, so it must be restated or the
     dialog pins itself to the top-left corner. */
  margin: auto;
  position: relative;
  width: min(460px, calc(100vw - 32px)); padding: var(--sp-6);
  border: 1px solid var(--line); border-radius: var(--r-xl);
  background: var(--surface); color: var(--ink);
  box-shadow: var(--shadow-xl);
}
.claim-dialog::backdrop { background: rgba(15,23,42,.55); backdrop-filter: blur(3px); }
.claim-dialog[open] { animation: claimIn .26s var(--ease-out); }
@keyframes claimIn {
  from { opacity: 0; transform: translateY(12px) scale(.96); }
  to   { opacity: 1; transform: none; }
}
.claim-dialog-close {
  position: absolute; top: 12px; right: 12px;
  display: grid; place-items: center; width: 34px; height: 34px;
  border-radius: 50%; background: var(--canvas); color: var(--muted);
  transition: background .16s var(--ease), color .16s var(--ease), transform .2s var(--ease);
}
.claim-dialog-close:hover { background: var(--red-50); color: var(--red-text); transform: rotate(90deg); }
.claim-dialog-close svg { width: 16px; height: 16px; }
.claim-dialog-icon {
  display: grid; place-items: center; width: 48px; height: 48px; margin-bottom: var(--sp-3);
  border-radius: 14px; color: #fff;
  background: linear-gradient(145deg, var(--brand-400), var(--brand) 50%, var(--brand-700));
  box-shadow: var(--shadow-brand);
}
.claim-dialog-icon svg { width: 24px; height: 24px; }
.claim-dialog h2 { font-size: var(--fs-xl); }
.claim-dialog-lead { margin-top: var(--sp-2); font-size: var(--fs-sm); color: var(--ink-2); }

.claim-dialog-mail {
  display: flex; align-items: center; gap: 11px;
  margin-top: var(--sp-4); padding: 12px 14px; border-radius: var(--r);
  background: var(--brand-50); border: 1px solid var(--brand-100); color: var(--brand-700);
}
.claim-dialog-mail:hover { background: var(--brand-100); color: var(--brand-700); }
.claim-dialog-mail svg { width: 20px; height: 20px; flex: none; }
.claim-dialog-mail small { display: block; font-size: var(--fs-xs); color: var(--brand); font-weight: 600; }
.claim-dialog-mail strong { font-size: var(--fs-md); letter-spacing: -.01em; word-break: break-all; }

.claim-dialog-what { margin-top: var(--sp-4); }
.claim-dialog-what strong { font-size: var(--fs-xs); font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
/* list-style restated: the base stylesheet strips bullets from every ul. */
.claim-dialog-what ul { margin: var(--sp-2) 0 0; padding-left: 20px; display: grid; gap: 4px; list-style: disc; }
.claim-dialog-what li { font-size: var(--fs-sm); color: var(--ink-2); }
.claim-dialog-what li::marker { color: var(--brand); }

.claim-dialog-actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-5); }

@media (prefers-reduced-motion: reduce) {
  .claim-dialog[open] { animation: none; }
}

/* ------------------------------------------------------------- toast ----- */
.toast {
  position: fixed; left: 50%; bottom: 24px; transform: translate(-50%, 160%); z-index: 300;
  padding: 12px 20px; border-radius: var(--r-full); max-width: calc(100vw - 32px);
  background: var(--ink); color: #fff; font-size: var(--fs-sm); font-weight: 500;
  box-shadow: var(--shadow-lg); transition: transform .3s cubic-bezier(.2,.9,.3,1);
}
.toast.show { transform: translate(-50%, 0); }

/* ==========================================================================
   BREAKPOINTS — min-width only
   ========================================================================== */

@media (min-width: 600px) {
  .search-box { grid-template-columns: 1fr auto; align-items: center; }
  .search-box .search-query-control { grid-column: 1 / -1; }
  .search-button { width: auto; }
  .search-actions { grid-template-columns: auto auto; }
  .hero-stats { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .horizontal-card { grid-template-columns: 190px 1fr; align-items: start; }
  .horizontal-card-media { height: 100%; }
  .horizontal-card-media .listing-media { height: 100%; aspect-ratio: auto; min-height: 150px; }
  .analytics-grid { grid-template-columns: 1.6fr 1fr; }
  .app-card, .app-promo-inner { grid-template-columns: 1fr 1fr; }
  .cta-inner, .global-cta-inner { grid-template-columns: auto 1fr auto; text-align: left; justify-items: start; }
  .footer-grid { grid-template-columns: repeat(2, 1fr); }
  .two-column-content { grid-template-columns: 1fr 1fr; }
  .reviews-layout { grid-template-columns: 230px 1fr; }
  .rating-summary { grid-row: span 3; }
  .area-map { grid-template-columns: 1fr 1fr; }
}@media (min-width: 768px) {
  :root { --header-h: 68px; }
  .wide-search { grid-template-columns: 1.4fr 1fr auto; align-items: center; }
  .search-box { grid-template-columns: 1.5fr 1px 1fr auto; }
  .search-box .search-query-control { grid-column: auto; }
  .search-separator { display: block; width: 1px; height: 30px; background: var(--line); }
  .hero { padding-block: var(--sp-12) var(--sp-16); }
  .category-hero-grid, .business-layout, .ai-trust-layout { grid-template-columns: 1fr 1fr; }
  .city-hero .site-container { grid-template-columns: 1.15fr .85fr; align-items: center; }
  .two-panel { grid-template-columns: .85fr 1.15fr; }
  /* .add-hero-grid / .onboarding-grid / .plan-layout removed here too — see the
     "add business" note above. */
  .footer-grid { grid-template-columns: repeat(3, 1fr); }
  .testimonial-strip { grid-template-columns: repeat(3, 1fr); }
  .dashboard-card { grid-template-columns: 168px 1fr; }
  .dashboard-sidebar { display: grid; gap: 2px; align-content: start; padding: var(--sp-4); background: var(--canvas); border-right: 1px solid var(--line); }
  .dashboard-sidebar strong { font-size: var(--fs-xs); color: var(--muted); margin-bottom: var(--sp-2); }
  .dashboard-sidebar a { padding: 8px 10px; border-radius: var(--r-sm); font-size: var(--fs-xs); font-weight: 600; color: var(--ink-2); }
  .dashboard-sidebar a.active { background: var(--brand); color: #fff; }
}
@media (min-width: 1024px) {
  /* ---- header becomes an inline rail with floating mega-menus ---- */
  .nav-toggle, .nav-backdrop, .nav-drawer-head { display: none !important; }
  .brand-text small { display: block; }

  .primary-nav {
    display: flex; align-items: center; gap: 2px;
    position: static; inset: auto; width: auto; transform: none;
    padding: 0; background: none; box-shadow: none;
    overflow: visible; overscroll-behavior: auto;
  }
  .primary-nav .nav-cta { display: none; }
  .nav-list { grid-auto-flow: column; gap: 2px; align-items: center; }

  /* nowrap on both: "For Business" and the brand sub-label were breaking onto a
     second line and pushing the bar out of its 68px height. */
  .nav-link {
    padding: 8px 12px; border-radius: var(--r-btn); gap: 7px;
    font-size: var(--fs-sm); font-weight: 600; white-space: nowrap;
  }
  .brand-text small { white-space: nowrap; }
  /* The icon chips are drawer affordances — on desktop the label carries it. */
  .nav-link-icon { display: none; }
  .nav-link .nav-caret { margin-left: 1px; }
  .nav-link .nav-caret svg { width: 13px; height: 13px; }

  /* Active pill + underline bar: colour alone was too quiet at this size. */
  .nav-link.active { background: var(--brand-50); color: var(--brand-700); }
  .nav-link.active::after {
    content: ''; position: absolute; left: 50%; bottom: -1px;
    width: 18px; height: 3px; border-radius: 3px 3px 0 0;
    background: var(--brand); transform: translateX(-50%);
  }
  .nav-item { display: flex; }
  .nav-details { position: relative; }

  /* Floating panel. Hover on desktop, plus [open] for keyboard/touch. */
  .nav-panel {
    position: absolute; top: calc(100% + 12px); left: 50%; z-index: 130;
    width: max-content; min-width: 320px; max-width: 560px;
    padding: var(--sp-4); border-radius: var(--r-lg);
    background: var(--surface); border: 1px solid var(--line);
    box-shadow: var(--shadow-xl);
    opacity: 0; visibility: hidden;
    transform: translateX(-50%) translateY(-8px) scale(.98);
    transition: opacity .2s var(--ease), transform .26s var(--ease-out), visibility .2s;
  }
  /* Invisible bridge so the pointer can cross the 12px gap without closing. */
  .nav-panel::before { content: ''; position: absolute; left: 0; right: 0; top: -14px; height: 14px; }
  .nav-details[open] > .nav-panel,
  .nav-item.has-panel:hover .nav-panel,
  .nav-item.has-panel:focus-within .nav-panel {
    opacity: 1; visibility: visible; transform: translateX(-50%) translateY(0) scale(1);
  }

  .nav-panel-head { display: block; margin-bottom: var(--sp-3); }
  .nav-panel-head strong { display: block; font-size: var(--fs-sm); font-weight: 700; color: var(--ink); }
  .nav-panel-head span { font-size: var(--fs-xs); color: var(--muted); }
  .nav-panel-grid { grid-template-columns: repeat(2, minmax(150px, 1fr)); gap: 2px; }
  .nav-panel-grid-cities { grid-template-columns: repeat(2, minmax(140px, 1fr)); }
  .nav-panel-foot {
    width: 100%; justify-content: space-between;
    margin-top: var(--sp-3); padding-top: var(--sp-3);
    border-top: 1px solid var(--line); border-radius: 0;
  }
  .nav-panel-foot:hover { background: none; }

  /* brand{margin-right:auto} + this split the slack evenly, so the nav sits
     optically centred between the brand and the actions. */
  .header-actions { display: flex; align-items: center; gap: var(--sp-2); flex: none; margin-left: auto; }

  .hero h1 { font-size: clamp(2.4rem, 1.6rem + 2.6vw, 3.6rem); }
  .search-layout { grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr); align-items: start; }
  .sticky-map { position: sticky; top: calc(var(--header-h) + 16px); height: calc(100dvh - var(--header-h) - 32px); }
  .results-layout { grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); align-items: start; }
  .results-map-card { position: sticky; top: calc(var(--header-h) + 16px); height: 620px; }
  .business-hero-grid { grid-template-columns: minmax(0, 1fr) 330px; }
  /* 6 children (brand + 5 link columns) in exactly 6 tracks. */
  .footer-grid { grid-template-columns: 1.75fr repeat(5, 1fr); }

}
@media print {
  .site-header, .site-footer, .business-tabs, .sticky-map,
  .filter-row, .toast, .global-cta, .final-cta { display: none !important; }
  body { background: #fff; }
  .content-card { break-inside: avoid; border-color: #ccc; }
}


/* ---------------------------------------------- city page, text-first ---- */
/* Stock photography came out with the listing images; these carry the same
   sections on type, counts and a single glyph instead. */
.city-figure {
  display: grid; gap: 4px; align-content: center; justify-items: center;
  padding: var(--sp-6) var(--sp-4); text-align: center;
  border: 1px solid var(--line); border-radius: var(--r-lg);
  background: linear-gradient(150deg, var(--brand-50), var(--green-50));
}
.city-figure-glyph { font-size: 2.6rem; line-height: 1; }
.city-figure strong { font-size: var(--fs-3xl); line-height: 1; letter-spacing: -.03em; color: var(--brand); }
.city-figure > span { font-size: var(--fs-sm); color: var(--ink-2); }
.city-figure p { font-size: var(--fs-xs); color: var(--muted); margin-top: var(--sp-2); }

.area-tiles { display: grid; gap: var(--sp-2); grid-template-columns: repeat(auto-fill, minmax(min(100%, 170px), 1fr)); }
.area-tile {
  display: grid; gap: 2px; padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--line); border-radius: var(--r); background: var(--surface);
  transition: border-color .18s, box-shadow .18s, transform .18s;
}
.area-tile:hover { border-color: var(--brand-200); box-shadow: var(--shadow); transform: translateY(-2px); }
.area-tile strong { font-size: var(--fs-sm); color: var(--ink); }
.area-tile span { font-size: var(--fs-xs); color: var(--muted); }

.collection-glyph, .article-kicker { display: block; padding: var(--sp-4) var(--sp-4) 0; }
.collection-glyph { font-size: 1.9rem; line-height: 1; }
.article-kicker { font-size: var(--fs-xs); font-weight: 700; color: var(--brand-700); }

/* =========================================================================
   CATEGORY DIRECTORY — 3D icon tiles
   The "3D" is pure CSS: a perspective-tilted plate with stacked shadows for
   depth, a gloss highlight, an emoji lifted on its own Z plane with a cast
   shadow, and a tilt-on-hover. No icon pack, no image requests, and it stays
   sharp at any DPI.
   ========================================================================= */
.cat-hero { padding-block: var(--sp-8) var(--sp-4); background: linear-gradient(180deg, var(--brand-50), rgba(255,255,255,0)); }
.cat-hero h1 { margin-bottom: var(--sp-2); }
.cat-hero-sub { color: var(--muted); font-size: var(--fs-lg); margin-bottom: var(--sp-5); }

.cat-filter {
  display: flex; align-items: center; gap: 10px;
  max-width: 520px; padding: 4px 4px 4px 14px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-full); box-shadow: var(--shadow-sm);
}
.cat-filter svg { width: 18px; height: 18px; color: var(--muted); flex: none; }
.cat-filter input { border: 0; background: none; min-height: 42px; }
.cat-filter input:focus { box-shadow: none; }
.cat-filter:focus-within { border-color: var(--brand); box-shadow: var(--ring); }



@keyframes catRise {
  from { opacity: 0; transform: translateY(14px) scale(.98); }
  to   { opacity: 1; transform: none; }
}


/* =========================================================================
   ICON 3D SYSTEM
   A glossy squircle badge: saturated core, rim light, coloured glow beneath,
   and the glyph floating on its own Z plane. Idle it breathes and catches a
   light sweep; on hover it pops forward and shakes once. Shared with
   .listing-avatar so a category reads the same everywhere on the site.
   ========================================================================= */
.cat-icon {
  position: relative; flex: none;
  width: 62px; height: 62px;
  display: grid; place-items: center;
  border-radius: 30%;                       /* squircle, not a rounded box */
  background:
    radial-gradient(115% 95% at 26% 16%, hsl(var(--hue,220) 100% 98%) 0%, transparent 52%),
    linear-gradient(158deg,
      hsl(var(--hue,220) 95% 84%) 0%,
      hsl(var(--hue,220) 85% 70%) 48%,
      hsl(calc(var(--hue,220) + 22) 78% 58%) 100%);
  box-shadow:
    inset 0 2px 0 hsl(var(--hue,220) 100% 96%),            /* rim light */
    inset 0 -3px 0 hsl(calc(var(--hue,220) + 18) 60% 46%), /* under-bevel */
    0 5px 0 hsl(calc(var(--hue,220) + 18) 52% 56%),        /* extruded edge */
    0 12px 20px -6px hsl(var(--hue,220) 65% 42% / .55),    /* cast shadow */
    0 0 26px -6px hsl(var(--hue,220) 90% 60% / .5);        /* coloured glow */
  transform: perspective(420px) rotateX(10deg);
  transform-style: preserve-3d;
  transition: transform .3s cubic-bezier(.2,.9,.3,1), box-shadow .3s;
  animation: iconBreathe 4.5s ease-in-out infinite;
  animation-delay: var(--delay, 0s);
}

/* Light sweep across the face, staggered so the grid glints in sequence. */
.cat-icon::after {
  content: ""; position: absolute; inset: 0; z-index: 1; border-radius: inherit;
  background: linear-gradient(105deg, transparent 42%, rgba(255,255,255,.95) 50%, transparent 58%);
  background-size: 300% 100%; background-position: 160% 0;
  animation: iconFlash 6s ease-in-out infinite;
  animation-delay: var(--delay, 0s);
  pointer-events: none;
}

.cat-icon-face {
  position: relative; z-index: 2;
  font-size: 30px; line-height: 1;
  transform: translateZ(20px);
  filter: drop-shadow(0 3px 2px hsl(var(--hue,220) 60% 32% / .5));
  transition: transform .3s cubic-bezier(.2,.9,.3,1);
}

/* Hover: pops toward you, shakes once, glow intensifies. */
.cat-card:hover .cat-icon {
  animation: iconShake .55s ease-in-out;
  box-shadow:
    inset 0 2px 0 hsl(var(--hue,220) 100% 97%),
    inset 0 -3px 0 hsl(calc(var(--hue,220) + 18) 60% 44%),
    0 8px 0 hsl(calc(var(--hue,220) + 18) 52% 54%),
    0 20px 28px -8px hsl(var(--hue,220) 65% 40% / .6),
    0 0 40px -4px hsl(var(--hue,220) 95% 62% / .75);
}
.cat-card:hover .cat-icon-face { transform: translateZ(36px) scale(1.14); }

/* Press: the extrusion collapses, like a key bottoming out. */
.cat-card:active .cat-icon {
  animation: none;
  transform: perspective(420px) rotateX(10deg) translateY(4px) scale(.96);
  box-shadow:
    inset 0 2px 0 hsl(var(--hue,220) 100% 96%),
    0 1px 0 hsl(calc(var(--hue,220) + 18) 52% 56%),
    0 4px 9px -4px hsl(var(--hue,220) 65% 42% / .5);
}

/* --- the shared keyframes ------------------------------------------------ */
/* Idle: a slow tilt-and-lift so the grid feels alive without pulling focus. */
@keyframes iconBreathe {
  0%, 100% { transform: perspective(420px) rotateX(10deg) rotateY(-5deg) translateY(0); }
  50%      { transform: perspective(420px) rotateX(4deg) rotateY(5deg) translateY(-3px); }
}

/* Flash: the sweep crosses quickly, then waits — a glint, not a strobe. */
@keyframes iconFlash {
  0%, 72%, 100% { background-position: 160% 0; }
  86%           { background-position: -60% 0; }
}

/* Shake: a damped wobble that settles, rather than a constant jitter. */
@keyframes iconShake {
  0%   { transform: perspective(420px) rotateX(-6deg) rotateZ(0deg) scale(1.08); }
  20%  { transform: perspective(420px) rotateX(-6deg) rotateZ(-9deg) scale(1.1); }
  40%  { transform: perspective(420px) rotateX(-6deg) rotateZ(7deg) scale(1.1); }
  60%  { transform: perspective(420px) rotateX(-6deg) rotateZ(-5deg) scale(1.09); }
  80%  { transform: perspective(420px) rotateX(-6deg) rotateZ(3deg) scale(1.08); }
  100% { transform: perspective(420px) rotateX(-6deg) rotateZ(0deg) scale(1.08); }
}


.cat-noresults { padding: var(--sp-8) 0; text-align: center; color: var(--muted); font-size: var(--fs-sm); }

/* The tilt and the entrance are decoration, not information. */
@media (prefers-reduced-motion: reduce) {
  /* Keep the 3D depth — it is static shading — but stop everything that moves. */
  .cat-card,
  .cat-icon, .cat-icon::after,
  .listing-avatar, .listing-avatar::after,
  .cat-card:hover .cat-icon,
  .listing-row:hover .listing-avatar,
  .listing-tile:hover .listing-avatar { animation: none; }
  .cat-icon, .cat-icon-face,
  .listing-avatar, .listing-avatar-face { transition: none; }
  .cat-icon { transform: perspective(420px) rotateX(10deg); }
  .cat-card:hover .cat-icon-face { transform: translateZ(20px); }
  .listing-row:hover .listing-avatar-face,
  .listing-tile:hover .listing-avatar-face { transform: translateZ(12px); }
}

/* --- flat category grid --------------------------------------------------- */
.cat-group { margin-bottom: var(--sp-8); }
.cat-group[hidden] { display: none; }
.cat-group-title {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-md); color: var(--ink-2);
  text-transform: uppercase; letter-spacing: .08em;
  margin-bottom: var(--sp-4);
}
.cat-group-title::after {
  content: ""; flex: 1; height: 1px; background: var(--line);
}
.cat-group-title span {
  order: 3; padding: 2px 9px; border-radius: var(--r-full);
  background: var(--line-2); color: var(--muted);
  font-size: var(--fs-xs); letter-spacing: 0;
}

.cat-grid {
  display: grid; gap: var(--sp-3);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 148px), 1fr));
}

.cat-card {
  display: grid; gap: 4px; justify-items: center; text-align: center;
  padding: var(--sp-4) var(--sp-2);
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
  transition: border-color .2s, box-shadow .2s, transform .2s;
  animation: catRise .5s cubic-bezier(.2,.8,.3,1) both;
}
.cat-card[hidden] { display: none; }
.cat-card:hover {
  border-color: hsl(var(--hue,220) 65% 76%);
  box-shadow: var(--shadow);
  transform: translateY(-3px);
}
.cat-card strong {
  font-size: var(--fs-sm); color: var(--ink); line-height: 1.25;
  margin-top: var(--sp-2);
}
.cat-card:hover strong { color: hsl(var(--hue,220) 58% 38%); }
.cat-card small { font-size: var(--fs-xs); color: var(--muted); }

/* ------------------------------------------------- live map (MapLibre) ---- */
/* NOTE: .mini-map-live is defined further down as a normal flex item. An
   earlier version of this block also set `position: absolute; inset: 0`, which
   the later rule never reset — so the canvas stayed absolutely positioned and
   the fallback plate rendered underneath it, showing the map twice. */

.map-pin-live {
  display: grid; place-items: center;
  width: 34px; height: 34px; cursor: pointer;
  border-radius: 50% 50% 50% 0; transform: rotate(-45deg);
  background: hsl(var(--hue,220) 70% 52%);
  border: 2px solid #fff;
  box-shadow: 0 3px 8px rgba(15,23,42,.35);
  transition: transform .15s, box-shadow .15s;
}
.map-pin-live span { transform: rotate(45deg); font-size: 15px; line-height: 1; }
.map-pin-live:hover { transform: rotate(-45deg) scale(1.15); box-shadow: 0 6px 14px rgba(15,23,42,.45); }

.map-me-live {
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--brand); border: 3px solid #fff;
  box-shadow: 0 0 0 4px rgba(23,105,255,.25), 0 2px 6px rgba(15,23,42,.3);
}

.maplibregl-popup-content {
  display: grid; gap: 2px; padding: 10px 13px;
  border-radius: var(--r-sm); box-shadow: var(--shadow);
  font-family: inherit;
}
.maplibregl-popup-content strong { font-size: var(--fs-sm); color: var(--ink); }
.maplibregl-popup-content span { font-size: var(--fs-xs); color: var(--muted); }

.map-pin-live:hover { z-index: 4; }

/* --- 3D hover card on the live map --------------------------------------- */
/* perspective sits on the popup wrapper so the content can swing in on its X
   axis; MapLibre owns the wrapper's translate, so only the content is animated. */
.listing-pop { perspective: 700px; z-index: 6; }
.listing-pop .maplibregl-popup-content {
  padding: 0; overflow: hidden;
  border-radius: var(--r-lg);
  background: rgba(255,255,255,.97);
  backdrop-filter: saturate(1.4) blur(10px);
  border: 1px solid rgba(255,255,255,.9);
  box-shadow:
    0 24px 48px -18px rgba(15,23,42,.42),
    0 6px 14px -6px rgba(15,23,42,.22),
    inset 0 1px 0 rgba(255,255,255,.9);
  transform-origin: 50% 100%;
  animation: popCard3d .32s cubic-bezier(.16,1,.3,1) both;
}
.listing-pop .maplibregl-popup-tip { border-top-color: rgba(255,255,255,.97); }

@keyframes popCard3d {
  from { opacity: 0; transform: translateY(10px) scale(.92) rotateX(-32deg); }
  to   { opacity: 1; transform: translateY(0)    scale(1)   rotateX(0deg); }
}

.pop-card { display: grid; gap: 9px; padding: 12px 13px 11px; }
.pop-head { display: flex; align-items: center; gap: 10px; }
.pop-glyph {
  display: grid; place-items: center; width: 38px; height: 38px; flex: none;
  border-radius: 12px; font-size: 18px; line-height: 1;
  background: hsl(var(--hue,220) 82% 96%);
  border: 1px solid hsl(var(--hue,220) 62% 86%);
  box-shadow: 0 4px 10px -4px hsl(var(--hue,220) 60% 50% / .5);
}
.pop-id { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pop-id strong { font-size: var(--fs-sm); font-weight: 700; color: var(--ink); line-height: 1.25; }
.pop-tick {
  display: inline-grid; place-items: center; width: 14px; height: 14px;
  border-radius: 50%; background: var(--brand); color: #fff;
  font-size: 9px; font-weight: 700; vertical-align: 1px;
}
.pop-id small { font-size: 11px; color: var(--muted); line-height: 1.3; }
.pop-row { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }
.pop-rating {
  display: inline-flex; align-items: center; gap: 3px;
  padding: 3px 8px; border-radius: var(--r-full);
  background: var(--amber-50); color: #92610a;
  font-size: 11px; font-weight: 700;
}
.pop-rating i { font-style: normal; font-weight: 600; opacity: .7; }
.pop-price {
  padding: 3px 8px; border-radius: var(--r-full);
  background: var(--line-2); color: var(--ink-2);
  font-size: 11px; font-weight: 700;
}
.pop-flag {
  padding: 3px 8px; border-radius: var(--r-full);
  background: var(--line-2); color: var(--muted);
  font-size: 11px; font-weight: 700;
}
.pop-flag.is-open { background: var(--green-50); color: var(--green-700); }

@media (prefers-reduced-motion: reduce) {
  .listing-pop .maplibregl-popup-content { animation-duration: .01ms; }
}

/* --- live map ------------------------------------------------------------- */
/*
 * The live canvas is a normal flex item, NOT absolutely positioned.
 *
 * Absolute + inset:0 depended on .mini-map being the containing block; when it
 * was not, the canvas sized itself to its min-height and the fallback plate
 * stayed visible underneath — the map rendered twice, with two sets of pins.
 * Sharing the flex column removes that whole class of bug.
 */
.mini-map { position: relative; isolation: isolate; }
.mini-map-live { flex: 1 1 auto; min-height: 300px; width: 100%; }
.mini-map-live .maplibregl-map { width: 100%; height: 100%; }

/* Once the real map is up, the CSS approximation must go — otherwise both are
   on screen at once, which is exactly what it looked like. */
.mini-map.has-live-map .mini-map-plate { display: none; }

/* When the map genuinely failed, say so rather than leaving a grid that looks
   like a design choice. */
.mini-map.map-failed .mini-map-plate::before {
  content: "Map unavailable — showing approximate positions";
  position: absolute; left: 50%; top: 10px; transform: translateX(-50%); z-index: 6;
  padding: 5px 12px; border-radius: var(--r-full);
  background: rgba(255,255,255,.95); border: 1px solid var(--line);
  font-size: var(--fs-xs); font-weight: 600; color: var(--muted); white-space: nowrap;
}

/* MapLibre injects its own controls; keep them on-brand and above the plate. */
.maplibregl-ctrl-group { border-radius: var(--r-sm) !important; box-shadow: var(--shadow-sm) !important; }
.city-map-frame {
  height: clamp(320px, 55vh, 520px);
  border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden;
}

/* --- related categories (category detail page) ---------------------------- */
.related-cats { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.related-cats a {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 6px 14px 6px 6px; border-radius: var(--r-full);
  background: var(--surface); border: 1px solid var(--line);
  font-size: var(--fs-sm); font-weight: 600; color: var(--ink-2);
  transition: border-color .18s, box-shadow .18s, transform .18s, color .18s;
}
.related-cats a:hover {
  border-color: hsl(var(--hue,220) 62% 78%);
  color: hsl(var(--hue,220) 55% 38%);
  box-shadow: var(--shadow-sm); transform: translateY(-2px);
}
/* Chip-scale badge: same 3D treatment, smaller. */
.related-cats .cat-icon { width: 34px; height: 34px; border-radius: 32%; }
.related-cats .cat-icon-face { font-size: 17px; transform: translateZ(12px); }

/* --- admin: inline category badge ---------------------------------------- */
.admin-cat-glyph, td .cat-icon {
  width: 30px; height: 30px; border-radius: 32%; vertical-align: middle;
}
td .cat-icon-face { font-size: 15px; transform: translateZ(10px); }

/* --- map wrappers without an explicit height ------------------------------ */
/* .category-aside and .nearby-map had none, so the live map had nothing to
   size against and collapsed to its min-height on those pages. */
.category-aside, .nearby-map {
  height: clamp(300px, 45vh, 460px);
  border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden;
}
@media (min-width: 768px) {
  .category-aside { height: clamp(340px, 50vh, 520px); }
}

/* --- map popup + controls ------------------------------------------------- */
.maplibregl-popup-content .popup-link {
  display: inline-block; margin-top: 6px;
  font-size: var(--fs-xs); font-weight: 700; color: var(--brand);
}
.maplibregl-popup-content .popup-link:hover { color: var(--brand-600); }

/* MapLibre stacks its controls; keep them on-brand and comfortably tappable. */
.maplibregl-ctrl-group button { width: 32px; height: 32px; }
@media (pointer: coarse) {
  .maplibregl-ctrl-group button { width: 40px; height: 40px; }
}
.maplibregl-ctrl-scale {
  border-color: var(--line); background: rgba(255,255,255,.9);
  font-size: var(--fs-xs); color: var(--muted); border-radius: 0 0 0 var(--r-sm);
}

/* The cooperative-gesture hint should read as ours, not as a browser default. */
.maplibregl-cooperative-gesture-screen {
  background: rgba(15,23,42,.55); backdrop-filter: blur(2px);
  font-family: inherit; font-size: var(--fs-sm); font-weight: 600;
}

/* =========================================================== auth pages ===
   Sign in, register, forgot password, reset password.

   These rules used to be two near-identical <style> blocks inlined in
   login.php and register.php. Consolidated here because forgot-password.php and
   reset-password.php need the same vocabulary and a third copy was not the
   answer — and because every inline <style> is a blocker for moving the CSP
   from Report-Only to enforce.
   ========================================================================= */

.auth-shell { max-width: 470px; margin-inline: auto; }
.auth-shell .content-card { display: grid; gap: var(--sp-4); }
.auth-shell h1 { font-size: var(--fs-xl); }

/* register.php carries a role chooser, so it needs the wider measure. */
.register-page .auth-shell { max-width: 560px; }

.auth-lede { color: var(--muted); font-size: var(--fs-sm); margin-top: 4px; }
.auth-alt  { text-align: center; font-size: var(--fs-sm); color: var(--muted); }
.auth-note { color: var(--muted); font-size: var(--fs-sm); }

/* Right-aligned under the password field, where the eye already is. */
.auth-forgot { text-align: right; font-size: var(--fs-sm); margin-top: -6px; }

/* --- confirmation / dead-end panels ------------------------------------- */
.auth-done { display: grid; gap: var(--sp-3); justify-items: center; text-align: center; }
.auth-done p { color: var(--ink-2); font-size: var(--fs-sm); max-width: 42ch; }
.auth-done-mark {
  width: 46px; height: 46px; display: grid; place-items: center;
  border-radius: 999px; background: var(--green-50, #e9f9f0); color: #047857;
  font-size: 22px; font-weight: 700; line-height: 1;
}
/* Not colour alone: the glyph changes too, so the failure state is legible
   without seeing the hue. */
.auth-done-mark.is-warn { background: #fff8e6; color: #b45309; }

.auth-actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); justify-content: center; }

/* --- field-level errors -------------------------------------------------- */
.field-error {
  display: block; margin-top: 6px;
  font-size: var(--fs-xs); font-weight: 500; color: #b91c1c;
}
.field-error[hidden] { display: none; }
label:has(> [aria-invalid="true"]) input { border-color: #b91c1c; }

/* --- register.php role chooser ------------------------------------------ */
.role-choice { display: grid; gap: var(--sp-2); }
.role-choice > label {
  display: flex; gap: var(--sp-3); align-items: flex-start; padding: 12px 14px;
  border: 1px solid var(--line); border-radius: var(--r-sm); cursor: pointer;
  font-weight: 500; color: var(--ink-2); min-height: 42px;
}
.role-choice > label:hover { border-color: var(--brand-200); background: var(--brand-50); }
.role-choice input {
  width: 18px; height: 18px; min-height: 0; margin-top: 3px;
  flex: none; accent-color: var(--brand);
}
.role-choice strong { display: block; font-size: var(--fs-sm); color: var(--ink); }
.role-choice small  { font-size: var(--fs-xs); color: var(--muted); }

/* .demo-box removed with the demo-credentials block in login.php — nothing
   renders it any more, and leaving the rule invites something to. */
.auth-legal { margin-top: var(--sp-4); }

/* ======================================================= locations page ===
   locations.php — countries -> regions -> cities -> listings.

   WHY THIS BLOCK DID NOT EXIST
   The page was added in the migration-010 locations cutover and shipped
   referencing a component set that was never written. Six of its classes were
   defined in NO stylesheet at all — .location-grid, .location-tile,
   .section-sub, .lede, .section-more and .empty-glyph — so the 252 country
   tiles on the root view and the 300 city tiles under a state rendered as bare
   stacked <a> elements running down the page. That is the layout fault: not a
   rule that needed tuning, a component that was never built.

   .stat-row had a subtler version of the same problem — see the note there.
   ========================================================================= */

/* --- page head ----------------------------------------------------------- */

.section-sub {
  color: var(--muted);
  font-size: var(--fs-sm);
  margin-top: 6px;
  max-width: 62ch;
}

.lede {
  color: var(--ink-2);
  font-size: var(--fs-md);
  line-height: 1.6;
  margin-top: var(--sp-3);
  max-width: 62ch;
}

.section-more { margin-top: var(--sp-5); }

/* --- the tile grid ------------------------------------------------------- */
/*
 * auto-fill, not auto-fit. With auto-fit a row holding one surviving tile
 * stretches it across the full container, so a state with a single city gets
 * one absurd 1100px-wide card. auto-fill keeps the empty tracks and the tile
 * keeps its natural size.
 */
.location-grid {
  display: grid;
  gap: var(--sp-3);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 210px), 1fr));
  margin-bottom: var(--sp-6);
}

.location-tile {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-height: 74px;
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  color: var(--ink);
  transition: border-color .15s ease, box-shadow .15s ease, transform .15s ease;
}
.location-tile:hover {
  text-decoration: none;
  border-color: var(--brand-200);
  box-shadow: 0 4px 14px rgba(15, 23, 42, .07);
  transform: translateY(-1px);
}
.location-tile:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}
.location-tile strong {
  font-size: var(--fs-sm);
  font-weight: 700;
  letter-spacing: -.01em;
  /* Place names run long ("Sri Potti Sriramulu Nellore"), and a name that
     overflows its tile drags the whole row's baseline out of alignment. */
  overflow-wrap: anywhere;
}
.location-tile span {
  font-size: var(--fs-xs);
  color: var(--muted);
}

/*
 * A location that actually has businesses is the one worth clicking, so it
 * carries a left accent and a tinted count. The accent is a border, not a
 * colour swap on the text, so the distinction survives greyscale and does not
 * rely on hue alone.
 */
.location-tile.is-live {
  border-left: 3px solid var(--brand);
  background: linear-gradient(180deg, var(--brand-50) 0%, var(--surface) 62%);
}
.location-tile.is-live span {
  color: var(--brand-700);
  font-weight: 600;
}

/*
 * The "everywhere else" list is reference material, not the call to action —
 * hundreds of rows a visitor scans rather than reads. Denser tracks and a
 * recessive surface keep it from competing with the list above it.
 */
.location-grid.is-quiet {
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 172px), 1fr));
  gap: var(--sp-2);
}
.location-grid.is-quiet .location-tile {
  min-height: 0;
  padding: 10px 13px;
  background: var(--canvas);
}
.location-grid.is-quiet .location-tile:hover { background: var(--surface); }
.location-grid.is-quiet .location-tile strong { font-size: var(--fs-xs); font-weight: 600; }

/* --- filter -------------------------------------------------------------- */
/*
 * Karnataka has 349 cities. A wall of 300 tiles with no way to narrow it is
 * not a browsing experience, so the list gets a filter. It is injected by
 * app.js and stays hidden without JavaScript, where the full list is still
 * completely usable — nothing is behind the filter.
 */
.location-filter {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-wrap: wrap;
  margin-bottom: var(--sp-4);
}
.location-filter input {
  flex: 1 1 260px;
  min-width: 0;
  min-height: 42px;
  padding: 10px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: var(--fs-sm);
}
.location-filter input:focus {
  outline: none;
  border-color: var(--brand);
  box-shadow: 0 0 0 3px rgba(22, 103, 252, .16);
}
.location-filter-count {
  font-size: var(--fs-xs);
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* Hidden by the filter. A separate class rather than inline display:none so
   the page never needs a style attribute (CSP). */
.location-tile.is-filtered { display: none; }

.location-empty {
  padding: var(--sp-5);
  text-align: center;
  color: var(--muted);
  font-size: var(--fs-sm);
  background: var(--canvas);
  border: 1px dashed var(--line);
  border-radius: var(--r);
  margin-bottom: var(--sp-6);
}

/* --- truncation notice --------------------------------------------------- */
/*
 * The query caps children at 300. Karnataka has 349, so 49 were silently
 * missing with nothing on the page admitting it. Saying so — and offering
 * search, which is not capped — is the honest fix.
 */
.location-note {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  padding: 12px 16px;
  margin-bottom: var(--sp-5);
  background: var(--amber-50, #fff8e6);
  border: 1px solid var(--amber-100, #fde3af);
  border-radius: var(--r);
  font-size: var(--fs-sm);
  color: var(--amber-700, #b45309);
}

/* --- empty state glyph --------------------------------------------------- */
.empty-glyph {
  font-size: 34px;
  line-height: 1;
  margin-bottom: var(--sp-2);
}

@media (max-width: 560px) {
  .location-grid { grid-template-columns: repeat(auto-fill, minmax(min(100%, 150px), 1fr)); }
  .location-grid.is-quiet { grid-template-columns: repeat(auto-fill, minmax(min(100%, 130px), 1fr)); }
}

@media (prefers-reduced-motion: reduce) {
  .location-tile { transition: none; }
  .location-tile:hover { transform: none; }
}

/* ==================================================== results mini-map ===
   Moved verbatim out of the <style> block that render_results_map() emitted
   inline in includes/public-queries.php. Its own comment asked for this.

   Two reasons it had to move: the partial is called from five pages
   (index, search, category, business, locations), so the same ~3KB was
   re-sent per page and re-parsed per call; and an inline <style> is a hard
   blocker for taking the CSP off Report-Only. Rules are unchanged.
   ======================================================================== */
/* Scoped to the results map partial — fold into style.css when convenient. */
.mini-map { display: flex; flex-direction: column; height: 100%; min-height: 300px; background: var(--surface); }
.mini-map-plate {
  position: relative; flex: 1 1 auto; min-height: 250px; overflow: hidden;
  background-color: var(--canvas);
  background-image:
    linear-gradient(to right, rgba(15,23,42,.055) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(15,23,42,.055) 1px, transparent 1px);
  background-size: 38px 38px;
}
/* Soft vignette so pins near the edge still read against the grid. */
.mini-map-plate::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(120% 90% at 50% 45%, rgba(255,255,255,0) 45%, rgba(255,255,255,.75) 100%);
}
.mini-map-pin {
  position: absolute; left: var(--x); top: var(--y); z-index: 2;
  display: grid; place-items: center; width: 30px; height: 30px;
  margin: -15px 0 0 -15px; border-radius: 50%;
  background: hsl(var(--hue,220) 66% 46%); color: #fff; border: 2px solid #fff;
  font-size: 11px; font-weight: 800; line-height: 1;
  box-shadow: 0 2px 6px rgba(15,23,42,.28);
  transition: transform .15s, box-shadow .15s;
}
/* Visual pin stays 30px; the tap target is padded out to 44px. */
.mini-map-pin::after { content: ""; position: absolute; inset: -7px; border-radius: 50%; }
.mini-map-pin:hover, .mini-map-pin:focus-visible { z-index: 5; color: #fff; transform: scale(1.18); box-shadow: 0 4px 12px rgba(15,23,42,.35); }
.mini-map-me {
  position: absolute; left: var(--x); top: var(--y); z-index: 1;
  width: 14px; height: 14px; margin: -7px 0 0 -7px; border-radius: 50%;
  background: var(--brand); border: 3px solid #fff; box-shadow: 0 0 0 6px rgba(23,105,255,.16);
}
/* Absolutely positioned, so `width: 25%` resolves against the plate itself —
   the bar is therefore exactly the quarter-width the label is computed for. */
.mini-map-scale {
  position: absolute; left: 12px; bottom: 10px; width: 25%; z-index: 3;
  display: grid; gap: 3px; font-size: 10px; font-weight: 700; color: var(--muted);
}
.mini-map-scale i { display: block; height: 5px; border: 1px solid var(--muted-2); border-top: 0; }
.mini-map-foot {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  flex-wrap: wrap; padding: 10px 14px; border-top: 1px solid var(--line);
  font-size: var(--fs-xs); color: var(--muted); background: var(--surface);
}
.mini-map-foot strong { color: var(--ink-2); }
.mini-map-empty { display: grid; place-items: center; padding: var(--sp-8) var(--sp-4); text-align: center; font-size: var(--fs-sm); color: var(--muted); }
/* ==================================================== category page ======
   category.php — one category, scoped to the active location.

   The components here already existed; what follows is the redesign pass plus
   the two rule-sets that were living in an inline <style> block on the page
   itself (.category-aside), which its own comment asked to have folded in.
   ======================================================================== */

/* --- hero ---------------------------------------------------------------- */

.category-hero {
  padding-block: var(--sp-8) var(--sp-10);
  background:
    radial-gradient(90% 120% at 12% 0%, var(--brand-50) 0%, rgba(255,255,255,0) 62%),
    linear-gradient(180deg, var(--brand-50), rgba(255,255,255,0));
}

/*
 * The H1's line break is a block-level span rather than a <br> — see the note
 * in category.php. "Explore" is the small word; the category name is the
 * heading you actually read, so it gets the size and the colour.
 */
.cat-h1-lead {
  display: block;
  font-size: var(--fs-md);
  font-weight: 600;
  letter-spacing: .01em;
  color: var(--muted);
  margin-bottom: 2px;
}
.category-hero h1 .cat-h1-name { color: var(--brand); }

.category-hero h1 {
  font-size: clamp(1.7rem, 1.15rem + 2.2vw, 2.6rem);
  line-height: 1.14;
  letter-spacing: -.03em;
  text-wrap: balance;
}

.category-hero-grid > div > p { max-width: 56ch; }

/*
 * The result count was a bare bold string sitting between two paragraphs, so
 * the single most important number on the page had no more weight than the
 * prose around it. A pill gives it an edge to sit against.
 */
.result-count {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 16px;
  margin-bottom: var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--brand-100);
  border-radius: var(--r-full);
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--brand-700);
  box-shadow: 0 1px 3px rgba(15,23,42,.06);
  font-variant-numeric: tabular-nums;
}

/* --- map aside ----------------------------------------------------------- */
/* Moved out of the inline <style> block in category.php. Rules unchanged. */
.category-aside { display: grid; gap: var(--sp-3); min-width: 0; }
.category-aside .mini-map {
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow);
}
.category-aside .mini-map-plate { min-height: 260px; }

/* --- related category chips ---------------------------------------------- */

.related-cats { margin-top: var(--sp-5); }

/* --- sparse results ------------------------------------------------------ */
/*
 * A category with one listing was rendering that listing into a grid whose
 * tracks are sized for twelve, so a single card sat marooned beside two empty
 * columns and the page read as broken rather than as new. Capping the track
 * count while the set is small keeps the row looking deliberate.
 *
 * :has() is already used elsewhere in this stylesheet, so the support baseline
 * is unchanged; browsers without it simply get the old full-width grid.
 */
.listing-grid:has(> .listing-tile:only-child) {
  grid-template-columns: minmax(0, 420px);
}
.listing-grid:has(> .listing-tile:nth-child(2):last-child) {
  grid-template-columns: repeat(2, minmax(0, 380px));
}

/* --- info columns -------------------------------------------------------- */

.info-columns { padding-block: var(--sp-10); }
.info-grid > article {
  display: flex;
  flex-direction: column;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.info-grid > article:hover {
  border-color: var(--brand-200);
  box-shadow: 0 4px 16px rgba(15,23,42,.06);
}
.info-grid .section-head { margin-bottom: var(--sp-2); }
.info-grid li a { font-weight: 500; }
/* Counts read as data, not as prose. */
.info-grid li span {
  flex: none;
  min-width: 30px;
  padding: 1px 8px;
  border-radius: var(--r-full);
  background: var(--canvas);
  text-align: center;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

@media (prefers-reduced-motion: reduce) {
  .info-grid > article { transition: none; }
}

/* ========================================================== landing page ===
   index.php — section rhythm, 3D result cards and the background layer.

   THE PROBLEM THIS SOLVES
   Of the eight sections on the homepage, five had no background rule at all
   and two shared the same --canvas fill, so the page read as one continuous
   sheet: nothing told you where "results" ended and "categories" began. What
   follows gives every band its own surface, separated by a deliberate rhythm
   (plain -> tinted -> plain -> brand -> plain -> deep) rather than repetition.
   ========================================================================== */

/* --- result list ---------------------------------------------------------- */
/* Moved out of the inline <style> block in index.php (its own comment asked
   for this). .listing-rows is a vertical stack — the shared grid utilities are
   all auto-fill column grids and would lay the rows out side by side. */
.listing-rows { display: grid; gap: var(--sp-3); min-width: 0; }

/*
 * The panel shows twelve results now instead of one. Twelve rows is well past
 * a fold, and letting them push the map and every section below them down the
 * page is worse than giving the list its own scrollport.
 */
.listing-rows-scroll {
  max-height: min(70vh, 620px);
  overflow-y: auto;
  overscroll-behavior: contain;         /* stop the page scrolling past the end */
  padding-right: 4px;                   /* room for the scrollbar, not under it */
  scrollbar-width: thin;
  scrollbar-color: var(--line) transparent;
}
.listing-rows-scroll:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; border-radius: var(--r); }
.listing-rows-scroll::-webkit-scrollbar { width: 8px; }
.listing-rows-scroll::-webkit-scrollbar-thumb { background: var(--line); border-radius: 99px; }
.listing-rows-scroll::-webkit-scrollbar-thumb:hover { background: var(--muted-2); }

/* Marks where "near you" stops being true and the national top-up begins. */
.results-divider {
  display: flex; align-items: center; gap: var(--sp-3);
  margin: var(--sp-2) 0;
  font-size: var(--fs-xs); font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--muted);
}
.results-divider::before, .results-divider::after {
  content: ""; flex: 1; height: 1px; background: var(--line);
}

/* --- 3D result cards ------------------------------------------------------ */
/*
 * Depth from layered shadow and a hairline, not from a border alone: a card
 * that only has an outline reads as a table row. The lift on hover is small on
 * purpose — twelve cards all leaping would be noise, and this list is scanned.
 */
.listing-row {
  border-radius: var(--r-lg);
  background: linear-gradient(180deg, var(--surface) 0%, #fcfdff 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.9),
    0 1px 2px rgba(15,23,42,.05),
    0 10px 22px -14px rgba(15,23,42,.32);
  transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.listing-row:hover {
  transform: translateY(-2px);
  border-color: var(--brand-200);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.95),
    0 2px 4px rgba(15,23,42,.06),
    0 18px 34px -18px rgba(23,103,252,.45);
}
/* Keyboard parity — a card reachable only by mouse hover is half a control. */
.listing-row:focus-within {
  border-color: var(--brand-200);
  box-shadow: 0 0 0 3px rgba(22,103,252,.16), 0 18px 34px -18px rgba(23,103,252,.45);
}

/* --- section rhythm ------------------------------------------------------- */
/*
 * Each band gets its own surface. The order alternates deliberately so no two
 * neighbours share a treatment — that adjacency is the whole point, and it is
 * why these are written together rather than next to their components.
 */
.results-section    { padding-block: var(--sp-10); background: var(--surface); }
.categories-section { padding-block: var(--sp-10); background: linear-gradient(180deg, var(--canvas), #eef3fb); }
.how-section        { padding-block: var(--sp-10); background:
                        radial-gradient(80% 60% at 50% 0%, var(--brand-50), rgba(255,255,255,0) 70%),
                        var(--surface); }
.featured-section   { padding-block: var(--sp-10); background: linear-gradient(180deg, #fffdf7, var(--surface)); }
.business-section   { padding-block: var(--sp-10); background:
                        radial-gradient(70% 80% at 88% 10%, rgba(139,92,246,.13), rgba(255,255,255,0) 62%),
                        linear-gradient(180deg, var(--canvas), #e9eefb); }
.ai-section         { padding-block: var(--sp-10); background:
                        radial-gradient(75% 70% at 12% 0%, rgba(22,103,252,.12), rgba(255,255,255,0) 64%),
                        var(--surface); }

/* A hairline between neighbouring bands, so even two light surfaces have a
   definite seam rather than bleeding into one another. */
.results-section, .categories-section, .how-section,
.featured-section, .business-section, .ai-section, .app-section {
  position: relative;
  isolation: isolate;
  border-top: 1px solid rgba(15,23,42,.05);
}

/* --- background decoration ------------------------------------------------ */
/*
 * Same construction as the add-business page: blurred gradient orbs plus
 * floating category tiles, animating transform/opacity only so the work stays
 * on the compositor. Decoration is inert — aria-hidden in the markup and
 * pointer-events:none here, because these layers span whole sections and would
 * otherwise swallow clicks meant for the content above them.
 */
.sec-decor {
  position: absolute; inset: 0; z-index: 0;
  overflow: hidden; pointer-events: none;
}
.sec-decor + .site-container,
.sec-decor ~ .site-container { position: relative; z-index: 1; }

.sec-orb {
  position: absolute; display: block; border-radius: 50%;
  filter: blur(60px); opacity: .45; will-change: transform;
}
.sec-orb-1 {
  width: 38vw; max-width: 440px; aspect-ratio: 1; top: -10%; left: -8%;
  background: radial-gradient(circle at 34% 34%, rgba(22,103,252,.5), rgba(22,103,252,0) 68%);
  animation: sec-drift-a 28s ease-in-out infinite;
}
.sec-orb-2 {
  width: 32vw; max-width: 380px; aspect-ratio: 1; bottom: -14%; right: -6%;
  background: radial-gradient(circle at 60% 40%, rgba(139,92,246,.44), rgba(139,92,246,0) 70%);
  animation: sec-drift-b 34s ease-in-out infinite;
}
@keyframes sec-drift-a {
  0%,100% { transform: translate3d(0,0,0) scale(1); }
  35%     { transform: translate3d(5vw, 4vh, 0) scale(1.12); }
  70%     { transform: translate3d(2vw,-3vh, 0) scale(.93); }
}
@keyframes sec-drift-b {
  0%,100% { transform: translate3d(0,0,0) scale(1); }
  40%     { transform: translate3d(-6vw,-4vh,0) scale(1.14); }
  75%     { transform: translate3d(-2vw, 3vh,0) scale(.9); }
}

/* Floating tiles — the "3D objects". Built from a gradient face, a hairline
   highlight and a cast shadow, so they read as lifted without an image. */
.sec-float {
  position: absolute;
  display: grid; place-items: center;
  width: 52px; height: 52px;
  border-radius: 16px;
  font-size: 23px; line-height: 1;
  background: linear-gradient(160deg, rgba(255,255,255,.97), rgba(238,244,255,.85));
  border: 1px solid rgba(22,103,252,.14);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.9), 0 10px 22px -12px rgba(15,23,42,.45);
  opacity: .5;
  will-change: transform;
}
.sec-float-1 { top: 14%; left:  5%; animation: sec-bob 19s ease-in-out infinite; }
.sec-float-2 { top: 70%; left: 11%; animation: sec-bob 23s ease-in-out -6s infinite; }
.sec-float-3 { top: 22%; right: 8%; animation: sec-bob 21s ease-in-out -12s infinite; }
.sec-float-4 { top: 74%; right: 14%; animation: sec-bob 25s ease-in-out -3s infinite; }

@keyframes sec-bob {
  0%,100% { transform: translate3d(0,0,0) rotate(-6deg); }
  25%     { transform: translate3d(9px,-16px,0) rotate(4deg); }
  50%     { transform: translate3d(-5px,-28px,0) rotate(-2deg); }
  75%     { transform: translate3d(-11px,-13px,0) rotate(7deg); }
}

@media (max-width: 719px) {
  /* Phones: keep the depth, drop the tiles. The bands are narrow enough that a
     tile is always behind something readable. */
  .sec-float { display: none; }
  .sec-orb { filter: blur(44px); opacity: .38; }
}
@media (prefers-reduced-motion: reduce) {
  .sec-orb, .sec-float { animation: none !important; }
  .listing-row { transition: none; }
  .listing-row:hover { transform: none; }
}
@media (forced-colors: active) {
  .sec-decor { display: none; }
}

/* ====================================================== listing hero =======
   business.php — the text-first listing hero.

   Moved out of the inline <style> block on that page (its own comment asked for
   it) and rebuilt with real depth. A listing carries no photograph by design,
   so the hero has to earn its presence from type, tint and elevation rather
   than from imagery — every surface below is built from gradients and layered
   shadow, nothing downloaded.
   ========================================================================== */

.biz-hero {
  --tint: hsl(var(--hue, 220) 80% 97%);
  position: relative;
  isolation: isolate;
  display: grid; gap: var(--sp-4); min-width: 0;
  padding: var(--sp-5);
  border: 1px solid var(--line);
  border-radius: var(--r-xl, 20px);
  background:
    radial-gradient(120% 80% at 88% -20%, hsl(var(--hue,220) 85% 94%) 0%, rgba(255,255,255,0) 58%),
    linear-gradient(180deg, var(--tint) 0%, var(--surface) 210px);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.9),
    0 1px 2px rgba(15,23,42,.05),
    0 22px 44px -26px hsl(var(--hue,220) 55% 40% / .55);
}
/* The tinted haze the card appears to cast, clipped away from the top so it
   reads as a shadow rather than a glow ring. */
.biz-hero::before {
  content: "";
  position: absolute; inset: 40% 4% -6%;
  z-index: -1;
  border-radius: var(--r-xl, 20px);
  background: linear-gradient(160deg, hsl(var(--hue,220) 70% 60% / .3), rgba(139,92,246,.16));
  filter: blur(38px);
  opacity: .75;
}

.biz-identity { display: flex; align-items: flex-start; gap: var(--sp-4); min-width: 0; }

/* --- the glyph as a real object ------------------------------------------ */
/*
 * Same hue formula as .listing-avatar so the hero and the cards read as one
 * object at two scales — but extruded: a lit top edge, a darker bottom edge
 * and a coloured cast shadow, which is what separates a tile from a swatch.
 */
.biz-glyph {
  display: grid; place-items: center; flex: none; line-height: 1;
  width: clamp(64px, 17vw, 96px); height: clamp(64px, 17vw, 96px);
  font-size: clamp(30px, 8vw, 46px);
  border-radius: clamp(18px, 4vw, 26px);
  background: linear-gradient(150deg,
      hsl(var(--hue, 220) 90% 97%) 0%,
      hsl(var(--hue, 220) 82% 93%) 38%,
      hsl(calc(var(--hue, 220) + 22) 74% 86%) 100%);
  box-shadow:
    inset 0 2px 0 hsl(var(--hue,220) 100% 98%),
    inset 0 -3px 0 hsl(calc(var(--hue,220) + 16) 48% 78%),
    0 4px 0 hsl(calc(var(--hue,220) + 16) 44% 82%),
    0 14px 26px -10px hsl(var(--hue,220) 60% 45% / .5);
  transform: translateZ(0);
  animation: biz-glyph-float 7s ease-in-out infinite;
}
@keyframes biz-glyph-float {
  0%, 100% { transform: translate3d(0, 0, 0) rotate(0deg); }
  50%      { transform: translate3d(0, -5px, 0) rotate(-1.5deg); }
}

.biz-identity-text { display: grid; gap: 6px; min-width: 0; }
.biz-eyebrow {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-xs); font-weight: 800; letter-spacing: .07em; text-transform: uppercase;
  color: hsl(var(--hue, 220) 52% 36%);
}
.biz-eyebrow a { color: inherit; text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
.biz-eyebrow a:hover { color: var(--brand); }
.biz-eyebrow span { font-weight: 600; letter-spacing: .02em; text-transform: none; color: var(--muted); }
.biz-eyebrow span::before { content: "·"; margin-right: var(--sp-2); color: var(--muted-2); }
.biz-tagline { font-size: var(--fs-sm); color: var(--ink-2); max-width: 60ch; }

/* --- fact strip ----------------------------------------------------------- */
/*
 * Was a flat grid separated by 1px gaps showing the container colour. Now each
 * cell is its own raised surface, so the strip reads as four facts rather than
 * one divided box. Cells are still omitted rather than filled with a
 * placeholder, so the strip is always true.
 */
.biz-facts {
  display: grid; gap: var(--sp-2);
  grid-template-columns: repeat(auto-fit, minmax(min(50% - 4px, 138px), 1fr));
  background: none; border: 0; border-radius: 0; overflow: visible;
}
.biz-fact {
  display: grid; gap: 2px; align-content: start;
  padding: var(--sp-3) var(--sp-4);
  background: linear-gradient(180deg, var(--surface), #fbfcff);
  border: 1px solid var(--line);
  border-radius: var(--r);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.9), 0 6px 14px -10px rgba(15,23,42,.4);
  transition: transform .16s ease, box-shadow .16s ease, border-color .16s ease;
}
.biz-fact:hover {
  transform: translateY(-2px);
  border-color: hsl(var(--hue,220) 60% 82%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.95), 0 12px 22px -12px hsl(var(--hue,220) 55% 45% / .5);
}
.biz-fact strong { font-size: var(--fs-xl); line-height: 1.15; letter-spacing: -.03em; }
.biz-fact small { font-size: var(--fs-xs); color: var(--muted); }
.biz-fact small a { font-weight: 600; }
.biz-fact .stars { font-size: var(--fs-xs); }
.biz-fact.is-rating strong { color: var(--ink); }
.biz-fact.is-open strong { color: var(--green-600); }
.biz-fact.is-soon strong { color: #b45309; }
.biz-fact.is-closed strong { color: #b91c1c; }

/* Status cells carry a tinted face so open/closed is legible at a glance
   without reading the word — and the tint is a second signal, not the only
   one, since the word itself is still there. */
.biz-fact.is-open   { background: linear-gradient(180deg, var(--green-50), var(--surface)); border-color: #b8ecd2; }
.biz-fact.is-soon   { background: linear-gradient(180deg, var(--amber-50), var(--surface)); border-color: #fde3af; }
.biz-fact.is-closed { background: linear-gradient(180deg, var(--red-50), var(--surface)); border-color: #fbd0d0; }

/* --- attribute chips ------------------------------------------------------ */
.biz-tags span {
  background: linear-gradient(180deg, #fff, var(--line-2));
  border: 1px solid var(--line);
  box-shadow: inset 0 1px 0 #fff, 0 2px 5px -3px rgba(15,23,42,.4);
  transition: transform .14s ease, box-shadow .14s ease;
}
.biz-tags span:hover { transform: translateY(-1px); box-shadow: inset 0 1px 0 #fff, 0 6px 12px -6px rgba(15,23,42,.45); }
.biz-tags a { align-self: center; font-size: var(--fs-xs); font-weight: 700; }
.biz-hero .address { margin-top: 0; }
.biz-hero .business-actions { margin-top: 0; }

/* --- action buttons with a real press ------------------------------------- */
/*
 * The depth is a solid offset shadow acting as the button's side wall, so
 * :active can shrink it and move the face down by the same amount — the button
 * travels instead of just changing colour. translateY + a shorter wall is the
 * whole trick; nothing here animates a layout property.
 */
.business-actions a {
  background: linear-gradient(180deg, var(--surface), #f7f9fd);
  box-shadow: inset 0 1px 0 #fff, 0 2px 0 var(--line), 0 8px 16px -10px rgba(15,23,42,.5);
  transition: transform .12s ease, box-shadow .12s ease, background .14s ease, border-color .14s ease;
}
.business-actions a:hover {
  transform: translateY(-1px);
  border-color: var(--brand-200);
  box-shadow: inset 0 1px 0 #fff, 0 3px 0 var(--brand-100), 0 12px 22px -12px rgba(22,103,252,.55);
}
.business-actions a:active {
  transform: translateY(2px);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.6), 0 0 0 var(--line), 0 4px 8px -6px rgba(15,23,42,.5);
}
.business-actions a.primary {
  background: linear-gradient(180deg, var(--brand-400, #5b8dff), var(--brand));
  border-color: var(--brand-600);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.42), 0 2px 0 var(--brand-600), 0 10px 22px -10px rgba(22,103,252,.85);
}
.business-actions a.primary:hover {
  background: linear-gradient(180deg, var(--brand), var(--brand-600));
  box-shadow: inset 0 1px 0 rgba(255,255,255,.45), 0 3px 0 var(--brand-600), 0 16px 30px -12px rgba(22,103,252,.9);
}
.business-actions a.primary:active {
  transform: translateY(2px);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.3), 0 0 0 var(--brand-600), 0 6px 12px -8px rgba(22,103,252,.8);
}
/* Keyboard parity — a press effect only a mouse can reach is half a control. */
.business-actions a:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; }

/* Contact card: text address instead of the stock map screenshot. */
.where-block { display: grid; gap: 4px; padding: var(--sp-3) var(--sp-1) 0; border-top: 1px solid var(--line); }
.where-block strong { font-size: var(--fs-xs); font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--muted); }
.where-block p { font-size: var(--fs-sm); color: var(--ink-2); line-height: 1.5; }

/* Similar places: the small category tile replaces the old thumbnail. */
.similar-grid a { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3); }
.similar-grid a:hover { border-color: var(--brand-200); }
.similar-grid div { padding: 0; min-width: 0; }
.similar-grid strong { display: block; }
.nearby-map { margin-top: var(--sp-4); overflow: hidden; border: 1px solid var(--line); border-radius: var(--r); }
.nearby-map .mini-map-plate { min-height: 220px; }

@media (min-width: 600px) { .biz-hero { padding: var(--sp-6); } }

@media (prefers-reduced-motion: reduce) {
  .biz-glyph { animation: none; }
  .biz-fact, .biz-tags span, .business-actions a { transition: none; }
  .biz-fact:hover, .biz-tags span:hover,
  .business-actions a:hover, .business-actions a:active { transform: none; }
}

/* ==================================================== location picker =====
   The type-ahead on the public search bars (assets/js/location-picker.js).
   The list is created by the script, so these are the only rules it needs.
   ======================================================================== */

.loc-picker-list {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  z-index: 60;              /* above the hero art, below the site header (100) */
  max-height: 280px;
  overflow-y: auto;
  margin: 0;
  padding: 6px;
  list-style: none;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  box-shadow: 0 18px 38px -14px rgba(15, 23, 42, .38);
}
.loc-picker-list[hidden] { display: none; }

.loc-picker-option {
  padding: 9px 12px;
  border-radius: var(--r-sm);
  font-size: var(--fs-sm);
  color: var(--ink-2);
  cursor: pointer;
  overflow-wrap: anywhere;
}
/* Hover and keyboard share one appearance — a highlight the arrow keys can
   reach but the mouse cannot (or vice versa) reads as two different controls. */
.loc-picker-option:hover,
.loc-picker-option.is-active {
  background: var(--brand-50);
  color: var(--brand-700);
  font-weight: 600;
}

.loc-picker-note {
  padding: 10px 12px;
  font-size: var(--fs-xs);
  color: var(--muted);
}

@media (max-width: 719px) {
  /* Keep the list clear of the on-screen keyboard on a phone. */
  .loc-picker-list { max-height: 210px; }
}

/* ============================================================ brand mark ===
   The v4 radar logo in the header and footer.

   Replaces .brand-pin, which was a CSS-drawn gradient tile wrapping an inline
   pin glyph — a stand-in from before the logo existed. The real mark is a file
   now, so the styling here is only about size, alignment and the hover.
   ========================================================================= */

.brand-mark {
  width: 36px;
  height: 36px;
  flex: none;
  display: block;
  border-radius: 11px;   /* matches the artwork's own corner, so the shadow sits flush */
  box-shadow: var(--shadow-brand), inset 0 1px 0 rgba(255, 255, 255, .4);
  transition: transform .3s var(--ease-out), box-shadow .3s var(--ease);
}
.brand:hover .brand-mark {
  transform: translateY(-2px) rotate(-6deg);
  box-shadow: var(--shadow-brand-lg), inset 0 1px 0 rgba(255, 255, 255, .4);
}

/* The old tile is gone from the markup; the rules stay harmless but the mark
   must not inherit its grid centring if any page still renders one. */
.brand-mark + .brand-text { min-width: 0; }

@media (prefers-reduced-motion: reduce) {
  .brand-mark { transition: none; }
  .brand:hover .brand-mark { transform: none; }
}

/* ------------------------------------------------------ full lockup ------ */
/*
 * The complete horizontal logo, for the places with real horizontal room —
 * the auth pages and the transactional email header. Not the site header: the
 * lockup carries the tagline and updatesee.com inside the artwork, and at a
 * 36px header height those set about two pixels tall.
 */
.brand-lockup {
  display: block;
  width: auto;
  max-width: 260px;
  height: auto;
  margin-inline: auto;
}
.auth-shell .brand-lockup { margin-bottom: var(--sp-5); }
