/* Realty of India — app layer (on top of tokens.css).
 * Component-scoped styles live here; design tokens live in tokens.css.
 *
 * tokens.css is NO LONGER @import'ed here — a plain CSS @import carries no
 * cache-buster, so token edits (dark-mode --ink/--accent flips) served a
 * STALE tokens.css to clients. It is now linked DIRECTLY (before app.css)
 * with its own ?v=filemtime in layouts/app.blade.php + layouts/onboarding
 * .blade.php. Any new layout that links app.css must also link tokens.css.
 */

/* Prevent horizontal scroll on the body. Several SRP components
   (search-engine category chips, budget slider tick row, filter chip
   strip) can collectively exceed viewport width at 360-430px and
   force the page wider than the screen — users see content cut off
   to the right and can horizontal-scroll the whole page.
   `overflow-x: clip` is the modern fix: it stops horizontal overflow
   at the body without creating a new scroll container (unlike
   `overflow-x: hidden`), so `position: sticky` elements like the
   navbar and .ps-filter-strip keep working. Components with their
   own intentional horizontal scroll (.feed-demand-scroll,
   .ps-filter-chips on mobile) still work inside their own clipping
   contexts. Mobile-overhaul Phase 4 follow-up. */
html, body { overflow-x: clip; }

/* ── Reduced-motion guard ────────────────────────────────────────
   Honour the OS-level "reduce motion" preference. Zeroes out the
   ~14 keyframe animations + 50+ transitions across the app for
   users with vestibular sensitivity. Single global rule scoped to
   *::before and *::after as well so pseudo-elements pick it up.
   Applied site-wide; component-specific motion can override only
   when it's an essential affordance (none currently). */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ── Navbar ──────────────────────────────────────────────────── */
.navbar {
  position: sticky;
  top: 0;
  z-index: 20;
  background: color-mix(in oklab, var(--ivory) 88%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
  padding-top: var(--inset-top);
}
.navbar-inner {
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 14px 32px;
  max-width: 1600px;
  margin: 0 auto;
}
/* Mobile: tighter horizontal padding + smaller gap so the brand +
   remaining right-side controls (city, theme, lang, CTA/avatar) all
   fit on one row at 360-430px viewports. The .navbar-tabs primary
   links already hide at this breakpoint (see L4270). */
@media (max-width: 700px) {
  .navbar-inner {
    gap: 10px;
    padding: 10px 14px;
  }
}

/* ── Brand mark ──────────────────────────────────────────────── */
.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  color: inherit;
}
/* ROI logo mark fills. Saffron is constant (reads on light + dark); the
   ink paths are warm-near-black on the light navbar and flip to warm-white
   in dark mode so the mark stays legible on the dark bar. Two-tone, so we
   can't use a single currentColor — fills are class-targeted instead. */
.brand-logo { display: block; flex: 0 0 auto; }
/* Saffron is constant (reads on light + dark). Ink is warm-near-black on
   the light navbar and flips to warm-white in dark mode. The mark uses
   filled dots (-saffron/-ink) + a stroked ring (-saffron-stroke/-ink-stroke). */
.roi-mark-saffron { fill: #e07926; }
.roi-mark-ink { fill: #151311; }
.roi-mark-saffron-stroke { stroke: #e07926; }
.roi-mark-ink-stroke { stroke: #151311; }
[data-theme="dark"] .roi-mark-ink { fill: #faf6ef; }
[data-theme="dark"] .roi-mark-ink-stroke { stroke: #faf6ef; }
@media (prefers-color-scheme: dark) {
  html:not([data-theme="light"]):not([data-theme="dark"]) .roi-mark-ink { fill: #faf6ef; }
  html:not([data-theme="light"]):not([data-theme="dark"]) .roi-mark-ink-stroke { stroke: #faf6ef; }
}
.brand-name {
  font-family: var(--serif);
  font-size: 22px;
  letter-spacing: -0.01em;
  line-height: 1;
}
/* Brand wordmark swap — desktop reads "Realty of India", phone reads
   "ROI". Both spans live in the DOM (see layouts/app brand markup) so
   screen readers + SEO crawlers always get the full name; CSS only
   toggles which is visually rendered. */
.brand-name__short { display: none; }
/* Logo subtitle uses the canonical .ph-tagline mark. The base
   .ph-tagline is inline-flex; restore the block-stack behaviour
   so it sits on its own line under the brand name. */
.brand-tagline {
  display: flex;
  margin-top: 4px;
  white-space: nowrap;
}
/* Mobile brand swap: hide "Realty of India" wordmark, show "ROI"
   instead. Saves ~90px of horizontal space — enough that the
   "Property Match Maker" subtitle stays visible on mobile (no
   longer hidden as it was in the prior commit). Per mobile-
   overhaul Phase 4 follow-up. */
@media (max-width: 700px) {
  .brand-name__full { display: none; }
  .brand-name__short { display: inline; }
  /* Slim the brand block typography on phone so the right-side
     cluster (city + lang + List CTA) has room to render fully.
     Brand goes from ~172px wide (22px wordmark + 18px tagline) to
     ~125px (17px wordmark + 13px tagline + tighter gap). Desktop
     keeps the full canonical sizes. Per user direction 2026-05-28. */
  .brand { gap: 8px; }
  .brand-name { font-size: 17px; }
  /* User feedback 2026-05-29 on Samsung Galaxy S8+ (360x740):
     tagline shrunk further to free up navbar real estate. Goes from
     13 -> 11px on phone — the canonical .ph-tagline--sm size is
     18px on desktop and 13px tablet, so 11px is the mobile-only
     additional shrink. Tighter line-height + margin-top so the
     two-line brand block (icon + ROI + tagline) stays compact. */
  .brand-tagline.ph-tagline--sm { font-size: 11px; line-height: 1.25; }
  .brand-tagline { margin-top: 2px; }
  /* NB: .navtab--realtyx hide rule moved to AFTER its base rule
     (~line 6960) so source order doesn't override it. */
  /* Shorter CTA on phone. The full "List in 60 Seconds" label is
     ~145px; the short form fits in ~70px so the right-side controls
     (city + theme + lang + this) all fit one row at 360px+. */
  .nav-list-in-60-btn .nav-list-in-60-btn-label--long { display: none; }
}
.nav-list-in-60-btn .nav-list-in-60-btn-label--short { display: none; }
@media (max-width: 700px) {
  .nav-list-in-60-btn .nav-list-in-60-btn-label--short { display: inline; }
}

/* ── Buttons (ink primary, paper secondary, saffron accent) ──── */
/* min-height 48px meets WCAG 2.5.5 AAA / Material Design touch-target.
 * Font-size uses the var(--fs-sm) scale so it tracks the root.
 * `.btn-sm` is allowed down to 36px for dense data-row contexts only
 * (intro inbox, saved card action, match-pair inline action). */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: var(--tap);
  padding: 10px 18px;
  border-radius: 8px;
  font-family: inherit;
  font-size: var(--fs-sm);
  font-weight: 500;
  cursor: pointer;
  border: 1px solid transparent;
  text-decoration: none;
  transition: transform 0.1s, background 0.15s, color 0.15s, border-color 0.15s;
}
.btn-sm {
  /* Floor exception for dense scrollers. The rubric D3 48px floor is
     enforced via .tap-floor (defined immediately below); bare .btn-sm
     intentionally stays at 36px so admin tables (.admin-table) keep
     their information density. Every other surface must compose
     .tap-floor — either via <x-button size="sm"> (which composes it
     automatically unless dense=true) or by appending ' tap-floor' to
     a raw class list. scripts/lint-tap-targets.php enforces this on
     the 8 named offenders and a soft-warn pass surfaces raw btn-sm
     callers outside .admin-table. See [[brief_realtyx_tap_44_lint]]. */
  min-height: 36px;
  padding: 6px 12px;
  font-size: var(--fs-xs);
}

/* RealtyX touch-floor utility (rubric D3 — see
   [[mobile-ergonomics-rubric]]). Single source of truth derived from
   the --tap token in tokens.css (48px today). Renaming --tap is a
   one-line edit; every consumer of .tap-floor picks it up. The
   utility is compose-friendly: drop it on any small button or chip
   and the visible box still grows to >= 48x48 with inline-flex
   centering. For chips that must visually stay at 26-30px, use a
   transparent ::before hit-area instead (see .feed-rail-filter /
   .feed-rail-pill-remove-btn / .feed-rail-addlink / .feed-rail-hide-btn
   below — same end-state, no visual distortion). */
.tap-floor {
  min-width: var(--tap);
  min-height: var(--tap);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* ── <x-img> base + variant rules ────────────────────────────────────
   Backs the resources/views/components/img.blade.php component. Each
   variant carries aspect-ratio + object-fit + object-position so the
   visible <img> reserves space pre-load (CLS-free first paint) AND
   shows the correct focal third — both per the rubric and the
   mobile-overhaul audit (memory: brief_realtyx_x_img_component).

   Per-surface overrides (.listing-hero-tile mobile 4/3, etc.) land in
   PR #3 of the brief sequence with HIGHER specificity than the bare
   .x-img--{variant} selector so they win without !important. Keeping
   the variant defaults in this block (not inline on the component)
   is load-bearing — inline emission would beat per-surface CSS and
   regress the PDP mobile hero LCP shape. */
.x-img {
  display: block;
  max-width: 100%;
  width: 100%;
  height: auto;
}
.x-img--hero      { aspect-ratio: 16 / 8;     object-fit: cover;   object-position: 50% 30%; }
.x-img--avatar    { aspect-ratio: 1 / 1;      object-fit: cover;   object-position: 50% 28%; }
.x-img--thumb     { aspect-ratio: 1 / 1;      object-fit: cover;   object-position: 50% 50%; }
.x-img--card      { aspect-ratio: 4 / 3;      object-fit: cover;   object-position: 50% 40%; }
.x-img--floorplan { aspect-ratio: 4 / 3;      object-fit: contain; object-position: 50% 50%; }
.x-img--og        { aspect-ratio: 1200 / 630; object-fit: cover;   object-position: 50% 50%; }
.x-img--placeholder { aspect-ratio: 1 / 1; opacity: 0; }
.btn-primary   { background: var(--ink);     color: var(--paper); }
.btn-primary:hover   { filter: brightness(1.12); }
.btn-secondary { background: var(--paper);   color: var(--ink);  border-color: var(--line-2); }
.btn-secondary:hover { border-color: var(--ink-3); }
.btn-accent    { background: var(--saffron); color: var(--ink);  font-weight: 600; }
.btn-accent:hover    { background: var(--saffron-deep); color: var(--paper); }
.btn-ghost     { background: transparent;    color: var(--ink-2); border-color: var(--line-2); }
.btn-ghost:hover     { background: var(--ivory-2); color: var(--ink); }

.btn:disabled,
.btn[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
  filter: none;
  pointer-events: none;
}

/* ── Tag pills (toggleable chips) ────────────────────────────── */
.tag {
  display: inline-flex;
  align-items: center;
  padding: 5px 11px;
  border-radius: 999px;
  border: 1px solid var(--line-2);
  background: var(--paper);
  color: var(--ink-2);
  font-size: 12px;
  font-weight: 500;
  font-family: var(--sans);
  cursor: pointer;
  white-space: nowrap;
  letter-spacing: 0.01em;
}
.tag.tag-sm { padding: 3px 9px; font-size: 11px; }
.tag[aria-pressed="true"],
.tag.is-active {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}

/* ── Badges (small status pills) ─────────────────────────────── */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.02em;
  padding: 3px 8px;
  border-radius: 999px;
  border: 1px solid var(--line-2);
  background: var(--ivory-2);
  color: var(--ink-2);
  white-space: nowrap;
}
.badge-xs { font-size: 10px; padding: 2px 6px; }
/* Badge borders derive from the same semantic tokens so dark mode
 * doesn't show light-mode-only oklch constants. color-mix blends
 * the accent into the soft bg for a barely-visible outline. */
.badge-saffron { background: var(--saffron-soft); color: var(--saffron-deep); border-color: color-mix(in oklab, var(--saffron) 30%, transparent); }
.badge-green   { background: var(--green-soft);   color: var(--green);        border-color: color-mix(in oklab, var(--green)   30%, transparent); }
.badge-ink     { background: var(--ink);          color: var(--paper);        border-color: var(--ink); }
.badge-ghost   { background: transparent;         color: var(--ink-3);        border-color: var(--line-2); }
/* Deal-won variant — saffron-tinted "trophy" feel. Used on the
   pair card when intro.deal_closed_at is set. */
.badge--won    { background: color-mix(in oklab, var(--saffron-deep, #d8a35e) 12%, var(--paper)); color: var(--saffron-deep, #d8a35e); border-color: color-mix(in oklab, var(--saffron-deep, #d8a35e) 45%, var(--line)); font-weight: 600; }

/* ── Admin panel chrome (B2) ─────────────────────────────────────
 * Lightweight surface that lives inside layouts.app — no separate
 * admin shell. Sub-nav strip + table + stat cards + form helpers.
 */
.admin-subnav { margin: 16px 0 24px; border-bottom: 1px solid var(--line-2); }
.admin-subnav ul {
  list-style: none; margin: 0; padding: 0;
  display: flex; gap: 4px; flex-wrap: wrap;
}
.admin-subnav a {
  display: inline-block;
  padding: 8px 14px;
  font-size: 13px;
  letter-spacing: 0.02em;
  color: var(--ink-2);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  text-decoration: none;
}
.admin-subnav a:hover { color: var(--ink); }
.admin-subnav a.is-active {
  color: var(--ink); font-weight: 600;
  border-bottom-color: var(--ink);
}
.admin-subnav-badge {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 7px;
  font-size: 10px;
  background: var(--saffron);
  color: var(--ink);
  border-radius: 999px;
  font-weight: 700;
  letter-spacing: 0.02em;
  vertical-align: 1px;
}

.admin-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 16px;
  margin: 24px 0;
}
.admin-stat {
  background: var(--ivory-2);
  border: 1px solid var(--line-2);
  border-radius: 8px;
  padding: 16px;
}
.admin-stat-label { font-size: 11px; color: var(--ink-3); text-transform: uppercase; letter-spacing: 0.06em; }
.admin-stat-value { font-size: 28px; font-weight: 600; margin-top: 6px; }
/* Brand color so the "Review →" CTA doesn't fall back to the UA
   visited-link purple — which rendered as a jarring violet on the
   dark-mode admin dashboard once an admin had clicked through. (This
   class is exempt from the a:not([class]) text-flow rule because it HAS
   a class.) Light mode uses --saffron-deep (AA on the pale card); dark
   mode uses the brighter --saffron, which reads cleaner on the dark
   card and has ample contrast there. */
.admin-stat-link {
  display: block; margin-top: 8px; font-size: 12px;
  color: var(--saffron-deep); text-decoration: underline; text-underline-offset: 2px;
}
.admin-stat-link:hover { color: var(--ink); }
[data-theme="dark"] .admin-stat-link { color: var(--saffron); }
@media (prefers-color-scheme: dark) {
  html:not([data-theme="light"]):not([data-theme="dark"]) .admin-stat-link { color: var(--saffron); }
}

.admin-section { margin: 32px 0; }
.admin-section-title { font-size: 16px; font-weight: 600; margin: 0 0 12px; }

.admin-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.admin-table th, .admin-table td {
  text-align: left;
  padding: 10px 12px;
  border-bottom: 1px solid var(--line-2);
  vertical-align: top;
}
.admin-table th {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-3);
  font-weight: 500;
  background: var(--ivory-2);
}
.admin-table td .small { font-size: 11px; color: var(--ink-3); margin-top: 2px; }

/* Pin-by-id form on /admin/pinned — compact row of label + input +
   button + inline error. Tight enough to sit above the table without
   pushing the listing down. */
.admin-pin-by-id {
  margin: 0 0 20px;
  padding: 12px 14px;
  background: var(--ivory-2);
  border: 1px solid var(--line-2);
  border-radius: 8px;
  max-width: 360px;
}
.admin-pin-by-id label {
  display: block;
  margin-bottom: 6px;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-3);
}
.admin-pin-by-id-row {
  display: flex;
  gap: 8px;
  align-items: center;
}
.admin-pin-by-id-row .form-input {
  flex: 1;
  min-width: 0;
}
.admin-pin-by-id .form-error {
  margin: 6px 0 0;
  color: #b00020;
  font-size: 12px;
}

.admin-card {
  background: var(--ivory-2);
  border: 1px solid var(--line-2);
  border-radius: 8px;
  padding: 16px;
  margin: 12px 0;
}
.admin-card-head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 12px;
}
.admin-form-inline {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}

/* ── ROI Verified badge ─────────────────────────────────────────
 * Shown ONLY when broker_profiles.roi_verified_at IS NOT NULL.
 * Display gate lives on the Blade component / model helper, never in
 * CSS. Visually distinct from the generic .badge family so verified
 * brokers stand out at a glance.
 */
.roi-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 999px;
  background: var(--red-soft);
  color: var(--red);
  border: 1px solid color-mix(in oklab, var(--red) 35%, transparent);
  white-space: nowrap;
  vertical-align: middle;
  /* No-crop reflex D4 — fixed-dimension flex sibling never gets
     compressed by a text neighbour. */
  flex-shrink: 0;
}
.roi-badge--compact { padding: 2px 6px; font-size: 9px; gap: 2px; }
.roi-badge svg { display: block; }
.roi-badge-label { line-height: 1; }

/* ── Avatars (initials on a warm tint) ───────────────────────── */
.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  font-family: var(--serif);
  font-style: italic;
  letter-spacing: 0.02em;
  color: var(--ink);
  flex-shrink: 0;
  /* Defensive against parent flex pressure that some surfaces
     (post-card-head, feed-rail-broker-meta wrap) accidentally apply.
     Paired with flex-shrink:0 above so the avatar never goes negative. */
  min-width: 0;
  /* Clip the bitmap to the circle, not the surrounding square. */
  overflow: hidden;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.06);
}
.avatar.is-ringed {
  box-shadow: 0 0 0 2px var(--paper), 0 0 0 3px var(--ink);
}

/* Avatar — image variant (uploaded broker_profiles.avatar_url).
   Per audit_mobile_realtyx D1 — fixes Galaxy S8+ chin-and-top-of-head
   crop. Three load-bearing pieces:
     - aspect-ratio + width/height attrs (in markup) eliminate CLS.
     - object-position: 50% 28% slices the upper-third so portrait
       headshots show eyes/forehead instead of cropping to a chest
       band (vs. the default 50% 50% center-slice).
     - background-color is a defensive letterbox — an off-aspect
       bitmap softens against the avatar tint instead of leaving a
       hard transparent gap.
   Until the upload pipeline normalises avatars to 1:1 server-side,
   this is the cheapest fix that visibly removes the crop without
   touching R2 or the bitmap pipeline. */
.avatar--img {
  aspect-ratio: 1 / 1;
  object-fit: cover;
  object-position: 50% 28%;
  background-color: var(--avatar-tint, color-mix(in oklab, var(--ink) 6%, var(--paper)));
}

/* ── Photo placeholder (striped tint + mono label) ───────────── */
.photo-slot {
  position: relative;
  border-radius: 10px;
  overflow: hidden;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.06);
  background-repeat: repeat;
}
.photo-slot > .photo-label {
  position: absolute;
  left: 10px;
  bottom: 8px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  color: var(--ink-3);
  text-transform: uppercase;
  background: rgba(255, 255, 255, 0.7);
  padding: 2px 6px;
  border-radius: 4px;
  backdrop-filter: blur(2px);
}

/* ── Eyebrow pulse (used on landing + auth heads) ──────────────── */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--saffron-deep);
  font-weight: 600;
  margin-bottom: 14px;
}
.eyebrow .pulse {
  width: 7px;
  height: 7px;
  border-radius: 999px;
  background: var(--saffron);
  animation: roi-pulse 2s infinite;
}
@keyframes roi-pulse {
  0%   { box-shadow: 0 0 0 0 oklch(0.68 0.16 55 / 0.6); }
  100% { box-shadow: 0 0 0 12px oklch(0.68 0.16 55 / 0); }
}

/* ── Landing hero ─────────────────────────────────────────────── */
.landing-hero {
  padding: 88px 40px 72px;
  max-width: 1280px;
  margin: 0 auto;
  position: relative;
}
.landing-hero::before {
  content: '';
  position: absolute;
  inset: 0;
  background:
    radial-gradient(circle at 20% 20%, var(--saffron-soft) 0%, transparent 45%),
    radial-gradient(circle at 85% 60%, var(--green-soft) 0%, transparent 40%);
  opacity: 0.6;
  pointer-events: none;
}
.landing-inner { position: relative; max-width: 920px; }
.landing-h1 {
  font-family: var(--serif);
  font-size: clamp(52px, 8vw, 96px);
  line-height: 0.96;
  letter-spacing: -0.035em;
  margin: 20px 0 28px;
}
.landing-h1 em { font-style: italic; color: var(--saffron-deep); }
.landing-lede {
  font-size: 21px;
  line-height: 1.45;
  color: var(--ink-2);
  max-width: 680px;
  margin: 0 0 36px;
  text-wrap: pretty;
}
.landing-actions { display: flex; gap: 12px; flex-wrap: wrap; }

/* ── Auth pages (phone + otp) ────────────────────────────────── */
.auth-shell {
  min-height: calc(100vh - 120px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 40px 20px;
}
.auth-card {
  width: 100%;
  max-width: 420px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 40px 32px 32px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.06);
}
.auth-head { margin-bottom: 28px; }
.auth-h1 {
  font-family: var(--serif);
  font-size: 32px;
  letter-spacing: -0.02em;
  margin: 6px 0 10px;
  line-height: 1.1;
}
.auth-sub {
  font-size: 14px;
  color: var(--ink-2);
  line-height: 1.5;
  margin: 0;
}
.auth-form { display: flex; flex-direction: column; gap: 20px; }
.auth-flash {
  background: var(--green-soft);
  color: var(--green);
  padding: 10px 14px;
  border-radius: 8px;
  font-size: 13px;
  margin-bottom: 16px;
}
.auth-foot {
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--ink-4);
  margin: 20px 0 0;
  text-align: center;
}
.auth-resend {
  display: flex;
  justify-content: center;
  gap: 8px;
  margin-top: 22px;
  font-size: 12px;
  color: var(--ink-3);
}
.auth-link {
  background: none;
  border: none;
  padding: 0;
  color: var(--saffron-deep);
  cursor: pointer;
  text-decoration: underline;
  font: inherit;
  font-family: var(--mono);
  font-size: 12px;
}
.auth-link:hover { color: var(--ink); }

.w-full { width: 100%; justify-content: center; }

/* ── Form primitives ─────────────────────────────────────────── */
.form-field { display: flex; flex-direction: column; gap: 6px; }
.form-field-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
}
.form-label {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-4);
  font-weight: 500;
}
.form-required { color: var(--saffron-deep); margin-left: 4px; }
.form-hint {
  font-size: 11px;
  color: var(--ink-4);
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
  font-family: var(--sans);
}
.form-input {
  width: 100%;
  min-height: var(--tap);
  padding: 11px 14px;
  font-family: inherit;
  font-size: var(--fs-input);
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--line-2);
  border-radius: 8px;
  transition: border-color 0.15s, box-shadow 0.15s;
  box-sizing: border-box;
}
.form-input:focus {
  outline: none;
  border-color: var(--ink);
  box-shadow: 0 0 0 3px oklch(0.22 0.015 60 / 0.08);
}
.form-input::placeholder { color: var(--ink-4); }

/* ── Base form layout primitives ───────────────────────────────────
   These class names were used across forms (notably the events composer)
   but had NO CSS, so those pages rendered as a single unstyled column.
   `.form-row > * { min-width: 0 }` is the standing flex-overflow guard
   (flex children default to min-width:auto and blow the row past the
   viewport otherwise). Collapses to one column on phones. */
.form-group { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; }
.form-row { display: flex; gap: 16px; }
.form-row > * { flex: 1 1 0; min-width: 0; }
.form-fieldset {
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 16px;
  margin-bottom: 20px;
}
.form-fieldset > legend { font-weight: 600; padding: 0 6px; font-size: 14px; }
.form-radio-row { display: flex; flex-wrap: wrap; gap: 16px; align-items: center; }
.form-radio-row label { display: inline-flex; align-items: center; gap: 6px; min-height: var(--tap); }
.form-errors {
  background: var(--red-soft, #fbeaea);
  border: 1px solid var(--red, #c0392b);
  color: var(--red, #c0392b);
  border-radius: 8px;
  padding: 12px 14px;
  margin-bottom: 18px;
  font-size: 14px;
}
.form-errors ul { margin: 6px 0 0; padding-left: 18px; }
.event-compose-form { margin-top: 18px; }
.event-kind-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 10px; }
.event-kind-option {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-height: var(--tap);
  padding: 12px 14px;
  border: 1px solid var(--line-2);
  border-radius: 8px;
  cursor: pointer;
}
.event-kind-option:has(input:checked) { border-color: var(--ink); background: var(--ivory-2); }
.event-kind-label { font-weight: 600; font-size: 14px; }
.event-kind-desc { font-size: 11px; color: var(--ink-3); }
@media (max-width: 600px) {
  .form-row { flex-direction: column; gap: 0; }
}

.form-textarea {
  resize: vertical;
  min-height: 100px;
  line-height: 1.5;
  font-family: var(--sans);
}
.form-error {
  font-size: 12px;
  color: var(--red);
  margin: 4px 0 0;
  font-family: var(--sans);
}

.phone-input {
  display: flex;
  align-items: stretch;
  background: var(--paper);
  border: 1px solid var(--line-2);
  border-radius: 8px;
  transition: border-color 0.15s;
}
.phone-input:focus-within {
  border-color: var(--ink);
  box-shadow: 0 0 0 3px oklch(0.22 0.015 60 / 0.08);
}
.phone-prefix {
  padding: 11px 12px 11px 14px;
  font-family: var(--mono);
  font-size: 14px;
  color: var(--ink-3);
  border-right: 1px solid var(--line-2);
  display: flex;
  align-items: center;
}
.phone-input .form-input {
  border: none;
  box-shadow: none;
  background: transparent;
  border-radius: 0 8px 8px 0;
}
.phone-input .form-input:focus {
  border: none;
  box-shadow: none;
}

/* B4.6.1 — password input with show/hide eye toggle. */
.password-input-wrap {
  position: relative;
  display: block;
}
.password-input-wrap .form-input {
  padding-right: 52px; /* leave room for the 44px toggle + 8px right offset */
}
.password-toggle {
  position: absolute;
  top: 50%;
  right: 8px;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  background: transparent;
  border: 0;
  border-radius: 6px;
  color: var(--ink-3);
  cursor: pointer;
  transition: color 0.15s, background-color 0.15s;
}
.password-toggle:hover { color: var(--ink); background: oklch(0.22 0.015 60 / 0.06); }
.password-toggle:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}
[x-cloak] { display: none !important; }

.otp-input {
  font-family: var(--mono);
  font-size: 28px;
  letter-spacing: 0.5em;
  text-align: center;
  padding: 16px 14px;
}

/* ── Onboarding ──────────────────────────────────────────────── */
.onboarding-shell { padding: 40px 20px 80px; }
.onboarding-inner { max-width: 780px; margin: 0 auto; }
.onboarding-h1 {
  font-family: var(--serif);
  font-size: clamp(36px, 5vw, 52px);
  letter-spacing: -0.025em;
  line-height: 1;
  margin: 10px 0 16px;
}
.onboarding-sub {
  font-size: 17px;
  color: var(--ink-2);
  line-height: 1.5;
  max-width: 640px;
  margin: 0 0 40px;
  text-wrap: pretty;
}
.onboarding-form { display: flex; flex-direction: column; gap: 36px; }

.form-section {
  border: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.form-section-title {
  font-family: var(--serif);
  font-size: 22px;
  letter-spacing: -0.01em;
  margin: 0 0 4px;
  padding: 0 0 12px;
  border-bottom: 1px solid var(--line);
  color: var(--ink);
  width: 100%;
}
.form-grid-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
}
.form-grid-3 {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 12px;
}
.form-grid-4 {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
}
/* Phase C: 7-column grid for the Category radio cards now that PG +
   Coliving have joined as top-level categories. Collapses to 4 → 2 → 1
   at the same breakpoints as form-grid-5; the wide layout flows as a
   single 7-card row on desktop. */
.form-grid-7 {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 12px;
}
/* Compose Buyer: 6-column grid for the buyer-side category cards (no
   rental umbrella — buyers think in (category, transaction_type) pairs).
   Same responsive collapse as form-grid-7. */
.form-grid-6 {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 12px;
}
@media (max-width: 1280px) {
  .form-grid-6 { grid-template-columns: repeat(3, 1fr); }
  .form-grid-7 { grid-template-columns: repeat(4, 1fr); }
}
@media (max-width: 1099px) {
  .form-grid-6 { grid-template-columns: repeat(3, 1fr); }
  .form-grid-7 { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 900px) {
  .form-grid-4 { grid-template-columns: 1fr 1fr; }
  .form-grid-6 { grid-template-columns: 1fr 1fr; }
  .form-grid-7 { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 640px) {
  .form-grid-2 { grid-template-columns: 1fr; }
  .form-grid-3 { grid-template-columns: 1fr; }
  .form-grid-4 { grid-template-columns: 1fr; }
  .form-grid-6 { grid-template-columns: 1fr; }
  .form-grid-7 { grid-template-columns: 1fr; }
}

/* ── Compose listing v2 ──────────────────────────────────────────── */
.compose-listing .form-section { margin-bottom: 28px; }
.form-section-hint {
  font-size: 13px;
  color: var(--ink-3);
  margin: -4px 0 12px;
  line-height: 1.5;
}

/* Compact, inline-feeling fieldset (no big legend / hint block above) — for
 * a single-row fieldset like the negotiable checkbox sitting between the
 * price section and the motivation section. */
.form-section--inline { padding: 12px 0; margin-bottom: 12px; }
.form-section--inline > .form-section-title { display: none; }

/* Wrapped <label> + checkbox + hint pattern. Used for the price-negotiable
 * flag (and is generic — reuse for similar single-toggle UX). */
.form-checkbox-row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  cursor: pointer;
  padding: 10px 14px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--paper);
  transition: border-color 120ms ease, background 120ms ease;
}
.form-checkbox-row:hover { border-color: var(--saffron); background: var(--saffron-soft); }
.form-checkbox-row input[type="checkbox"] {
  margin-top: 2px;
  accent-color: var(--saffron-deep);
  flex-shrink: 0;
}
.form-checkbox-label {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: var(--fs-sm);
  color: var(--ink);
}
.form-checkbox-hint {
  font-size: var(--fs-xs);
  color: var(--ink-3);
}

/* Checkbox pill (amenity + plot flags) */
.checkbox-row { display: flex; flex-wrap: wrap; gap: 8px; }
.checkbox-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink-2);
  font-size: 13px;
  cursor: pointer;
  transition: background 0.1s, border-color 0.1s, color 0.1s;
}
.checkbox-pill:hover {
  background: color-mix(in oklab, var(--saffron) 6%, transparent);
  border-color: color-mix(in oklab, var(--saffron) 40%, var(--line));
}
.checkbox-pill input[type="checkbox"] {
  accent-color: var(--ink);
  margin: 0;
}
.checkbox-pill:has(input:checked) {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--paper);
}

/* Amenity grid */
.amenity-group { margin-bottom: 14px; }
.amenity-group:last-child { margin-bottom: 0; }
.amenity-group-title {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-3);
  margin-bottom: 8px;
}
.amenity-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

/* Photo dropzone */
.photo-dropzone {
  display: block;
  border: 2px dashed var(--line);
  border-radius: 12px;
  padding: 24px;
  background: var(--paper);
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s;
}
.photo-dropzone:hover, .photo-dropzone:focus-within {
  border-color: var(--saffron);
  background: color-mix(in oklab, var(--saffron) 5%, var(--paper));
}
.photo-dropzone-body {
  text-align: center;
}
.photo-dropzone-icon {
  font-size: 32px;
  line-height: 1;
  margin-bottom: 8px;
}
.photo-dropzone-prompt {
  font-size: 14px;
  font-weight: 500;
  color: var(--ink);
  margin-bottom: 4px;
}
.photo-dropzone-hint {
  font-size: 11px;
  color: var(--ink-3);
}

/* Photo thumbs */
.photo-thumbs {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 12px;
  margin-top: 14px;
}
.photo-thumb {
  margin: 0;
  border: 1px solid var(--line);
  border-radius: 8px;
  overflow: hidden;
  background: var(--paper);
}
.photo-thumb img {
  width: 100%;
  height: 110px;
  object-fit: cover;
  display: block;
}
.photo-thumb-label {
  width: 100%;
  border: none !important;
  border-top: 1px solid var(--line) !important;
  border-radius: 0 !important;
  font-size: 12px;
  padding: 6px 8px;
}
/* Per-thumbnail remove toggle in the edit form. Sits below the caption
 * input as a faint row; goes red on hover so the action reads. */
.photo-thumb-remove {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 8px;
  font-size: 11px;
  color: var(--ink-3);
  border-top: 1px solid var(--line);
  cursor: pointer;
  font-family: var(--mono);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  transition: color 120ms ease, background 120ms ease;
}
.photo-thumb-remove:hover { color: var(--red); background: var(--red-soft); }
.photo-thumb-remove input[type="checkbox"] { accent-color: var(--red); margin: 0; }

/* Alpine.js x-cloak — hides elements until Alpine has hydrated.
   Single canonical declaration; duplicates that previously lived
   scattered through the file were removed in the !important audit. */
[x-cloak] { display: none !important; }

.radio-card {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 14px 16px;
  border: 1px solid var(--line-2);
  border-radius: 10px;
  background: var(--paper);
  cursor: pointer;
  user-select: none;
  transition: border-color 120ms ease, background 120ms ease;
}
.radio-card input[type="radio"] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.radio-card:hover { border-color: var(--ink-3); }
.radio-card--selected {
  border-color: var(--ink);
  background: var(--paper-2, var(--paper));
  box-shadow: inset 0 0 0 1px var(--ink);
}
.radio-card-title {
  font-weight: 600;
  font-size: 14px;
  color: var(--ink);
}
.radio-card-hint {
  font-size: 12px;
  color: var(--ink-4);
}
.form-actions {
  display: flex;
  align-items: center;
  gap: 16px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
}
.form-actions--wizard { border-top: none; padding-top: 24px; }
.form-actions-row {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding-top: 16px;
  border-top: 1px solid var(--line);
  width: 100%;
}
.form-note { font-size: 11px; color: var(--ink-4); }
.form-note--warn { color: var(--saffron-deep); font-weight: 500; }

/* ── Compose wizard chrome ────────────────────────────────────────
   3-step listing wizard: Identify → Essentials → Enrich. Step indicator
   sits above the form, time hint sits between indicator and the first
   fieldset. Step buttons are clickable for past steps (jump-back),
   disabled for the current step and any future step (linear flow per
   Baymard — sending users forward without input creates dead-air UX).
*/
.wizard-steps {
  display: flex;
  align-items: stretch;
  gap: 8px;
  list-style: none;
  margin: 24px 0 8px;
  padding: 0;
  counter-reset: wizard-step;
}
.wizard-step {
  flex: 1 1 0;
  display: flex;
}
.wizard-step-button {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--paper);
  color: var(--ink-3);
  font-family: inherit;
  font-size: var(--fs-sm);
  text-align: left;
  cursor: pointer;
  transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.wizard-step-button:disabled {
  cursor: default;
}
.wizard-step-button:not(:disabled):hover {
  border-color: var(--ink-3);
  color: var(--ink-2);
}
.wizard-step-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--ivory-2);
  color: var(--ink-3);
  font-size: 12px;
  font-weight: 600;
}
.wizard-step--active .wizard-step-button {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--paper);
}
.wizard-step--active .wizard-step-num {
  background: var(--saffron);
  color: var(--ink);
}
.wizard-step--done .wizard-step-button {
  border-color: var(--line-2);
  color: var(--ink-2);
}
.wizard-step--done .wizard-step-num {
  background: var(--green);
  color: var(--paper);
}
.wizard-time-hint {
  margin: 0 0 24px;
  font-size: var(--fs-xs);
  color: var(--ink-4);
}

/* Per-step validation summary. Shown only when the broker tries to advance
   from a step with empty required fields (banner sits above the form,
   inside .compose-listing — same Alpine scope as the wizard state). */
.wizard-error-banner {
  margin: 0 0 20px;
  padding: 12px 16px;
  background: var(--red-soft);
  border: 1px solid var(--red);
  border-radius: 8px;
  color: var(--red);
  font-size: var(--fs-sm);
}
.wizard-error-banner ul { margin: 6px 0 0 18px; padding: 0; }
.wizard-error-banner li { line-height: 1.5; }

/* Server-side validation variant — rendered on a redirect-back from
   SaveListingFormRequest. Visually heavier than the client-side gate
   banner above because a server reject means the broker already tried
   to publish (vs. just advancing a step). Thicker left border draws
   the eye on a busy form. */
.wizard-error-banner--server {
  border-left-width: 4px;
  background: var(--red-soft);
}

/* Pause-and-resume draft banner (create flow only). Surfaced by
   ComposeListingController@show when the broker has an auto-saved
   in-progress listing. Saffron-tinted to read as "your work is safe
   here", deliberately distinct from the red validation banners above.
   --saffron flips for dark mode; the translucent fallback is theme-safe. */
.compose-draft-banner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 0 0 20px;
  padding: 12px 16px;
  background: var(--saffron-soft, rgba(255, 153, 51, 0.08));
  border: 1px solid var(--saffron);
  border-left-width: 4px;
  border-radius: 8px;
  font-size: var(--fs-sm);
  color: var(--ink-1);
}
.compose-draft-banner-text {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
}
.compose-draft-banner-note {
  flex-basis: 100%;
  color: var(--ink-4);
  font-size: var(--fs-xs);
}
.compose-draft-banner-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}
/* The discard form is a bare action wrapper — don't let it add layout. */
.compose-draft-banner-actions form { margin: 0; }

/* Transient "Draft saved" confirmation under the step hint. */
.compose-autosave-status {
  margin: -16px 0 16px;
  font-size: var(--fs-xs);
  color: var(--green);
}

/* ── Collapsible enrichment sections (Step 3) ─────────────────────
   <details><summary> for opt-in field groups. Closed by default to
   keep Step 3 scannable; open shows the contained fields. The summary
   reuses .form-section-title so the typography matches non-collapsible
   fieldsets above. */
.form-collapsible {
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 4px 16px 4px;
  background: var(--paper);
}
.form-collapsible[open] {
  padding: 4px 16px 16px;
}
.form-collapsible > summary {
  cursor: pointer;
  padding: 14px 0;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 10px;
  user-select: none;
}
.form-collapsible > summary::-webkit-details-marker { display: none; }
.form-collapsible > summary::before {
  content: '+';
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--ivory-2);
  color: var(--ink-2);
  font-size: 16px;
  font-weight: 600;
  line-height: 1;
  flex-shrink: 0;
  transition: transform 0.15s, background 0.15s;
}
.form-collapsible[open] > summary::before {
  content: '−';
  background: var(--saffron-soft);
}
.form-collapsible > summary:hover::before {
  background: var(--saffron-soft);
}

/* ── Slice P2.5: Multi-configuration editor ────────────────────────
   Primary listings (new launches) capture multiple BHK × property-type ×
   price tuples. Each row sits in its own card with subtle separation;
   rows can be removed individually. The "+ Add configuration" button
   sits below the row list. */
.config-editor {
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin-bottom: 16px;
}
.config-row {
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 16px;
  background: color-mix(in oklab, var(--paper) 96%, var(--saffron-soft));
}
.config-row > .form-grid-3,
.config-row > .form-grid-4 {
  margin-bottom: 12px;
}
.config-row > *:last-child {
  margin-bottom: 0;
}
.config-row-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
  padding-bottom: 8px;
  border-bottom: 1px dashed var(--line);
}
.config-row-label {
  font-size: var(--fs-xs);
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.config-row-remove {
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 4px 10px;
  font-size: 12px;
  color: var(--red);
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s;
}
.config-row-remove:hover {
  background: var(--red-soft);
  border-color: var(--red);
}
.config-add {
  align-self: flex-start;
  padding: 10px 16px;
  border: 1px dashed var(--line-2);
  border-radius: 8px;
  background: var(--paper);
  color: var(--ink-2);
  font-size: var(--fs-sm);
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.config-add:hover {
  background: var(--saffron-soft);
  border-color: var(--saffron);
  color: var(--ink);
}

@media (max-width: 640px) {
  .wizard-steps { flex-direction: column; gap: 6px; }
  .wizard-step-label { font-size: var(--fs-xs); }
}

.tag-grid { display: flex; flex-wrap: wrap; gap: 6px; }
.tag-checkbox {
  display: inline-flex;
  align-items: center;
  padding: 6px 12px;
  border-radius: 999px;
  border: 1px solid var(--line-2);
  background: var(--paper);
  font-size: 12px;
  color: var(--ink-2);
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
  transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.tag-checkbox input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.tag-checkbox.is-active,
.tag-checkbox:has(input:checked) {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}
.tag-checkbox:hover { border-color: var(--ink-3); }

/* ── Generic page shell (stub views) ─────────────────────────── */
.page-shell { padding: 20px 20px; }
.page-inner { max-width: 1200px; margin: 0 auto; }
.page-h1 {
  font-family: var(--serif);
  font-size: var(--fs-2xl);
  letter-spacing: -0.02em;
  margin: 6px 0 14px;
  line-height: var(--lh-heading);
  color: var(--ink);
}
.page-h1 em {
  font-style: italic;
  color: var(--saffron-deep);
}
.page-sub {
  font-size: var(--fs-md);
  color: var(--ink-2);
  line-height: var(--lh-body);
  max-width: 700px;
}
/* Brand color for unclassed text-flow anchors. Without this the
   browser default visited-link purple rendered against the dark-mode
   background as nearly invisible — reported on the developer
   projects edit page across THREE different wrappers (.page-sub,
   .eyebrow, .dash-section-sub). Instead of growing a whitelist of
   wrapper classes, the selector targets anchors WITHOUT a class so
   every purpose-built anchor (buttons .btn, nav links, badges,
   breadcrumb pills, etc.) keeps its own styling untouched.

   `a:not([class])` catches every `<a href="…">text</a>` that
   relies on flowing-text styling. Saffron-deep resolves in BOTH
   themes (light: AA-passing deep orange; dark: lighter saffron) so
   the fix works in either mode. Underline + offset signals "this
   is a link" without needing a separate visited-state color. */
a:not([class]) {
  color: var(--saffron-deep);
  text-decoration: underline;
  text-underline-offset: 2px;
}
a:not([class]):hover { color: var(--ink); }
.page-flash {
  background: var(--green-soft);
  color: var(--green);
  padding: 12px 16px;
  border-radius: 8px;
  font-size: 13px;
  margin-bottom: 20px;
}

/* ── Empty state (shared) ──────────────────────────────────────── */
.empty-state {
  padding: 40px 24px;
  text-align: center;
  border: 1px dashed var(--line-2);
  border-radius: 12px;
  background: var(--paper);
  color: var(--ink-3);
}
.empty-state-actions {
  display: flex;
  justify-content: center;
  gap: 12px;
  margin-top: 16px;
  flex-wrap: wrap;
}

/* ── Smart Matches feed ────────────────────────────────────────── */
.match-bucket {
  margin-top: 32px;
}
.match-bucket-header {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 12px;
  border-bottom: 1px solid var(--line);
  padding-bottom: 8px;
}
.match-bucket-title {
  font-family: var(--serif);
  font-size: 22px;
  margin: 0;
  color: var(--ink);
}
.match-bucket-count {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-4);
  letter-spacing: 0.04em;
}
.match-pairs {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.match-pair {
  border: 1px solid var(--line);
  background: var(--paper);
  border-radius: 12px;
  padding: 20px;
}
.match-pair-grid {
  display: grid;
  grid-template-columns: 1fr 100px 1fr;
  gap: 20px;
  align-items: start;
}
/* Mobile pair block — hidden on desktop. The mobile @media block
   below (at the end of app.css) swaps visibility: hides
   .match-pair-grid + shows .match-pair-mobile. This pair partial
   ships BOTH DOMs per pair article; CSS picks which one displays. */
.match-pair-mobile { display: none; }
@media (max-width: 800px) {
  .match-pair-grid { grid-template-columns: 1fr; }
}
.match-side {
  padding: 14px;
  border-radius: 10px;
  background: var(--paper-2, var(--paper));
  border: 1px solid var(--line);
}
.match-side--mine {
  background: var(--saffron-soft);
  border-color: var(--saffron);
}
.match-side-label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-4);
  margin-bottom: 10px;
}
.match-buyer-head {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 12px;
}
.match-initials {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--ink);
  color: var(--paper);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
  font-size: 13px;
  letter-spacing: 0.04em;
}
.match-buyer-vertical {
  font-weight: 600;
  font-size: 14px;
  color: var(--ink);
}
.match-buyer-purpose {
  font-size: 12px;
  color: var(--ink-3);
  margin-top: 2px;
}
.match-listing-title {
  margin: 0 0 4px;
  font-family: var(--serif);
  font-size: 18px;
  line-height: 1.25;
  color: var(--ink);
}
.match-listing-title a {
  color: inherit;
  text-decoration: none;
}
.match-listing-title a:hover { text-decoration: underline; }
.match-listing-locality {
  font-size: 12px;
  color: var(--ink-3);
  margin-bottom: 10px;
}
.match-data {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px 14px;
  margin: 0;
}
.match-data > div { min-width: 0; }
.match-data dt {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.match-data dd {
  margin: 1px 0 0;
  font-size: 13px;
  color: var(--ink);
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.match-dial {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 18px 0;
}
.match-dial-label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-4);
  margin-top: 4px;
}

/* ── Listing detail page ───────────────────────────────────────── */
/* Full-page redesign: hero gallery + 8-section main column + sticky
 * right rail. Replaces the previous bare two-column shell. Information
 * architecture is documented in resources/views/pages/listings/show.blade.php
 * and the partials under partials/_*.blade.php. */

.breadcrumb {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  font-size: var(--fs-xs);
  color: var(--ink-4);
  margin-bottom: 18px;
}
.breadcrumb a { color: var(--ink-3); text-decoration: none; }
.breadcrumb a:hover { color: var(--ink); text-decoration: underline; }

/* ── Hero gallery ────────────────────────────────────────────── */
.listing-gallery { margin-bottom: 28px; position: relative; }

.listing-hero {
  display: grid;
  grid-template-columns: 2fr 1fr;
  grid-template-rows: 1fr 1fr;
  gap: 6px;
  border-radius: 14px;
  overflow: hidden;
  aspect-ratio: 16 / 8;
  background: var(--paper-2);
  position: relative;
  isolation: isolate;
}
.listing-hero--n1 { grid-template-columns: 1fr; grid-template-rows: 1fr; }
.listing-hero--n1 .listing-hero-tile--lead { grid-column: 1; grid-row: 1; }
.listing-hero--n2 { grid-template-rows: 1fr; }
.listing-hero--n2 .listing-hero-tile--lead { grid-column: 1; grid-row: 1; }
.listing-hero--n2 .listing-hero-tile--top  { grid-column: 2; grid-row: 1; }

/* Mobile: collapse the hero to a single full-width lead image. The
   thumbnail rail below the hero (.listing-hero-rail) already shows
   every photo, so the desktop right-column thumbs are redundant on
   phone — they were rendering as wasted half-width with empty space
   on the right. Single-column + 4:3 aspect ratio reads as a proper
   mobile hero. The overlay pill (View all photos / Floor plans)
   stays anchored at the bottom of the hero via its own absolute
   positioning. */
@media (max-width: 800px) {
  .listing-hero,
  .listing-hero--n2,
  .listing-hero--n3 {
    grid-template-columns: 1fr;
    grid-template-rows: 1fr;
    aspect-ratio: 4 / 3;
  }
  .listing-hero .listing-hero-tile--lead {
    grid-column: 1;
    grid-row: 1;
  }
  .listing-hero-tile--top,
  .listing-hero-tile--bottom {
    display: none;
  }
}

/* Single-photo moodboard tile — fills the column-height gap when a
 * listing has only one photo. Editorial decorative panel: warm
 * gradient + line-art building SVG + RERA / status stamps. Mirrors
 * the v4 sample-matches treatment so the page still reads as
 * "curated", not "broken-empty". Only renders when $photoCount === 1. */
.listing-moodboard {
  margin-top: 12px;
  display: grid;
  grid-template-columns: 140px 1fr;
  gap: 18px;
  align-items: center;
  padding: 22px 24px;
  border-radius: 14px;
  background: linear-gradient(135deg, var(--saffron-soft) 0%, var(--cream) 60%, var(--paper-2) 100%);
  border: 1px solid var(--line);
  overflow: hidden;
  position: relative;
}
.listing-moodboard-art {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--terracotta-deep);
  opacity: 0.85;
}
.listing-moodboard-art svg { width: 100%; height: auto; max-width: 120px; }
.listing-moodboard-body { min-width: 0; }
.listing-moodboard-eyebrow {
  font-size: var(--fs-xs);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-3);
  font-weight: 700;
  margin-bottom: 0.5rem;
  display: flex;
  align-items: center;
  gap: 0.65rem;
}
.listing-moodboard-eyebrow::before {
  content: "";
  width: 1.4rem;
  height: 2px;
  background: var(--terracotta);
}
.listing-moodboard-place {
  font-size: var(--fs-lg);
  line-height: 1.2;
  color: var(--ink);
  font-weight: 400;
  letter-spacing: -0.01em;
  margin-bottom: 0.85rem;
}
.listing-moodboard-place em {
  font-style: italic;
  color: var(--terracotta-deep);
}
.listing-moodboard-stamps {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.listing-moodboard-stamp {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.35rem 0.7rem;
  border-radius: 999px;
  background: var(--paper);
  border: 1px solid var(--line);
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--ink-2);
  letter-spacing: 0.01em;
}
.listing-moodboard-stamp--rera { color: var(--moss); border-color: color-mix(in oklab, var(--moss) 30%, var(--line)); }
.listing-moodboard-stamp-mark {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--moss);
  color: var(--paper);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 10px;
  font-weight: 700;
}
.listing-moodboard-stamp-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--saffron-deep);
}
@media (max-width: 640px) {
  .listing-moodboard { grid-template-columns: 1fr; text-align: center; padding: 18px 18px 20px; }
  .listing-moodboard-art svg { max-width: 80px; }
  .listing-moodboard-stamps { justify-content: center; }
  .listing-moodboard-eyebrow { justify-content: center; }
}

/* Possession callout inside the moodboard — surfaces the dated handover
   above-fold (the rail shows only the status word). */
.listing-moodboard-possession {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.85rem;
  font-size: 14px;
  color: var(--ink-2);
}
.listing-moodboard-possession-icon { color: var(--saffron-deep); font-size: 15px; line-height: 1; }
.listing-moodboard-possession strong { color: var(--ink); font-weight: 600; }

/* Lifestyle-highlight stamps — a warmer tint than the RERA/status stamps
   so the row reads as "facts + lifestyle", not a flat repeat of the rail. */
.listing-moodboard-stamp--highlight {
  color: var(--terracotta-deep);
  border-color: color-mix(in oklab, var(--terracotta) 28%, var(--line));
}

/* ── Gallery column fills the tall-rail height (public PDP only) ───────
   .pl-hero is align-items:stretch, so the gallery grid column already
   stretches to match the (taller) contact rail. Make .listing-gallery a
   flex column and let the moodboard be the slack-absorber so the editorial
   panel grows to meet the bottom of the rail — no dead whitespace. Scoped
   to .pl-hero-a so the broker-internal gallery (which reuses
   .listing-gallery / .listing-hero unwrapped) is untouched. */
.pl-hero-a .pl-hero-gallery { min-height: 100%; }
.pl-hero-a .pl-hero-gallery .listing-gallery {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  margin-bottom: 0;
}
.pl-hero-a .pl-hero-gallery .listing-hero,
.pl-hero-a .pl-hero-gallery .listing-hero-rail { flex: 0 0 auto; }
.pl-hero-a .pl-hero-gallery .listing-moodboard { flex: 1 1 auto; }

.listing-hero-tile {
  position: relative;
  display: block;
  overflow: hidden;
  border: 0;
  padding: 0;
  cursor: zoom-in;
  background: var(--paper-2);
}
.listing-hero-tile img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 280ms ease;
}
.listing-hero-tile:hover img { transform: scale(1.03); }
.listing-hero-tile--lead   { grid-column: 1; grid-row: 1 / span 2; }
.listing-hero-tile--top    { grid-column: 2; grid-row: 1; }
.listing-hero-tile--bottom { grid-column: 2; grid-row: 2; }

.listing-hero--empty {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 8px;
  color: var(--ink-4);
}
.listing-hero-empty-mark { font-size: 36px; color: var(--saffron); }
.listing-hero-empty-text { font-family: var(--mono); font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; }

/* Floating control overlay — pills sit at bottom-left of the gallery. */
.listing-hero-overlay {
  position: absolute;
  bottom: 14px;
  left: 14px;
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  z-index: 2;
}
.listing-hero-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 13px;
  border-radius: 999px;
  background: color-mix(in oklab, var(--ink) 88%, transparent);
  color: var(--paper);
  font-size: var(--fs-xs);
  font-weight: 500;
  border: 0;
  cursor: pointer;
  text-decoration: none;
  backdrop-filter: blur(6px);
  transition: background 150ms ease, transform 100ms ease;
}
.listing-hero-pill:hover { background: var(--ink); transform: translateY(-1px); }
.listing-hero-pill-count {
  font-size: 10px;
  letter-spacing: 0.06em;
  background: var(--saffron);
  color: var(--ink);
  padding: 2px 7px;
  border-radius: 999px;
  font-weight: 600;
}
.listing-hero-pill--ghost {
  background: color-mix(in oklab, var(--paper) 90%, transparent);
  color: var(--ink);
}
.listing-hero-pill--ghost:hover { background: var(--paper); }

/* Thumb rail — sibling of the gallery box, only rendered for 4+ photos. */
.listing-hero-rail {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  scrollbar-width: thin;
  margin-top: 10px;
  padding: 2px 2px 8px;
}
.listing-hero-thumb {
  /* 2026-05-26 — flex: 1 0 110px (was 0 0 110px) so each thumbnail
     grows to fill the available rail width when there are only a
     handful of photos. 4-photo listing in a ~700px container = each
     thumb ~165px wide instead of clumping at 110px with whitespace.
     shrink=0 + the rail's overflow-x: auto keeps long lists scrollable
     once total width exceeds the container. The 4:3 aspect-ratio
     drives height, so taller-when-wider stays proportional. */
  flex: 1 0 110px;
  max-width: 200px;
  aspect-ratio: 4 / 3;
  border: 1px solid transparent;
  padding: 0;
  cursor: pointer;
  border-radius: 8px;
  overflow: hidden;
  background: var(--paper-2);
  transition: border-color 150ms ease, transform 100ms ease;
}
.listing-hero-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  opacity: 0.85;
  transition: opacity 150ms ease;
}
.listing-hero-thumb:hover img { opacity: 1; }
.listing-hero-thumb.is-active {
  border-color: var(--saffron);
  transform: translateY(-1px);
}

/* Lightbox overlay */
.listing-lightbox {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: color-mix(in oklab, var(--ink) 92%, transparent);
  display: flex;
  align-items: center;
  justify-content: center;
}
.listing-lightbox-stage {
  max-width: 92vw;
  max-height: 88vh;
  display: flex;
  align-items: center;
  justify-content: center;
}
.listing-lightbox-stage img {
  max-width: 92vw;
  max-height: 88vh;
  object-fit: contain;
  border-radius: 4px;
}
.listing-lightbox-close,
.listing-lightbox-nav {
  position: absolute;
  background: color-mix(in oklab, var(--paper) 92%, transparent);
  color: var(--ink);
  border: 0;
  /* 48 px tap floor per the project rubric. 44 px was sub-floor;
     bumped so a broker on a phone reliably hits close/next instead
     of accidentally swiping the underlying image carousel. */
  width: 48px;
  height: 48px;
  border-radius: 999px;
  cursor: pointer;
  font-size: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 100ms ease;
}
/* Close button positioned with safe-area inset so it clears the iOS
   notch + Android status bar on full-bleed phones. Tokens are
   centralised in tokens.css per the safe-area lint. */
.listing-lightbox-close {
  top: calc(20px + var(--inset-top));
  right: calc(20px + var(--inset-right));
  font-size: 18px;
}
.listing-lightbox-nav--prev { left: calc(16px + var(--inset-left));  top: 50%; transform: translateY(-50%); }
.listing-lightbox-nav--next { right: calc(16px + var(--inset-right)); top: 50%; transform: translateY(-50%); }
.listing-lightbox-nav--prev:hover { transform: translateY(-50%) translateX(-2px); }
.listing-lightbox-nav--next:hover { transform: translateY(-50%) translateX(2px); }
/* Mobile: pull the nav buttons closer to the screen edges so the
   image stage retains more width. Both arrows stay visible (swipe
   is an ADDITIONAL gesture, not a replacement) so brokers who don't
   know about swipe still have a tap path. */
@media (max-width: 800px) {
  .listing-lightbox-nav--prev { left: 8px; }
  .listing-lightbox-nav--next { right: 8px; }
}
.listing-lightbox-counter {
  position: absolute;
  bottom: 24px;
  color: var(--paper);
  font-size: var(--fs-xs);
  letter-spacing: 0.08em;
}
.listing-lightbox-meta {
  position: absolute;
  bottom: 18px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  text-align: center;
  max-width: 80vw;
}
.listing-lightbox-meta .listing-lightbox-counter {
  position: static;
}
.listing-lightbox-caption {
  color: var(--paper);
  font-size: var(--fs-sm);
  opacity: 0.92;
}

/* ── Layout ──────────────────────────────────────────────────── */
.listing-detail {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 360px;
  gap: 40px;
  align-items: start;
}
.listing-detail-main { min-width: 0; }
/* Sticky lives on the GRID ITEM (the aside) — putting it on an inner
 * wrapper doesn't engage in CSS Grid because the inner element shrinks
 * to its content. align-self:start keeps the aside content-height
 * inside a row that's tall enough for stickiness to take effect. */
.listing-detail-side {
  position: sticky;
  top: 88px;
  align-self: start;
  max-height: calc(100vh - 96px);
  overflow-y: auto;
  scrollbar-width: thin;
  padding-right: 4px;
}
.listing-detail-side-sticky {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
@media (max-width: 900px) {
  .listing-detail { grid-template-columns: 1fr; gap: 28px; }
  .listing-detail-side {
    position: static;
    max-height: none;
    overflow: visible;
  }
  /* Single column (NOT 1.6fr 1fr — the comment above pins the
     intent as "collapses to one column" but the original rule
     shipped with a 2-col bug that left ~40% of viewport empty
     on the right of the lead image). The thumbnail rail below
     surfaces the secondary photos. */
  .listing-hero { aspect-ratio: 4 / 3; grid-template-columns: 1fr; grid-template-rows: 1fr; }

  /* Gallery gap-fill is a >900px two-column concern. At <=900px the public
     PDP hero collapses to one column and the rail stacks below (no side
     gap), so reset the flex column and drop the moodboard — the rail +
     below-fold body-intro already carry locality / status / possession /
     highlights, and this keeps a decorative panel from landing above the
     title in the single-column scroll. */
  .pl-hero-a .pl-hero-gallery .listing-gallery { display: block; flex: 0 0 auto; }
  .pl-hero-a .pl-hero-gallery .listing-moodboard { display: none; }
}

/* ── Eyebrow + title block ───────────────────────────────────── */
.listing-eyebrow {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  font-size: var(--fs-xs);
  color: var(--ink-3);
  margin-bottom: 8px;
}
.listing-eyebrow-pill {
  display: inline-flex;
  align-items: center;
  padding: 3px 10px;
  border-radius: 999px;
  border: 1px solid var(--line-2);
  background: var(--paper);
  color: var(--ink-2);
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  font-size: 10px;
}
.listing-eyebrow-pill--accent {
  border-color: var(--saffron);
  background: var(--saffron-soft);
  color: var(--saffron-deep);
}
.listing-eyebrow-meta { color: var(--ink-4); letter-spacing: 0.04em; }

.listing-detail-title {
  font-family: var(--serif);
  font-size: var(--fs-1.5xl);
  line-height: var(--lh-tight);
  letter-spacing: -0.01em;
  margin: 4px 0 8px;
  color: var(--ink);
}
.listing-detail-subtitle {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  font-size: var(--fs-sm);
  color: var(--ink-3);
  margin-bottom: 28px;
}
.listing-detail-society {
  font-weight: 600;
  color: var(--ink);
}
.listing-detail-divider { color: var(--ink-4); }

/* ── Section wrapper (used by every §1–§9 partial) ──────────── */
.listing-section { margin: 36px 0; }
.listing-section-title {
  font-family: var(--serif);
  font-size: var(--fs-lg);
  letter-spacing: -0.005em;
  margin: 0 0 14px;
  color: var(--ink);
  position: relative;
  padding-bottom: 10px;
}
.listing-section-title::after {
  content: '';
  position: absolute;
  bottom: 0;
  left: 0;
  width: 32px;
  height: 2px;
  background: var(--saffron);
  border-radius: 2px;
}

/* ── §1 Key facts grid ───────────────────────────────────────── */
/* Property details groups — vertical stack of subsection blocks, each
 * with a small mono heading and its own keyfacts grid. Lets the reader
 * scan by category (Configuration / Area / Building / Move-in) instead
 * of one undifferentiated tile wall. */
.listing-keyfacts-groups {
  display: flex;
  flex-direction: column;
  gap: 22px;
}
.listing-keyfacts-group-title {
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin: 0 0 10px;
  font-weight: 600;
}
.listing-keyfacts {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 12px;
  margin: 0;
}
.listing-keyfact {
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--paper);
  min-width: 0;
}
.listing-keyfact dt {
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-4);
  margin-bottom: 6px;
}
.listing-keyfact dd {
  margin: 0;
  font-size: var(--fs-md);
  font-weight: 500;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

/* ── §2 Description ──────────────────────────────────────────── */
/* The About-this-property block now receives RENDERED HTML from
 * DescriptionRenderer (CommonMark for local listings, nl2br plain text
 * for cache listings). Removed `white-space: pre-line` — it was doubling
 * line breaks against the explicit <br> tags from nl2br. */
.listing-detail-description {
  color: var(--ink-2);
  line-height: var(--lh-body);
  font-size: var(--fs-base);
  max-width: 68ch;
}
.listing-detail-description p {
  margin: 0 0 14px;
}
.listing-detail-description p:last-child { margin-bottom: 0; }
.listing-detail-description h2,
.listing-detail-description h3,
.listing-detail-description h4 {
  font-family: var(--serif);
  color: var(--ink);
  margin: 22px 0 8px;
  line-height: var(--lh-tight);
}
.listing-detail-description h2 { font-size: var(--fs-lg); }
.listing-detail-description h3 { font-size: var(--fs-md); }
.listing-detail-description h4 { font-size: var(--fs-base); }
.listing-detail-description ul,
.listing-detail-description ol {
  margin: 0 0 14px;
  padding-left: 22px;
}
.listing-detail-description li { margin: 4px 0; }
.listing-detail-description strong { color: var(--ink); font-weight: 600; }
.listing-detail-description em { font-style: italic; }
.listing-detail-description a {
  color: var(--saffron-deep);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.listing-detail-description a:hover { color: var(--ink); }
.listing-detail-description blockquote {
  margin: 14px 0;
  padding: 8px 16px;
  border-left: 3px solid var(--saffron);
  background: var(--saffron-soft);
  color: var(--ink);
  font-style: italic;
}
.listing-detail-description code {
  font-family: var(--mono);
  font-size: 0.92em;
  padding: 1px 5px;
  background: var(--paper-2);
  border: 1px solid var(--line);
  border-radius: 4px;
}
.listing-detail-description hr {
  border: 0;
  border-top: 1px dashed var(--line);
  margin: 18px 0;
}

/* ── §3 Amenities grid ───────────────────────────────────────── */
.listing-amenity-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 14px 18px;
  list-style: none;
  margin: 0;
  padding: 0;
}
.listing-amenity {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border-radius: 8px;
  background: var(--paper);
  border: 1px solid var(--line);
}
.amenity-icon-svg { color: var(--saffron-deep); flex-shrink: 0; }
.listing-amenity-label {
  font-size: var(--fs-sm);
  color: var(--ink-2);
}

/* ── §4 Project & §5 Location meta rows ──────────────────────── */
.listing-meta-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 14px 22px;
  margin: 0;
}
.listing-meta-row dt {
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-4);
  margin-bottom: 4px;
}
.listing-meta-row dd {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--ink);
}

.listing-location-meta {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 16px;
  font-size: var(--fs-sm);
  color: var(--ink-2);
}
.listing-location-line { display: flex; align-items: center; gap: 8px; }
.listing-location-pin { color: var(--saffron); }
.listing-location-pincode { color: var(--ink-3); font-size: var(--fs-xs); }
.listing-location-address {
  margin-top: 4px;
  padding: 12px 14px;
  border-radius: 8px;
  background: var(--saffron-soft);
  border: 1px dashed var(--saffron);
}
.listing-location-address-label {
  display: block;
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--saffron-deep);
  margin-bottom: 4px;
}
.listing-map-wrap {
  border-radius: 12px;
  overflow: hidden;
  border: 1px solid var(--line);
  aspect-ratio: 16 / 9;
  background: var(--paper-2);
}
.listing-map { width: 100%; height: 100%; border: 0; display: block; }
.listing-map-fallback {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-sm);
  color: var(--ink-2);
  text-decoration: none;
  border-bottom: 1px dashed var(--line-2);
  padding-bottom: 2px;
}
.listing-map-fallback:hover { color: var(--ink); border-color: var(--ink-3); }

/* ── §6 Floor plans ──────────────────────────────────────────── */
.listing-floorplan-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 14px;
}
.listing-floorplan {
  display: block;
  width: 100%;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 10px;
  overflow: hidden;
  background: var(--paper);
  text-decoration: none;
  color: inherit;
  cursor: pointer;
  font: inherit;
  text-align: left;
  transition: border-color 150ms ease, transform 100ms ease, box-shadow 150ms ease;
}
.listing-floorplan:hover {
  border-color: var(--saffron);
  transform: translateY(-2px);
  box-shadow: 0 6px 18px -10px color-mix(in oklab, var(--ink) 50%, transparent);
}
.listing-floorplan:focus-visible {
  outline: 2px solid var(--saffron);
  outline-offset: 2px;
}
.listing-floorplan img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: contain;
  background: var(--paper-2);
  display: block;
}
.listing-floorplan-label {
  display: block;
  padding: 8px 12px;
  font-size: var(--fs-xs);
  color: var(--ink-3);
  border-top: 1px solid var(--line);
}

/* ── §7 Video tour ───────────────────────────────────────────── */
.listing-video-wrap {
  border-radius: 12px;
  overflow: hidden;
  border: 1px solid var(--line);
  aspect-ratio: 16 / 9;
  background: var(--ink);
}
.listing-video { width: 100%; height: 100%; border: 0; display: block; }

/* ── §8 Tags ─────────────────────────────────────────────────── */
.listing-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

/* ── §9 Compliance & source footer-strip ─────────────────────── */
.listing-compliance {
  margin-top: 48px;
  padding-top: 20px;
  border-top: 1px dashed var(--line);
}
.listing-compliance-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px 22px;
  font-size: var(--fs-xs);
  color: var(--ink-4);
}
.listing-compliance-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px;
  border-radius: 6px;
  background: var(--green-soft);
  color: var(--green);
  font-size: 11px;
  font-weight: 500;
}
.listing-compliance-badge--rera .listing-compliance-badge-mark {
  width: 16px;
  height: 16px;
  border-radius: 999px;
  background: var(--green);
  color: var(--paper);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 10px;
  font-weight: 700;
}
.listing-compliance-badge-label { letter-spacing: 0.06em; text-transform: uppercase; font-size: 10px; }
.listing-compliance-badge-state { font-weight: 600; }
.listing-compliance-badge-id { font-size: 10px; color: var(--ink-3); }
.listing-compliance-source { color: var(--ink-3); }
.listing-compliance-date { color: var(--ink-4); }
.listing-compliance-id { margin-left: auto; color: var(--ink-4); }

/* ── Sticky right rail: price card / broker card / owner card ── */
.listing-price-card,
.listing-broker-card,
.listing-owner-card {
  padding: 22px 22px 20px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--paper);
}
.listing-price-card {
  background: linear-gradient(180deg, var(--paper) 0%, var(--paper-2) 120%);
}
.listing-price-label,
.listing-broker-label,
.listing-owner-label {
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-4);
  margin-bottom: 6px;
}
.listing-price-value {
  font-family: var(--serif);
  font-size: var(--fs-xl);
  color: var(--ink);
  line-height: 1.05;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
}
.listing-price-persqft {
  font-size: var(--fs-xs);
  color: var(--ink-3);
  margin-top: 6px;
}
.listing-price-offer {
  margin-top: 10px;
  padding: 6px 10px;
  border-radius: 6px;
  background: var(--saffron-soft);
  color: var(--saffron-deep);
  font-size: var(--fs-xs);
  font-weight: 500;
  display: inline-block;
}
/* Inline pill near the ask price — set when broker ticks "Price is
 * negotiable" on the compose form. Visible signal for visitors that
 * there's room to talk. Intentionally subdued (green not saffron) so it
 * reads as informational, not promotional. */
.listing-price-negotiable {
  display: inline-block;
  margin-top: 8px;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--green-soft);
  color: var(--green);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.listing-price-rera {
  display: inline-flex;
  align-items: flex-start;
  gap: 8px;
  margin-top: 14px;
  padding: 6px 10px;
  border-radius: 6px;
  background: var(--green-soft);
  color: var(--green);
  font-size: 11px;
  font-weight: 500;
}
.listing-price-rera-mark {
  width: 16px;
  height: 16px;
  border-radius: 999px;
  background: var(--green);
  color: var(--paper);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 10px;
  font-weight: 700;
  flex-shrink: 0;
  margin-top: 1px;
}
.listing-price-rera-body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  line-height: 1.35;
}
.listing-price-rera-num {
  opacity: 0.85;
}
.listing-price-rera-verify {
  font-size: 10px;
  color: var(--green);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.listing-price-rera-verify:hover {
  text-decoration: none;
}

.listing-facts {
  margin: 18px 0 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px 16px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
}
.listing-facts > div { min-width: 0; }
.listing-facts dt {
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-4);
  margin-bottom: 2px;
}
.listing-facts dd {
  margin: 0;
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  overflow: hidden;
  text-overflow: ellipsis;
}

.listing-detail-actions {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.listing-detail-actions .btn,
.listing-detail-actions .save-form,
.listing-detail-actions .save-form .btn { width: 100%; }
/* The share rocket renders inline-block by default; in the stacked CTA
   column it should fill the width like Save / Stamp-duty / Back. */
.listing-detail-actions .share-rocket-wrap { display: block; width: 100%; }
.listing-detail-actions .share-rocket { width: 100%; justify-content: center; }

/* Broker card */
.listing-broker-head {
  display: flex;
  gap: 12px;
  align-items: center;
  margin-top: 4px;
}
.listing-broker-avatar,
.listing-broker-avatar-fallback {
  width: 44px;
  height: 44px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  font-weight: 600;
  font-size: var(--fs-sm);
  color: var(--ink);
  object-fit: cover;
}
.listing-broker-head-text { min-width: 0; }
.listing-broker-name {
  font-weight: 600;
  font-size: var(--fs-base);
  color: var(--ink);
  line-height: 1.25;
}
.listing-broker-name a { color: inherit; text-decoration: none; }
.listing-broker-name a:hover { text-decoration: underline; }
.listing-broker-firm {
  font-size: var(--fs-xs);
  color: var(--ink-3);
  margin-top: 2px;
}
.listing-broker-stats {
  display: flex;
  gap: 14px;
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}
.listing-broker-stat {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.listing-broker-stat-value {
  font-family: var(--serif);
  font-size: var(--fs-md);
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.listing-broker-stat-label {
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.listing-broker-stat--badge .listing-broker-stat-value { color: var(--green); }
.listing-broker-contacts {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}
.listing-broker-link {
  font-size: var(--fs-sm);
  color: var(--ink-2);
  text-decoration: none;
}
.listing-broker-link:hover { color: var(--ink); text-decoration: underline; }

/* Owner-only card (commission + private note) */
.listing-owner-card {
  background: var(--saffron-soft);
  border-color: var(--saffron);
}
.listing-owner-row { font-size: var(--fs-sm); margin-top: 4px; color: var(--ink); }
.listing-owner-note {
  font-size: var(--fs-sm);
  color: var(--ink-2);
  white-space: pre-line;
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px dashed var(--saffron);
}
.listing-owner-hint { font-size: 10px; color: var(--saffron-deep); margin-top: 10px; letter-spacing: 0.06em; }

/* Claim & enrich card — shown to the original DB.com associate only,
 * on an unclaimed cache row. Same saffron palette as the owner card so
 * it reads as "this belongs to you". */
.listing-claim-card {
  padding: 18px 20px 16px;
  border: 1px solid var(--saffron);
  border-radius: 14px;
  background: var(--saffron-soft);
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.listing-claim-eyebrow {
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--saffron-deep);
}
.listing-claim-text {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--ink-2);
  line-height: var(--lh-body);
}
.listing-claim-cta { width: 100%; }

/* ── Intro request card ──────────────────────────────────────── */
.intro-match-card {
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 18px;
  background: var(--paper);
  margin: 16px 0 24px;
}
.intro-match-row {
  display: grid;
  grid-template-columns: 1fr 80px 1fr;
  gap: 20px;
  align-items: center;
}
@media (max-width: 700px) {
  .intro-match-row { grid-template-columns: 1fr; }
}
.intro-match-label {
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.intro-match-value {
  font-weight: 600;
  font-size: 14px;
  color: var(--ink);
  margin-top: 2px;
}
.intro-match-meta {
  font-size: 12px;
  color: var(--ink-3);
  margin-top: 2px;
}
.intro-match-score {
  display: flex;
  flex-direction: column;
  align-items: center;
}
.intro-match-score-value {
  font-family: var(--serif);
  font-size: 28px;
  line-height: 1;
}
.intro-match-score-label {
  font-size: 10px;
  color: var(--ink-4);
  margin-top: 2px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* ── Intros inbox ────────────────────────────────────────────── */
.intros-lanes {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
  margin-top: 24px;
}
@media (max-width: 900px) {
  .intros-lanes { grid-template-columns: 1fr; }
}
.intros-lane-title {
  font-family: var(--serif);
  font-size: 20px;
  margin: 0 0 12px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--line);
}
.intro-card {
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 16px;
  background: var(--paper);
  margin-bottom: 12px;
}
.intro-card--pending {
  border-color: var(--saffron);
  background: var(--saffron-soft);
}
.intro-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
}
.intro-card-label {
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-4);
  margin-bottom: 2px;
}
.intro-card-name {
  font-weight: 600;
  font-size: 14px;
}
.intro-card-time {
  font-size: 11px;
  color: var(--ink-4);
  margin-top: 2px;
}
.intro-card-note {
  margin: 10px 0;
  padding: 10px 14px;
  border-left: 2px solid var(--ink-4);
  color: var(--ink-2);
  font-style: italic;
  font-size: 14px;
  background: var(--paper-2, transparent);
}
.intro-card-split {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 8px 14px;
  margin: 10px 0;
}
.intro-card-split dt {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.intro-card-split dd {
  margin: 1px 0 0;
  font-size: 13px;
  color: var(--ink);
}
.intro-card-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 10px;
  align-items: center;
}
.intro-decline-form {
  display: flex;
  gap: 6px;
  align-items: center;
  flex: 1;
  min-width: 240px;
}
.intro-decline-reason {
  flex: 1;
}
.intro-card-decline {
  font-size: 11px;
  color: var(--red, #991b1b);
  margin: 8px 0;
}

/* ── Conversation thread ─────────────────────────────────────── */
.conversation-layout {
  display: grid;
  grid-template-columns: 1fr 320px;
  gap: 32px;
  align-items: start;
}
@media (max-width: 900px) {
  .conversation-layout { grid-template-columns: 1fr; }
}
.conversation-main { min-width: 0; }
.conversation-head {
  border-bottom: 1px solid var(--line);
  padding-bottom: 12px;
  margin-bottom: 20px;
}
.conversation-title {
  font-family: var(--serif);
  font-size: 28px;
  margin: 0;
}
.conversation-sub {
  font-size: 12px;
  color: var(--ink-3);
  margin-top: 4px;
}
.conversation-thread {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin-bottom: 20px;
  max-height: 520px;
  overflow-y: auto;
  padding: 4px;
}
.message {
  max-width: 80%;
  padding: 12px 14px;
  border-radius: 12px;
  background: var(--paper);
  border: 1px solid var(--line);
  align-self: flex-start;
}
.message--mine {
  align-self: flex-end;
  background: var(--saffron-soft);
  border-color: var(--saffron);
}
.message-meta {
  font-size: 10px;
  color: var(--ink-4);
  letter-spacing: 0.04em;
  margin-bottom: 4px;
}
.message-body {
  font-size: 14px;
  line-height: 1.5;
  white-space: pre-line;
  /* Long URLs/IDs without spaces would otherwise overflow the
     bubble horizontally and cascade into a page-level scroll
     break (visible on /conversations/{c} because the sticky
     composer has a -14 px negative-margin bleed). */
  overflow-wrap: anywhere;
  word-break: break-word;
  color: var(--ink);
}
/* System-style messages — intro accept seed, contact-share events,
   close events, abuse events. Centered, italic, no avatar / sender
   meta. The kind suffix on the wrapping div lets future variants
   (e.g., a saffron tint for contact-share) extend without rewiring. */
.message-system {
  align-self: center;
  text-align: center;
  font-style: italic;
  color: var(--ink-2);
  font-size: 13px;
  padding: 8px 16px;
  margin: 6px 0;
  background: var(--ivory-2);
  border-radius: 999px;
  max-width: 80%;
}
.message-system-time {
  font-size: 10px;
  color: var(--ink-3);
  margin-top: 2px;
  font-style: normal;
}
.message-system--contact_share {
  background: color-mix(in oklab, var(--saffron-deep, #d8a35e) 8%, var(--paper));
  color: var(--ink);
  font-weight: 500;
  font-style: normal;
}
.message-system--abuse_event {
  background: color-mix(in oklab, #b04545 12%, var(--paper));
  color: var(--ink);
  font-style: normal;
}
/* Closed banner — top of the chat thread when conversation.closed_at
   is set. Variant per close_reason. */
.conversation-closed-banner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 12px 16px;
  border-radius: 10px;
  text-align: center;
  margin-bottom: 12px;
  font-size: 13px;
}
.conversation-closed-banner strong {
  font-family: var(--serif);
  font-size: 15px;
}
.conversation-closed-banner--no-deal {
  background: var(--ivory-2);
  border: 1px solid var(--line);
  color: var(--ink-2);
}
.conversation-closed-banner--abuse {
  background: color-mix(in oklab, #b04545 10%, var(--paper));
  border: 1px solid color-mix(in oklab, #b04545 45%, var(--line));
  color: #7a2a2a;
}
/* Contact-share right-rail block. */
.conversation-share-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.share-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.share-row--other .share-row-label,
.share-row--done .share-row-label {
  color: var(--ink-2);
  font-size: 13px;
}
.share-row-label { font-size: 13px; color: var(--ink); }
.share-row-state {
  font-size: 11px;
  color: var(--ink-3);
  letter-spacing: 0.02em;
}
.share-row--done .share-row-state {
  color: var(--saffron-deep, #d8a35e);
}
.share-hint {
  font-size: 11px;
  color: var(--ink-3);
  line-height: 1.4;
  margin: 4px 0 0;
}
/* Close + report block — sits at the bottom of the rail. The report
   form expands on click via Alpine x-show. */
.conversation-close-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.close-row {
  display: flex;
  align-items: center;
  gap: 10px;
  justify-content: space-between;
}
.close-row-hint {
  font-size: 11px;
  color: var(--ink-3);
}
.close-row-report {
  background: transparent;
  border: 0;
  padding: 0;
  text-align: left;
  font-size: 12px;
  color: var(--ink-3);
  cursor: pointer;
  letter-spacing: 0.02em;
  position: relative;
}
/* Tap-floor overlay — visible chip stays compact on desktop via
   ::before pseudo. Mobile bumps the VISIBLE control to var(--tap)
   in the conversation polish @media block. */
.close-row-report::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  min-width: var(--tap);
  min-height: var(--tap);
  transform: translate(-50%, -50%);
}
.close-row-report:hover { color: #b04545; }
.close-report-form {
  display: flex;
  flex-direction: column;
  gap: 10px;
  border-top: 1px dashed var(--line);
  padding-top: 12px;
  margin-top: 4px;
}
.conversation-composer {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.conversation-composer-actions {
  display: flex;
  justify-content: flex-end;
}
.conversation-side {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.conversation-context-card {
  padding: 16px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--paper);
}
.conversation-context-title {
  font-weight: 600;
  font-size: 15px;
  margin-top: 4px;
}
.conversation-context-title a { color: inherit; }
.conversation-context-meta {
  font-size: 12px;
  color: var(--ink-3);
  margin-top: 4px;
}
.conversation-buyer-note {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px dashed var(--line);
}
.conversation-buyer-note p {
  margin: 4px 0 0;
  font-size: 13px;
  color: var(--ink-2);
  white-space: pre-line;
}

/* ── Broker profile page ─────────────────────────────────────── */
.broker-profile {
  display: grid;
  grid-template-columns: 1fr 320px;
  gap: 32px;
  align-items: start;
  margin-top: 12px;
}
@media (max-width: 900px) {
  .broker-profile { grid-template-columns: 1fr; }
}
.broker-profile-main { min-width: 0; }
.broker-profile-head {
  display: flex;
  align-items: center;
  gap: 20px;
  margin-bottom: 20px;
}
.broker-profile-avatar {
  width: 96px;
  height: 96px;
  border-radius: 50%;
  object-fit: cover;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.08);
}
.broker-profile-head-body { flex: 1; min-width: 0; }
.broker-profile-name {
  font-family: var(--serif);
  font-size: 32px;
  line-height: 1.1;
  margin: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  color: var(--ink);
}
.broker-profile-meta {
  display: flex;
  gap: 6px;
  align-items: center;
  flex-wrap: wrap;
  color: var(--ink-3);
  font-size: 14px;
  margin-top: 4px;
}
.broker-profile-actions { flex-shrink: 0; }

.broker-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 14px 20px;
  padding: 20px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--paper);
  margin: 0 0 28px;
}
.broker-stats > div { min-width: 0; }
.broker-stats dt {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.broker-stats dd {
  margin: 2px 0 0;
  font-family: var(--serif);
  font-size: 22px;
  line-height: 1;
  color: var(--ink);
}
.broker-profile-section { margin: 24px 0; }
.broker-profile-section-title {
  font-family: var(--serif);
  font-size: 20px;
  margin: 0 0 10px;
}
.broker-profile-bio {
  color: var(--ink-2);
  line-height: 1.55;
  white-space: pre-line;
  margin: 0;
}
.broker-profile-side {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.broker-sidecard {
  padding: 16px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--paper);
}
.broker-sidecard-label {
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-4);
  margin-bottom: 8px;
}
.broker-sidecard-row {
  font-size: 13px;
  color: var(--ink);
  margin-bottom: 6px;
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}
.broker-sidecard-link {
  display: block;
  margin-top: 4px;
  font-size: 13px;
  color: var(--ink);
  text-decoration: none;
}
.broker-sidecard-link:hover { text-decoration: underline; }

/* ── Claim banner ────────────────────────────────────────────── */
.claim-banner {
  padding: 24px;
  border: 1px solid var(--saffron);
  background: var(--saffron-soft);
  border-radius: 12px;
  margin-bottom: 24px;
}
.claim-banner-title {
  font-family: var(--serif);
  font-size: 24px;
  margin: 0 0 8px;
}
.claim-banner-body {
  color: var(--ink-2);
  font-size: 14px;
  line-height: 1.5;
  margin: 0 0 14px;
}
.claim-banner-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

/* Inline modifier — slim saffron callout for in-page nudges (e.g. the
 * broker-profile listings-tab claim prompt). Reuses the same saffron
 * border + background tokens; trims padding and typography for an
 * above-the-stream banner that doesn't dominate the viewport. */
.claim-banner--inline {
  padding: 14px 18px;
  border-radius: 8px;
  margin: 0 0 18px;
}
.claim-banner--inline .claim-banner-title {
  font-family: var(--sans);
  font-size: 15px;
  font-weight: 600;
  margin: 0 0 2px;
}
.claim-banner--inline .claim-banner-body {
  font-size: 13px;
  margin: 0;
}
.claim-banner--inline .claim-banner-actions {
  margin-top: 10px;
}

/* Per-listing claim list under the welcome banner. Compact rows so a
 * shadow with 50 attributed brochures can scan them quickly. */
.claim-listing-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.claim-listing {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 16px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 10px;
}
.claim-listing-text {
  flex: 1 1 auto;
  min-width: 0;
  text-decoration: none;
  color: inherit;
}
.claim-listing-title {
  font-weight: 600;
  font-size: var(--fs-sm);
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.claim-listing-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 2px;
  font-size: var(--fs-xs);
  color: var(--ink-3);
}
.claim-listing-divider { color: var(--ink-4); }
.claim-listing-action { flex: 0 0 auto; }

/* ── Directory ──────────────────────────────────────────────── */
.directory-filters {
  display: flex;
  gap: 10px;
  align-items: center;
  flex-wrap: wrap;
  padding: 14px;
  border: 1px solid var(--line);
  background: var(--paper);
  border-radius: 10px;
  margin-bottom: 20px;
}
.directory-filters .form-input { max-width: 220px; }
.directory-check {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--ink-2);
  font-family: var(--mono);
  letter-spacing: 0.04em;
}
.roi-paginator {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 6px;
  font-family: var(--mono);
  font-size: 12px;
}
.roi-pag-num,
.roi-pag-step {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 34px;
  height: 34px;
  padding: 0 10px;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: var(--paper);
  color: var(--ink-2);
  text-decoration: none;
  font-weight: 500;
  letter-spacing: 0.04em;
  transition: background 0.1s ease, color 0.1s ease, border-color 0.1s ease;
}
.roi-pag-num:hover,
.roi-pag-step:hover {
  background: color-mix(in oklab, var(--saffron) 10%, transparent);
  border-color: color-mix(in oklab, var(--saffron) 50%, var(--line));
  color: var(--ink);
}
.roi-pag-num--active {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
  cursor: default;
}
.roi-pag-num--active:hover {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}
.roi-pag-step--disabled {
  color: var(--ink-4);
  background: transparent;
  border-color: var(--line);
  cursor: not-allowed;
}
.roi-pag-step--disabled:hover {
  background: transparent;
  border-color: var(--line);
  color: var(--ink-4);
}
.roi-pag-dots {
  padding: 0 6px;
  color: var(--ink-3);
}

.broker-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 14px;
}
.broker-card {
  padding: 18px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--paper);
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.broker-card-head {
  display: flex;
  align-items: center;
  gap: 12px;
}
.broker-card-avatar {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  object-fit: cover;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.06);
  flex-shrink: 0;
}
.broker-card-avatar--placeholder {
  background: var(--ivory-2);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--serif);
  font-size: 18px;
  color: var(--ink);
}
.broker-card-head-body { min-width: 0; flex: 1; }
.broker-card-name {
  font-weight: 600;
  font-size: 14px;
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}
.broker-card-name a { color: var(--ink); text-decoration: none; }
.broker-card-name a:hover { text-decoration: underline; }
.broker-card-meta {
  font-size: 12px;
  color: var(--ink-3);
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.broker-card-bio {
  margin: 0;
  font-size: 13px;
  color: var(--ink-2);
  line-height: 1.45;
}
.broker-card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding-top: 10px;
  border-top: 1px dashed var(--line);
}
.broker-card-stat {
  font-size: 11px;
  color: var(--ink-4);
}
/* Tighter .btn-sm inside broker cards — base .btn-sm (L86) sets
   min-height: 36px which crowds the dense broker-card layout. Scoped
   so this doesn't leak to .btn-sm globally. */
.broker-card .btn-sm { padding: 5px 10px; font-size: 12px; }

/* ── Feed stream ────────────────────────────────────────────── */
.feed-stream {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.feed-item {
  padding: 16px 18px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--paper);
}
.feed-item--buyer {
  background: var(--saffron-soft);
  border-color: var(--saffron);
}
.feed-item-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 8px;
}
.feed-item-broker {
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
}
.feed-item-broker:hover { text-decoration: underline; }
.feed-item-kind {
  font-size: 11px;
  color: var(--ink-3);
}
.feed-item-time {
  font-size: 11px;
  color: var(--ink-4);
  margin-left: auto;
}
.feed-item-title {
  margin: 0;
  font-family: var(--serif);
  font-size: 18px;
  line-height: 1.2;
}
.feed-item-title a { color: var(--ink); text-decoration: none; }
.feed-item-title a:hover { text-decoration: underline; }
.feed-item-locality { font-size: 12px; color: var(--ink-3); margin-top: 4px; }
.feed-item-facts { font-size: 12px; color: var(--ink-2); margin-top: 6px; }
/* Listing fact strip — meta (property type · transaction · config) on the
   left, price on the right, one row to save vertical space. Price never
   shrinks; a long meta truncates with an ellipsis so the price stays put. */
.feed-item-factline {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-top: 6px;
}
.feed-item-factline-meta {
  font-size: 11px; color: var(--ink-3); letter-spacing: 0.02em;
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.feed-item-factline-price { font-size: 13px; color: var(--ink-2); flex-shrink: 0; }
/* Mobile: the "X ago" timestamp (margin-left:auto + the header's wrap)
   drops onto its own right-aligned row on the narrow listing card, eating
   the space between the byline and the listing. Listing age is low-value
   on a phone feed, so hide it on mobile for listing cards (events/buyers
   keep theirs — events carry real date context). */
@media (max-width: 600px) {
  .feed-item--local_listing .feed-item-time,
  .feed-item--cache_listing .feed-item-time { display: none; }
}

/* ── Saved cards ────────────────────────────────────────────── */
.saved-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 14px;
}
.saved-card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--paper);
  overflow: hidden;
}
.saved-card-photo {
  display: block;
  aspect-ratio: 16 / 9;
  background: var(--ivory-2);
  overflow: hidden;
}
.saved-card-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.saved-card-body { padding: 12px 14px; flex: 1; }
.saved-card-title {
  font-family: var(--serif);
  font-size: 17px;
  margin: 0 0 4px;
  line-height: 1.2;
}
.saved-card-title a { color: var(--ink); text-decoration: none; }
.saved-card-title a:hover { text-decoration: underline; }
.saved-card-meta { font-size: 12px; color: var(--ink-3); margin-bottom: 6px; }
.saved-card-facts { font-size: 11px; color: var(--ink-4); }
.saved-card-action {
  padding: 8px 14px;
  border-top: 1px dashed var(--line);
  display: flex;
  justify-content: flex-end;
}

/* ── Save button (inline form) ──────────────────────────────── */
.save-form { display: inline-flex; }
.save-form .btn { white-space: nowrap; }

/* ── Deal close + reviews on conversation page ───────────────── */
.deal-card { background: var(--paper); }
.deal-card--closed {
  background: var(--green-soft);
  border-color: var(--green);
}
.deal-card-hint {
  font-size: 12px;
  color: var(--ink-3);
  line-height: 1.4;
  margin: 0 0 10px;
}
.deal-form {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.deal-form-label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.deal-form-label .form-input {
  margin-top: 2px;
  font-family: var(--sans);
  font-size: var(--fs-input);
  text-transform: none;
  letter-spacing: 0;
  color: var(--ink);
}
.review-form {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px dashed var(--line);
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.review-item {
  padding: 10px 0;
  border-bottom: 1px dashed var(--line);
}
.review-item:last-of-type { border-bottom: none; }
.review-item-head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 4px;
}
.review-rating { color: var(--saffron-deep, #c2410c); font-size: 12px; letter-spacing: 1px; }
.review-body { margin: 4px 0; font-size: 13px; color: var(--ink-2); }
.review-time { font-size: 10px; color: var(--ink-4); }

/* ── Leaderboard ─────────────────────────────────────────────── */
.leaderboard-tabs {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin: 0 0 16px;
  border-bottom: 1px solid var(--line);
  padding-bottom: 12px;
}
.leaderboard-tab {
  padding: 8px 14px;
  border-radius: 999px;
  font-size: 12px;
  font-family: var(--mono);
  color: var(--ink-3);
  text-decoration: none;
  border: 1px solid var(--line-2);
  background: var(--paper);
}
.leaderboard-tab--active {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}
.leaderboard-list {
  list-style: none;
  padding: 0;
  margin: 16px 0 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.leaderboard-row {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 16px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--paper);
}
.leaderboard-rank {
  font-family: var(--serif);
  font-size: 22px;
  color: var(--ink-3);
  min-width: 44px;
  text-align: center;
}
.leaderboard-body { flex: 1; min-width: 0; }
.leaderboard-name {
  display: flex;
  align-items: center;
  gap: 6px;
  font-weight: 600;
  color: var(--ink);
  flex-wrap: wrap;
}
.leaderboard-name a { color: inherit; text-decoration: none; }
.leaderboard-name a:hover { text-decoration: underline; }
.leaderboard-meta {
  font-size: 12px;
  color: var(--ink-3);
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.leaderboard-metric {
  text-align: right;
  flex-shrink: 0;
}
.leaderboard-metric-value {
  font-family: var(--serif);
  font-size: 22px;
  color: var(--ink);
  line-height: 1;
}
.leaderboard-metric-label {
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-4);
  margin-top: 2px;
}

/* ── Top Contributors rail (locality public page) ─────────── */
.pll-contributors {
  margin: 32px 0;
}
.pll-section-sub {
  font-size: 12px;
  color: var(--ink-3);
  letter-spacing: 0.02em;
  margin-top: 2px;
}
.pll-contributors-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 12px;
  margin-top: 12px;
}
.pll-contributor-card {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 12px 14px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 10px;
  text-decoration: none;
  color: var(--ink);
  transition: border-color 0.15s ease;
}
.pll-contributor-card:hover {
  border-color: var(--saffron);
}
.pll-contributor-name {
  font-weight: 600;
  font-size: 14px;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.pll-contributor-meta {
  font-size: 11px;
  color: var(--ink-3);
  letter-spacing: 0.02em;
}
.badge--roi {
  font-size: 10px;
  padding: 2px 6px;
  background: var(--saffron);
  color: var(--ink);
  border-radius: 999px;
  font-weight: 700;
  letter-spacing: 0.04em;
}

/* ── Autocomplete (locality picker etc.) ────────────────────── */
.form-group--autocomplete {
  position: relative;
}
.autocomplete-control {
  position: relative;
  display: flex;
  align-items: center;
}
.autocomplete-clear {
  position: absolute;
  right: 8px;
  top: 50%;
  transform: translateY(-50%);
  background: transparent;
  border: none;
  font-size: 18px;
  color: var(--ink-3);
  cursor: pointer;
  padding: 2px 6px;
  line-height: 1;
}
.autocomplete-clear:hover { color: var(--ink); }
.autocomplete-suggestions {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  z-index: 30;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.08);
  max-height: 280px;
  overflow-y: auto;
}
.autocomplete-option {
  display: flex;
  flex-direction: column;
  gap: 2px;
  width: 100%;
  text-align: left;
  padding: 10px 12px;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--line);
  cursor: pointer;
  font-size: 13px;
}
.autocomplete-option:last-child { border-bottom: none; }
.autocomplete-option:hover { background: var(--ivory-2); }
.autocomplete-name { color: var(--ink); font-weight: 500; }
.autocomplete-meta { color: var(--ink-3); font-size: 11px; }
[x-cloak] { display: none !important; }

/* ── Rail primitive (.app-rail) — dark-launched ──────────────────────
   Unified sticky-rail behaviour for .feed-rail / .rail / .lrail. The
   primitive measures the COLUMN width via container queries (not the
   viewport), so any future shell rearrangement gets correct sticky
   behaviour automatically — a fourth rail or an embedded surface
   inherits the contract.

   Dark-launch gate: every rule inside this block is scoped under
   `body.app-rail-primitive`. The class is ABSENT from layouts/app.blade.php
   on Ship A so this block is inert on prod. Ship B adds the class +
   deletes the legacy per-rail sticky blocks in one commit, completing
   the cutover. Rollback path = revert Ship B (single-line body class
   removal + restore of the legacy blocks).

   See memory/brief_realtyx_sticky_rail_primitive.md. */
body.app-rail-primitive .app-rail {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* When the rail enters its sticky desktop state (the @container /
   @media branches below), the rail also picks up `max-height` +
   `overflow-y: auto` so it gets its OWN bounded scroller. This
   restores the "scroll the rail and the feed independently"
   desktop ergonomics the 2026-06-05 user-reported regression
   surfaced; the mobile/tablet nested-scroll trap stays closed
   because the rail is NOT sticky at narrow shell widths (no
   sticky → no max-height → static flow → scrolls with the page).
   The scrollbar is rendered thin so it doesn't visually dominate.

   See memory/brief_realtyx_sticky_rail_primitive.md ship notes
   for the original retire-then-restore rationale. */
body.app-rail-primitive .app-rail::-webkit-scrollbar { width: 2px; }
body.app-rail-primitive .app-rail::-webkit-scrollbar-thumb {
  background: var(--line-2);
  border-radius: 3px;
}
body.app-rail-primitive .app-rail::-webkit-scrollbar-thumb:hover {
  background: var(--ink-4);
}

@supports (container-type: inline-size) {
  body.app-rail-primitive .feed-shell {
    container-type: inline-size;
    container-name: feed-rail-shell;
  }
  body.app-rail-primitive .matches-layout {
    container-type: inline-size;
    container-name: matches-rail-shell;
  }
  /* Feed rails go sticky when the rail's own column is wide enough.
     720px is the column width at the existing 1001px viewport
     activation (240+24+min(0,1fr)+24+280). In the sticky desktop
     state the rail also picks up `app-rail--scrolling` semantics
     (max-height + overflow:auto) — applied to the SAME selector so
     a rail is sticky AND independently scrollable in the same
     query state. */
  @container feed-rail-shell (min-width: 720px) {
    body.app-rail-primitive .app-rail:not(.app-rail--static) {
      position: sticky;
      top: var(--app-rail-top, 16px);
      max-height: calc(100vh - var(--app-rail-top, 16px) - 16px);
      overflow-y: auto;
      padding-right: 8px;
      scrollbar-width: thin;
    }
  }
  /* Matches rails go sticky when the rail's own column is wide enough.
     240px matches the existing 1100px viewport activation for the
     left rail; the right rail column at 300px clears 240px trivially. */
  @container matches-rail-shell (min-width: 240px) {
    body.app-rail-primitive .app-rail:not(.app-rail--static) {
      position: sticky;
      top: var(--app-rail-top, 16px);
      max-height: calc(100vh - var(--app-rail-top, 16px) - 16px);
      overflow-y: auto;
      padding-right: 8px;
      scrollbar-width: thin;
    }
  }
  /* Narrow-shell hide modifier — replaces the .lrail @media display:none. */
  @container feed-rail-shell (max-width: 719px) {
    body.app-rail-primitive .app-rail--hide-narrow { display: none; }
  }
  @container matches-rail-shell (max-width: 239px) {
    body.app-rail-primitive .app-rail--hide-narrow { display: none; }
  }
}

/* Progressive-enhancement fallback for Safari <16 / older Chromium
   that don't support container queries. Converges on the same visual
   outcome at the same desktop breakpoints — including the bounded
   internal scroller restored 2026-06-05. */
@supports not (container-type: inline-size) {
  @media (min-width: 1001px) {
    body.app-rail-primitive .feed-shell .app-rail:not(.app-rail--static) {
      position: sticky;
      top: var(--app-rail-top, 16px);
      max-height: calc(100vh - var(--app-rail-top, 16px) - 16px);
      overflow-y: auto;
      padding-right: 8px;
      scrollbar-width: thin;
    }
  }
  @media (min-width: 1100px) {
    body.app-rail-primitive .matches-layout .app-rail:not(.app-rail--static) {
      position: sticky;
      top: var(--app-rail-top, 16px);
      max-height: calc(100vh - var(--app-rail-top, 16px) - 16px);
      overflow-y: auto;
      padding-right: 8px;
      scrollbar-width: thin;
    }
  }
  @media (max-width: 1099px) {
    body.app-rail-primitive .app-rail--hide-narrow { display: none; }
  }
}

/* ── Feed M1 — 3-column shell + rails (Sprint 1) ──────────── */
.feed-shell {
  display: grid;
  grid-template-columns: 240px minmax(0, 1fr) 280px;
  gap: 24px;
  max-width: 1280px;
  margin: 0 auto;
  padding: 16px;
  align-items: start;
}
@media (max-width: 1000px) {
  .feed-shell {
    grid-template-columns: 1fr;
    gap: 16px;
    /* Single column here, so this padding is the only side gutter — keep it
       tight (8px) so feed cards run wide on mobile without looking clipped. */
    padding: 8px;
  }
  .feed-rail--left { order: 3; }
  .feed-rail--right { order: 2; }
  .feed-stream-col { order: 1; }
}
.feed-rail {
  display: flex;
  flex-direction: column;
  gap: 10px;
  /* Sticky / hide-on-narrow / safe-area behaviour is owned by the
     .app-rail primitive (search for "Rail primitive (.app-rail)" in
     this file). The legacy `max-height + overflow-y: auto` nested-
     scroll trap that lived here was retired in the Ship B commit
     of [[brief_realtyx_sticky_rail_primitive]] — rails now scroll
     with the page on every viewport, no nested-scroll region. */
}
.feed-rail-section {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 14px 16px;
}
.feed-rail-title {
  margin: 0 0 10px;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-2);
  letter-spacing: 0.02em;
  text-transform: uppercase;
}
.feed-identity-card {
  display: flex;
  align-items: center;
  gap: 12px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 14px 16px;
}
.feed-identity-avatar {
  width: 36px; height: 36px;
  border-radius: 50%;
  background: var(--ivory-2);
  display: flex; align-items: center; justify-content: center;
  font-size: 14px; font-weight: 700;
  color: var(--ink);
}
.feed-identity-name { font-weight: 600; font-size: 14px; }
.feed-identity-sub { color: var(--ink-3); font-size: 11px; letter-spacing: 0.02em; }
.feed-rail-pills {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 6px;
}
.feed-rail-pill {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 6px 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 12px;
  color: var(--ink);
  text-decoration: none;
  background: var(--paper);
}
.feed-rail-pill:hover { background: var(--ivory-2); }
.feed-rail-pill-dot {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  /* No-crop reflex D4 — fixed-dimension primitive never collapses. */
  flex-shrink: 0;
}
.feed-rail-pill--locality .feed-rail-pill-dot { background: #4A6FA5; }
.feed-rail-pill--category .feed-rail-pill-dot { background: #5A9C5A; }
.feed-rail-pill--price-band .feed-rail-pill-dot { background: var(--saffron); }
.feed-rail-pill--tag .feed-rail-pill-dot { background: #d9342b; }
.feed-rail-pill--broker .feed-rail-pill-dot { background: #8B5CF6; }
.feed-rail-pill--event .feed-rail-pill-dot { background: #F59E0B; }
.feed-rail-pill--builder .feed-rail-pill-dot { background: #14B8A6; }
.feed-rail-pill--society .feed-rail-pill-dot { background: #EC4899; }
.feed-rail-addlink {
  /* Hit-area pseudo-element keeps the visible '+ add' link at its
     11px font size while the tap target grows to 48x48 (rubric D3).
     position: relative anchors the ::before below. */
  position: relative;
  display: inline-block;
  margin-top: 8px;
  padding: 0;
  font-size: 11px;
  color: var(--ink-3);
  text-decoration: none;
  background: none;
  border: none;
  cursor: pointer;
  font-family: inherit;
}
.feed-rail-addlink::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  min-width: var(--tap);
  min-height: var(--tap);
}
.feed-rail-addlink:hover { color: var(--ink); }

/* --- Subscription pill (with inline ✕ remove) ---------------------- */
.feed-rail-pill-wrap {
  display: flex;
  align-items: center;
  gap: 4px;
  position: relative;
}
.feed-rail-pill-wrap .feed-rail-pill {
  flex: 1 1 auto;
  min-width: 0;
}
.feed-rail-pill-remove {
  margin: 0;
  display: inline-flex;
  opacity: 0;
  transition: opacity 0.15s ease-out;
}
.feed-rail-pill-wrap:hover .feed-rail-pill-remove,
.feed-rail-pill-wrap:focus-within .feed-rail-pill-remove {
  opacity: 1;
}
.feed-rail-pill-remove-btn {
  /* Visible X stays at 22x22 inside the pill; ::before extends the
     hit area to 48x48 around it (rubric D3). Growing the visible X
     to 48px would dominate the pill row, so the wrapper approach
     is the right trade. position: relative anchors the ::before. */
  position: relative;
  width: 22px;
  height: 22px;
  padding: 0;
  border: 1px solid var(--line);
  background: var(--paper);
  color: var(--ink-3);
  border-radius: 50%;
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.feed-rail-pill-remove-btn::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  min-width: var(--tap);
  min-height: var(--tap);
}
.feed-rail-pill-remove-btn:hover {
  color: #d9342b;
  border-color: #d9342b;
}
/* HTMX swap transition — fade the <li> as it's removed. */
.feed-rail-pill-wrap.htmx-swapping {
  opacity: 0;
  transition: opacity 0.2s ease-out;
}
/* Mobile: hover doesn't apply, so the ✕ is always shown. */
@media (max-width: 600px) {
  .feed-rail-pill-remove { opacity: 1; }
}

/* --- Subscription picker modal ------------------------------------ */
.subscription-picker {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Full 4-side safe-area on a fullscreen overlay — inner card stays
     flex-centered inside the padded shell. max() floor preserves the
     16px baseline on non-notched devices ([[safe-area-sweep]]). */
  padding: max(16px, var(--inset-top)) max(16px, var(--inset-right)) max(16px, var(--inset-bottom)) max(16px, var(--inset-left));
}
.subscription-picker-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
}
.subscription-picker-inner {
  position: relative;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 12px;
  max-width: 480px;
  width: 100%;
  max-height: 80vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  box-shadow: 0 24px 64px rgba(0, 0, 0, 0.35);
}
.subscription-picker-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px;
  border-bottom: 1px solid var(--line);
}
.subscription-picker-title {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
  color: var(--ink);
}
.subscription-picker-close {
  width: 28px;
  height: 28px;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--ink-3);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
}
.subscription-picker-close:hover { color: var(--ink); }
.subscription-picker-body {
  padding: 16px 20px;
  overflow-y: auto;
}

.sub-picker-locality .form-input { width: 100%; box-sizing: border-box; }
.sub-picker-results {
  margin-top: 8px;
  max-height: 280px;
  overflow-y: auto;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--paper);
}
.sub-picker-loading, .sub-picker-empty {
  padding: 12px;
  color: var(--ink-3);
  font-size: 12px;
}
.sub-picker-suggestion {
  display: block;
  width: 100%;
  padding: 10px 12px;
  text-align: left;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--line);
  color: var(--ink);
  cursor: pointer;
  font-family: inherit;
}
.sub-picker-suggestion:last-child { border-bottom: none; }
.sub-picker-suggestion:hover { background: var(--ivory-2); }
.sub-picker-suggestion:disabled { opacity: 0.5; cursor: wait; }
.sub-picker-suggestion-main { display: block; font-size: 14px; }
.sub-picker-suggestion-sub { display: block; font-size: 11px; color: var(--ink-3); margin-top: 2px; }
.sub-picker-suggested { margin-top: 16px; }
.sub-picker-suggested-title {
  margin: 0 0 8px;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-3);
}
.sub-picker-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.sub-picker-chip {
  padding: 6px 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink);
  font-size: 12px;
  cursor: pointer;
  font-family: inherit;
}
.sub-picker-chip:hover { background: var(--ivory-2); border-color: var(--ink-3); }
.sub-picker-chip:disabled { opacity: 0.5; cursor: wait; }

/* --- Inline-expand chip grid (Category / Price Band rail) ---------- */
.feed-rail-chipgrid {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
  padding: 10px;
  background: var(--ivory-2);
  border-radius: 8px;
}
.feed-rail-chipform { margin: 0; display: inline-block; }
.feed-rail-chip {
  padding: 4px 10px;
  border: 1px dashed var(--ink-3);
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink-2);
  font-size: 11px;
  cursor: pointer;
  font-family: inherit;
}
.feed-rail-chip:hover {
  background: var(--ink);
  color: var(--paper);
  border-style: solid;
}

/* --- Event subscription picker list ------------------------------- */
.sub-picker-event-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 8px;
}
.sub-picker-event-row {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--paper);
  text-align: left;
  cursor: pointer;
  font-family: inherit;
}
.sub-picker-event-row:hover { background: var(--ivory-2); border-color: var(--ink-3); }
.sub-picker-event-row:disabled { opacity: 0.5; cursor: wait; }
.sub-picker-event-date {
  flex: 0 0 auto;
  font-size: 11px;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding-top: 2px;
}
.sub-picker-event-meta {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.sub-picker-event-title {
  font-size: 13px;
  color: var(--ink);
  font-weight: 500;
}
.sub-picker-event-venue {
  font-size: 11px;
  color: var(--ink-3);
}
.feed-rail-events { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.feed-rail-event {
  display: flex; gap: 10px;
  text-decoration: none;
  color: var(--ink);
  padding: 8px;
  border-radius: 8px;
}
.feed-rail-event:hover { background: var(--ivory-2); }
.feed-rail-event-date {
  background: var(--ivory-2);
  border-radius: 6px;
  padding: 6px 10px;
  font-size: 10px; font-weight: 700;
  white-space: nowrap;
  align-self: flex-start;
  /* No-crop reflex D4 — date pill is fixed visual chrome. */
  flex-shrink: 0;
}
/* No-crop reflex D2 — text-bearing flex children inside the broker
   row + event row. Allows shrink + provides explicit overflow policy
   so a long broker name (and esp. transliterated Devanagari) can't
   push the row past container width. Renders inert if the matching
   class isn't in markup. */
.feed-rail-event-body,
.feed-rail-broker-meta {
  min-width: 0;
  flex: 1 1 auto;
  overflow: hidden;
}
.feed-rail-broker-name,
.feed-rail-broker-stats {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.feed-rail-event-kind { color: var(--ink-3); font-size: 10px; text-transform: uppercase; letter-spacing: 0.04em; }
.feed-rail-event-title { font-size: 13px; font-weight: 500; line-height: 1.3; margin-top: 2px; }
.feed-rail-brokers { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.feed-rail-broker-link {
  display: flex; gap: 10px; align-items: center;
  text-decoration: none; color: var(--ink);
  padding: 6px;
  border-radius: 8px;
}
.feed-rail-broker-link:hover { background: var(--ivory-2); }
.feed-rail-broker-avatar {
  width: 28px; height: 28px;
  border-radius: 50%;
  background: var(--ivory-2);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 700;
  flex: none;
}
/* Photo variant — uploaded broker avatar fills the circle. */
.feed-rail-broker-avatar--img {
  /* D11 — same defensive pattern as the .avatar--img fix (D1). Upper-
     third object-position keeps faces in frame; aspect-ratio + the
     parent's overflow:hidden ensure the bitmap stays circular. */
  aspect-ratio: 1 / 1;
  object-fit: cover;
  object-position: 50% 28%;
  background: var(--ivory-2);
}
.feed-rail-broker-name { font-weight: 500; font-size: 13px; }
.feed-rail-broker-stats { display: block; color: var(--ink-3); font-size: 10px; letter-spacing: 0.02em; }
.feed-rail-broker-badge {
  display: inline-block;
  margin-left: 4px;
  color: var(--saffron, #d68a00);
  font-size: 11px;
  font-weight: 700;
  vertical-align: baseline;
}
/* Sprint 2 — section header with inline hide affordance. */
.feed-rail-section-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
  /* No-crop reflex D7 — wrap on narrow widths instead of pushing the
     row past container. Long city names + counts get a second row. */
  flex-wrap: wrap;
  row-gap: 6px;
}
.feed-rail-hide { display: inline-block; margin: 0; }
.feed-rail-hide-btn {
  /* Visible "hide" button stays at its small font; ::before extends
     hit area to 48x48 (rubric D3). position: relative anchors. */
  position: relative;
  display: inline-block;
  background: none; border: 0; padding: 0 4px; cursor: pointer;
  color: var(--ink-3); font-size: 16px; line-height: 1;
}
.feed-rail-hide-btn::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  min-width: var(--tap);
  min-height: var(--tap);
}
.feed-rail-hide-btn:hover { color: var(--ink); }
.feed-stream-col { min-width: 0; }
.feed-header { margin-bottom: 12px; }

/* (Removed 2026-06-11) Legacy `.feed-type-badge` single-letter top-right
   chip — D/L/E/R/B/P/W. Card kind is now signalled by the visible header
   copy (`.post-card-cat` lozenge for posts; `.feed-item-kind` mono label
   for event/buyer/listing) plus the `data-feed-type` attribute on each
   <article>. Post cards host their own corner-pinned timestamp via
   .post-card { position: relative } + .post-card-time absolute pin (see
   below). `.feed-item-wrapper.feed-item--pinned` retains its own
   position:relative for the saffron-accent border (independent rule at
   line ~6459). */

/* Public homepage "Live in {city}" section — uses the standard
   ph-section shell + feed-stream cards underneath. The auth-gate
   CTA inside the section sub appears as an inline link prompting
   sign-in for write actions. */
.ph-live-feed-section { padding: 32px 0; }
.feed-stream--public { max-width: 760px; margin: 0 auto; }
.auth-gate-cta {
  color: var(--saffron);
  font-weight: 600;
  text-decoration: none;
}
.auth-gate-cta:hover { text-decoration: underline; }

/* ── Feed v2 tabs (BiggerPockets-style) ─────────────────────── */
.feed-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  margin: -5px 0 20px;
  padding-bottom: 2px;
  border-bottom: 1px solid var(--line);
  overflow-x: auto;
}
.feed-tab {
  display: inline-flex;
  align-items: center;
  padding: 8px 14px;
  /* Rubric D3 48px floor — grows from 36->48px, normal button size at
     13px font. See [[brief_realtyx_tap_44_lint]]. */
  min-height: var(--tap);
  min-width: var(--tap);
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-2);
  text-decoration: none;
  border-radius: 8px 8px 0 0;
  border-bottom: 2px solid transparent;
  white-space: nowrap;
  margin-bottom: -1px;
}
.feed-tab:hover {
  color: var(--ink);
  background: var(--ivory-2);
}
.feed-tab--active {
  color: var(--ink);
  background: var(--ivory-2);
  border-bottom-color: var(--saffron);
}

/* ── Posts ───────────────────────────────────────────────────── */
.feed-composer-rail {
  display: flex;
  justify-content: flex-end;
  margin: 8px 0 16px;
}
.post-card {
  /* Positioning context for the corner-pinned .post-card-time (top-right
     of the card, where the legacy .feed-type-badge chip used to sit).
     The pin lives on .post-card itself — not .feed-item-wrapper —
     because <x-post-card> is also used outside the feed (posts/show,
     tags/show, posts/archived), and those callers must keep the
     timestamp without per-caller markup changes. */
  position: relative;
  padding: 16px 18px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--paper);
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-bottom: 12px;
}
.post-card-head {
  display: flex;
  align-items: center;
  gap: 10px;
  /* No wrap: the time is absolutely positioned and out of flex flow,
     so wrap would only happen if the inline children themselves (avatar
     + author + cat lozenge + ROI badge + edited marker) collectively
     overflow. Every non-author sibling is `flex-shrink: 0` below, so
     author ellipsizes first and the row stays one line. */
  flex-wrap: nowrap;
  min-width: 0;
}
/* Avatar tile sits flush with the author name; center-aligned with the
   row instead of baseline so the round image doesn't crop the chip row. */
.post-card-avatar-link {
  display: inline-flex;
  flex-shrink: 0;
  text-decoration: none;
}
.post-card-author {
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
  /* Ellipsize before bumping siblings. min-width:0 is load-bearing —
     the default flex min-content floor would keep the link from
     shrinking below intrinsic name width. */
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.post-card-author:hover { text-decoration: underline; }
.post-card-cat {
  font-size: 10px;
  color: var(--ink-4);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--ivory-2);
  /* Never the wrapping element; never the shrinking element. The
     trailing ellipsis falls to the author name first (above). */
  flex-shrink: 0;
}
/* Compact ROI Verified badge + "· edited" marker live in the same row.
   Freeze them too so they can't be the wrap victim. */
.post-card-head > .roi-badge,
.post-card-edited {
  flex-shrink: 0;
}
.post-card-time {
  /* Corner-pinned 2026-06-11 — sits where the deleted .feed-type-badge
     chip used to. top: 14px + right: 14px to align with the avatar's
     vertical centerline and stay clear of the card's 16px top padding.
     pointer-events:none so a hover/tap on the corner falls through to
     the author link below, not the non-interactive timestamp.

     Same pin applies on mobile — the user explicitly asked for the
     time to be "where the D is written" and the screenshot was a phone.
     Wrap-to-second-row collision is structurally impossible at any
     viewport because .post-card-head is `flex-wrap: nowrap` and every
     non-author sibling carries `flex-shrink: 0`: the author name
     ellipsizes before anyone else gets bumped. */
  position: absolute;
  top: 14px;
  right: 14px;
  font-size: 11px;
  color: var(--ink-4);
  white-space: nowrap;
  pointer-events: none;
  z-index: 1;
}
/* Mobile collision guard — at <=700px (the same breakpoint where the
   .post-card-more footer overflow menu engages), the corner-pinned time
   can horizontally overlap the cat lozenge once ROI badge + lozenge +
   timestamp coexist in a 360 CSS-px header. Hide the lozenge below 700px:
   the post body carries the kind signal at that width, and the lozenge
   is small enough that removing it doesn't degrade scan-ability. The
   `.feed-item-kind` mono label on event/buyer/listing cards is
   unaffected (different selector). */
@media (max-width: 700px) {
  .post-card-cat { display: none; }
}
/* Archived-post opt-out — pages/posts/archived.blade.php hand-rolls a
   .post-card whose header has ONLY a cat lozenge + a long "Archived 3
   weeks ago" timestamp (no avatar / author / ROI badge / edited marker).
   Two regressions vs the canonical card:
     1. Corner-pinning time at right:14px leaves a ~250px empty gap
        between the lone lozenge and the timestamp.
     2. Hiding the lozenge at <=700px strips the only category signal
        on the page (there's no body-shape cue like the feed has).
   Revert both effects via the modifier class; the archived header
   reads naturally with cat-then-time on one inline-flow row. */
.post-card--archived .post-card-time {
  position: static;
  margin-left: auto;
  pointer-events: auto;
  top: auto;
  right: auto;
}
@media (max-width: 700px) {
  .post-card--archived .post-card-cat { display: inline-block; }
}
.post-body {
  font-size: 15px;
  color: var(--ink);
  line-height: 1.55;
  white-space: pre-wrap;
  word-break: break-word;
}
.post-tag {
  color: var(--saffron-deep, #c2410c);
  text-decoration: none;
  font-weight: 500;
}
.post-tag:hover { text-decoration: underline; }
.post-card-photo {
  display: block;
  overflow: hidden;
  border-radius: 8px;
  background: var(--ivory-2);
  max-height: 480px;
}
.post-card-photo img {
  width: 100%;
  height: auto;
  display: block;
  max-height: 480px;
  object-fit: cover;
}
.post-card-foot {
  display: flex;
  align-items: center;
  gap: 6px;
  padding-top: 10px;
  border-top: 1px dashed var(--line);
  /* Defensive wrap — if the overflow-menu fix below ever fails (CSS
     not loaded yet, JS off), the row drops to a second visual row
     rather than pushing past the card edge. */
  flex-wrap: wrap;
  row-gap: 6px;
}
.post-card-spacer { flex: 1 1 0; min-width: 0; }

/* Mobile post-card overflow menu (Phase 5 #2.5 user feedback
   2026-05-29). On phone the footer collapses to four primary
   actions (Like / Comment / Share / Save) + a ⋯ trigger; the three
   secondary actions (Quote / Edit / View →) move into a dropdown
   panel anchored under the trigger. Desktop renders all seven
   inline as before — the .post-card-more wrapper is display:none
   above the breakpoint. */
.post-card-more { display: none; }
@media (max-width: 700px) {
  .post-card-secondary-inline { display: none !important; }
  .post-card-more {
    display: inline-flex;
    position: relative;
  }
  .post-card-more-trigger {
    /* Ghost-button styling consistent with the rest of the row. */
    min-width: 44px;
    padding: 6px 10px;
    font-size: 14px;
    line-height: 1;
  }
  .post-card-more-panel {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    min-width: 200px;
    padding: 6px;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: 10px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.12);
    z-index: 50;
    display: flex;
    flex-direction: column;
    gap: 2px;
  }
  .post-card-more-item {
    display: flex;
    align-items: center;
    padding: 10px 12px;
    min-height: 44px;
    background: transparent;
    border: 0;
    border-radius: 6px;
    font-size: 14px;
    color: var(--ink-2);
    text-decoration: none;
    cursor: pointer;
    font-family: inherit;
  }
  .post-card-more-item:hover {
    background: var(--ivory-2);
    color: var(--ink);
  }
}
.post-card-like button { cursor: pointer; }

/* Archive action — the footer form is a flex item (mirrors the inline
   Edit/Quote buttons); the ⋯-panel form is a full-width menu row. */
.post-card-archive-form { display: inline-flex; align-items: center; margin: 0; }
.post-card-more-archive { display: block; margin: 0; }
.post-card-more-archive .post-card-more-item { width: 100%; }
/* Left-rail link to the author's archived posts. */
.feed-rail-archived-link {
  display: inline-block;
  margin: 8px 0 4px;
  font-size: 12px;
  color: var(--ink-3, #6b7280);
  text-decoration: none;
}
.feed-rail-archived-link:hover { color: var(--accent, #0a5d3b); text-decoration: underline; }

.post-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 16px 0;
}

.post-comments { margin-top: 28px; }
.post-comments-title {
  font-family: var(--serif);
  font-size: 20px;
  margin: 0 0 14px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--line);
}
.post-comment-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 20px;
}
.post-comment {
  padding: 10px 14px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--paper);
}
.post-comment-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 4px;
}
.post-comment-author {
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
  font-size: 13px;
}
.post-comment-time { font-size: 10px; color: var(--ink-4); margin-left: auto; }
.post-comment-body { font-size: 14px; color: var(--ink-2); line-height: 1.5; white-space: pre-line; }
.post-comment-form {
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: flex-start;
}

/* ── Inline (feed) comments — LinkedIn-style expand-in-place ──── */
.post-card-inline-comments {
  margin-top: 12px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}
.post-comment-form--inline {
  gap: 8px;
  margin-bottom: 14px;
  width: 100%;
}
.post-comment-form--inline .form-textarea { width: 100%; }
.post-comment-form-row {
  display: flex;
  align-items: center;
  gap: 12px;
}
.post-comment-error { color: var(--danger, #b3261e); }
.post-comment-thread {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.post-comment-thread > div[x-html] { display: contents; }
.post-comment--inline { background: var(--paper-2, var(--paper)); }
.post-comment-fulllink {
  display: inline-block;
  margin-top: 12px;
  font-size: 12px;
  color: var(--accent, #0a5d3b);
  text-decoration: none;
}

/* ── Canonical post page — public discussion (server-rendered, indexed) ── */
.public-post-discussion { margin-top: 26px; }
.public-post-discussion-title {
  font-size: 16px;
  font-weight: 700;
  color: var(--ink);
  margin: 0 0 14px;
}
.public-post-discussion-cta { margin-top: 16px; font-size: 13px; }
.public-post-discussion-cta a { color: var(--accent, #0a5d3b); text-decoration: none; font-weight: 600; }

/* ── Tools (calculators) ────────────────────────────────────── */
.tool-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
  margin-top: 20px;
}
.tool-card {
  display: block;
  padding: 18px 20px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--paper);
  text-decoration: none;
  color: var(--ink);
  transition: border-color 120ms ease, transform 120ms ease;
}
.tool-card:hover {
  border-color: var(--ink-3);
  transform: translateY(-1px);
}
.tool-card-title {
  font-family: var(--serif);
  font-size: 20px;
  margin-bottom: 4px;
}
.tool-card-hint {
  font-size: 13px;
  color: var(--ink-3);
  line-height: 1.4;
}

.calc-result {
  margin-top: 24px;
  padding: 22px;
  border: 1px solid var(--ink);
  border-radius: 12px;
  background: var(--paper);
}
.calc-result-headline {
  padding-bottom: 14px;
  margin-bottom: 14px;
  border-bottom: 1px dashed var(--line);
}
.calc-label {
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-4);
  margin-bottom: 4px;
}
.calc-value {
  font-family: var(--serif);
  font-size: 32px;
  line-height: 1;
  color: var(--ink);
}
.calc-breakdown {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 10px 18px;
  margin: 0;
}
.calc-breakdown > div { min-width: 0; }
.calc-breakdown dt {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.calc-breakdown dd {
  margin: 2px 0 0;
  font-size: 14px;
  color: var(--ink);
}
.calc-notes {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px dashed var(--line);
  font-size: 11px;
  color: var(--ink-4);
  line-height: 1.5;
}

.preset-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-top: 12px;
}
.preset-chip {
  padding: 5px 10px;
  border-radius: 999px;
  font-size: 11px;
  font-family: var(--mono);
  color: var(--ink-3);
  background: var(--paper);
  border: 1px solid var(--line-2);
  text-decoration: none;
}
.preset-chip:hover { border-color: var(--ink-3); color: var(--ink); }
.preset-chip--active {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}

/* ── Mobile bottom navigation ────────────────────────────────── */
/* Hidden by default (desktop uses the top nav). The @media block
 * below shows this + hides the top nav at ≤768px. Fixed to the
 * viewport bottom with safe-area-inset for iOS notch devices. */
.mobile-bottom-nav {
  display: none;
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 30;
  height: 64px;
  padding: 0 4px;
  padding-bottom: var(--inset-bottom);
  background: color-mix(in oklab, var(--paper) 92%, transparent);
  backdrop-filter: blur(12px);
  border-top: 1px solid var(--line);
  grid-template-columns: 1fr 1fr 1.3fr 1fr 1fr;
  align-items: center;
}
.mbn-slot {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-height: var(--tap);
  color: var(--ink-3);
  text-decoration: none;
  font-size: 10px;
  font-family: var(--mono);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  /* No-crop reflex D4 — bottom-nav slots keep their pixel size when
     a neighbour's label grows. Without this the SVG icons compress
     while a wider neighbour stays full-width. */
  min-width: 0;
}
.mbn-slot svg {
  /* SVG icon never shrinks below its declared size. */
  flex-shrink: 0;
}
.mbn-slot:hover { color: var(--ink); }
.mbn-slot--active {
  color: var(--saffron-deep);
  font-weight: 600;
}
.mbn-slot--active svg {
  stroke: var(--saffron-deep);
}
/* Count badge on a slot (broker Leads). Pinned to the top-right of the
   slot's icon so it doesn't widen the equal-share grid column. */
.mbn-slot { position: relative; }
.mbn-badge {
  position: absolute;
  top: 4px;
  left: 50%;
  margin-left: 6px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: var(--saffron);
  color: var(--ink);
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 700;
  line-height: 1;
}

/* Centre FAB — sits up and over the bar, so Post reads as the primary CTA. */
.mbn-fab {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  margin: 0 auto;
  border-radius: 999px;
  background: var(--ink);
  color: var(--paper);
  text-decoration: none;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
  transform: translateY(-10px);
  transition: transform 120ms ease, background 120ms ease;
}
.mbn-fab:hover { filter: brightness(0.96); }
.mbn-fab:active { transform: translateY(-8px) scale(0.96); }

/* The 800px boundary here is content-driven, not Tailwind-aligned —
   it's the width at which the desktop navbar's brand + nav tabs +
   city + theme + lang + auth controls stop fitting on one row. Both
   the top-nav hide and bottom-nav show flip together at this exact
   width, so there is no "dead zone" between hide-top and show-bottom.
   Mobile-overhaul Phase 4 #5 audited this and confirmed the pair is
   pragmatic-policy B-bucket — keep at 800, don't move to Tailwind md. */
@media (max-width: 800px) {
  /* Top nav collapses: keep brand + language switcher + auth state
   * (avatar/get-started) but the primary nav links move to the bottom. */
  .navbar-inner nav { display: none !important; }

  /* Reveal the bottom nav as a 5-col grid. */
  .mobile-bottom-nav { display: grid; }

  /* Push main content above the bar so it doesn't hide under it.
     The bottom-nav is 64px tall + var(--inset-bottom) (its
     padding-bottom respects the home indicator), so main must reserve
     that plus a 16px breathing gap. Previously hardcoded 80px ignored
     safe-area and overlapped content on notched iPhones. */
  main { padding-bottom: var(--bottom-nav-clearance-16); }

  /* Reduce body / hero padding on small screens so the feed isn't
   * one-card-per-scroll. page-shell is the app's top-level wrapper. */
  .page-shell { padding: 14px 14px; }

  /* Page headings shrink a step on mobile so the hero doesn't eat
   * the entire first screen. */
  .page-h1 { font-size: var(--fs-lg); }
  .landing-h1 { font-size: clamp(36px, 9vw, 56px); }
}

/* ── Theme toggle button (navbar) ───────────────────────────── */
.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--paper);
  color: var(--ink-2);
  cursor: pointer;
  padding: 0;
  transition: border-color 120ms ease, color 120ms ease, background 120ms ease;
}
.theme-toggle:hover { border-color: var(--ink-3); color: var(--ink); }
.theme-toggle-sun, .theme-toggle-moon { display: none; }

/* Show moon when light-mode is active (hint: tap → go dark).
 * Show sun when dark-mode is active (hint: tap → go light). */
:root:not([data-theme="dark"]) .theme-toggle-moon { display: block; }
[data-theme="dark"] .theme-toggle-sun { display: block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="dark"]) .theme-toggle-moon { display: none; }
  :root:not([data-theme="light"]):not([data-theme="dark"]) .theme-toggle-sun  { display: block; }
}

/* ── Dark-mode specific polish ──────────────────────────────── */
/* Shadows don't read on dark — swap for lighter-surface elevation
 * on the cards that rely on shadow for lift in light mode. */
[data-theme="dark"] .landing-h1 em { color: var(--saffron-deep); }
[data-theme="dark"] .mbn-fab { box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5); }
[data-theme="dark"] .btn-primary { box-shadow: none; }
[data-theme="dark"] .btn-primary:hover { box-shadow: 0 0 0 1px var(--saffron-deep) inset; }
[data-theme="dark"] .auth-card { box-shadow: 0 10px 32px rgba(0, 0, 0, 0.5); }
[data-theme="dark"] .profile-card { box-shadow: 0 6px 24px rgba(0, 0, 0, 0.4); }

/* Landing hero's radial-gradient wash looks bright on dark —
 * soften it a touch. */
[data-theme="dark"] .landing-hero::before { opacity: 0.3; }

/* Navbar + bottom-nav translucency tint — blur still works but the
 * color-mix needs to reach for the new dark base. */
[data-theme="dark"] .navbar {
  background: color-mix(in oklab, var(--ivory) 70%, transparent);
}
[data-theme="dark"] .mobile-bottom-nav {
  background: color-mix(in oklab, var(--paper) 85%, transparent);
}

/* ── Matches dashboard header (KPI strip + digest banner) ──────── */
.dash {
  margin: 24px 0 28px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.dash-kpis {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
}
@media (max-width: 800px) {
  .dash-kpis { grid-template-columns: repeat(2, 1fr); }
}

.dash-kpi {
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--paper);
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.dash-kpi-label {
  font-size: 10px;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.dash-kpi-value {
  font-family: var(--serif);
  font-size: 28px;
  line-height: 1;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.dash-kpi-foot {
  font-size: 10px;
  color: var(--ink-3);
  letter-spacing: 0.04em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.dash-kpi-foot a {
  color: var(--saffron-deep);
  text-decoration: none;
  font-weight: 600;
}
.dash-kpi-foot a:hover { text-decoration: underline; }

/* Intros-pending gets saffron tint when there's real work to do. */
.dash-kpi--intros {
  background: var(--saffron-soft);
  border-color: var(--saffron);
}
.dash-kpi--intros .dash-kpi-value { color: var(--saffron-deep); }

.dash-kpi--pulse::before {
  content: '';
  position: absolute;
  top: 10px;
  right: 12px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--saffron);
  box-shadow: 0 0 0 0 color-mix(in oklab, var(--saffron) 60%, transparent);
  animation: dash-pulse 1.8s infinite;
}
.dash-kpi--pulse { position: relative; }

@keyframes dash-pulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in oklab, var(--saffron) 60%, transparent); }
  70%  { box-shadow: 0 0 0 10px color-mix(in oklab, var(--saffron) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in oklab, var(--saffron) 0%, transparent); }
}

/* ── Right rail ───────────────────────────────────────────────── */
.rail {
  display: flex;
  flex-direction: column;
  gap: 14px;
  /* Don't go wider than the column on desktop; on mobile the partial
   * stacks below the feed and fills the available width. Sticky
   * behaviour is owned by the .app-rail primitive (Ship B of
   * [[brief_realtyx_sticky_rail_primitive]]); the per-page offset is
   * supplied by the matches/right-rail partial via --app-rail-top. */
}

.rail-card {
  padding: 16px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--paper);
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.rail-card-head {
  font-size: 10px;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.rail-card-link {
  font-size: 11px;
  color: var(--saffron-deep);
  text-decoration: none;
  letter-spacing: 0.04em;
  font-weight: 600;
  align-self: flex-start;
}
.rail-card-link:hover { text-decoration: underline; }

/* Top brokers -------------------------------------------------- */
.rail-broker-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.rail-broker {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}
.rail-broker-avatar {
  width: 36px;
  height: 36px;
  border-radius: 999px;
  object-fit: cover;
  flex-shrink: 0;
  box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--ink) 10%, transparent);
}
.rail-broker-avatar--ph {
  background: var(--ivory-2);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--serif);
  color: var(--ink);
  font-size: 14px;
}
.rail-broker-body {
  flex: 1;
  min-width: 0;
}
.rail-broker-name {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--ink);
  text-decoration: none;
  font-weight: 600;
  font-size: 13px;
  line-height: 1.25;
}
.rail-broker-name:hover { text-decoration: underline; }
.rail-broker-meta {
  font-size: 10px;
  color: var(--ink-3);
  margin-top: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Recent closes ------------------------------------------------ */
.rail-closes-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.rail-close {
  padding-bottom: 8px;
  border-bottom: 1px dashed var(--line);
}
.rail-close:last-child { border-bottom: none; padding-bottom: 0; }
.rail-close-title {
  font-size: 13px;
  color: var(--ink);
  font-weight: 500;
  line-height: 1.3;
}
.rail-close-meta {
  font-size: 10px;
  color: var(--ink-3);
  margin-top: 3px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Empty-state text across all rail cards */
.rail-empty {
  font-size: 12px;
  color: var(--ink-3);
  line-height: 1.5;
}

/* ── LIVE bar (dark strip above navbar) ─────────────────────── */
.live-bar {
  background: var(--ink);
  color: var(--paper);
  border-bottom: 1px solid color-mix(in oklab, var(--paper) 10%, transparent);
  font-size: 11px;
  letter-spacing: 0.02em;
}
.live-bar-inner {
  max-width: 1600px;
  margin: 0 auto;
  padding: 7px 24px;
  display: flex;
  align-items: center;
  gap: 22px;
  flex-wrap: wrap;
}
.live-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--saffron);
  box-shadow: 0 0 0 0 color-mix(in oklab, var(--saffron) 60%, transparent);
  animation: dash-pulse 1.8s infinite;
  flex-shrink: 0;
}
.live-bar-label {
  color: var(--saffron);
  font-weight: 700;
  letter-spacing: 0.14em;
}
.live-stat {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  white-space: nowrap;
}
.live-stat em {
  font-style: normal;
  color: color-mix(in oklab, var(--paper) 60%, transparent);
  letter-spacing: 0.02em;
}
.live-stat strong {
  font-weight: 600;
  color: var(--paper);
}
.live-stat-pos { color: oklch(0.75 0.12 155) !important; }
.live-bar-spacer { flex: 1; }
.live-stat--pipeline strong { color: var(--saffron); }
@media (max-width: 900px) {
  .live-bar-inner { gap: 14px; padding: 8px 14px; }
  .live-stat em { display: none; }   /* show values only on narrow screens */
}

/* Post-buyer nav CTA — saffron accent button. */
.nav-post-cta { padding: 8px 14px; min-height: 36px; font-size: 12px; letter-spacing: 0.02em; }

/* ── Combined top-nav controls pill ──────────────────────────
   Wraps the theme toggle + EN/HI language switcher in one
   rounded container so the right-side cluster reads as a single
   utility group. Replaces two separately-bordered controls. */
.nav-controls-pill {
  display: inline-flex;
  align-items: center;
  gap: 0;
  padding: 3px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 999px;
}
.nav-controls-pill__theme {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  margin: 0;
  border: 0;
  background: transparent;
  border-radius: 999px;
  color: var(--ink-2);
  cursor: pointer;
  transition: background 0.12s, color 0.12s;
}
.nav-controls-pill__theme:hover {
  background: var(--ivory-2);
  color: var(--ink);
}
.nav-controls-pill__divider {
  display: inline-block;
  width: 1px;
  height: 18px;
  background: var(--line);
  margin: 0 4px;
}
.nav-controls-pill__lang {
  display: inline-flex;
  padding: 0;
  margin: 0;
  background: transparent;
  border: 0;
  border-radius: 0;
  font-family: var(--mono);
  font-size: 11px;
}
.nav-controls-pill__lang-btn {
  padding: 4px 10px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--ink-3);
  font: inherit;
  font-weight: 600;
  letter-spacing: 0.04em;
  cursor: pointer;
  transition: background 0.12s, color 0.12s;
}
.nav-controls-pill__lang-btn:hover {
  color: var(--ink);
}
.nav-controls-pill__lang-btn.is-active {
  background: var(--ink);
  color: var(--paper);
}
/* Mobile (<=800px): the inline guest controls (theme + lang pill +
   "List in 60 Seconds" CTA) collapse into a single "···" overflow
   menu — see .nav-mobile-overflow below. The inline pair is hidden
   here; the overflow menu shows itself in its own rule block.

   NB: this boundary is 800px (not 700) to MATCH the navbar's primary-nav
   collapse (`.navbar-inner nav { display:none }` @800). Before the
   alignment there was a 701-800px dead zone where the full guest cluster
   (✨ + RealtyX + lang pill + List CTA) all showed at once and overflowed
   — the "···" only kicked in at 700. Keep all guest-cluster mobile
   breakpoints at 800 so they flip together. */
@media (max-width: 800px) {
  .nav-controls-pill { display: none; }
}

/* "···" mobile overflow menu — guest-only, hidden on tablet+. Holds
   List a property / List a buyer / Language / Theme so the inline
   guest navbar cluster doesn't overflow at 360-430px. */
.nav-mobile-overflow { display: none; position: relative; }
.nav-mobile-overflow-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px;
  padding: 0; margin: 0;
  background: transparent; border: 0;
  border-radius: 999px;
  color: var(--ink-2);
  cursor: pointer;
  transition: background 0.12s, color 0.12s;
}
.nav-mobile-overflow-btn:hover,
.nav-mobile-overflow-btn[aria-expanded="true"] {
  background: var(--ivory-2);
  color: var(--ink);
}
.nav-mobile-overflow-panel {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  min-width: 240px;
  padding: 6px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 12px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  z-index: 50;
  display: flex; flex-direction: column;
  gap: 2px;
}
.nav-mobile-overflow-item {
  display: flex; align-items: center;
  padding: 10px 12px;
  min-height: 44px;
  background: transparent; border: 0;
  border-radius: 8px;
  font-family: inherit;
  font-size: 14px;
  color: var(--ink-2);
  text-decoration: none;
  cursor: pointer;
  text-align: left;
  width: 100%;
  transition: background 0.12s, color 0.12s;
}
.nav-mobile-overflow-item:hover,
.nav-mobile-overflow-item:focus-visible {
  background: var(--ivory-2);
  color: var(--ink);
  outline: none;
}
.nav-mobile-overflow-item--row {
  justify-content: space-between;
  margin: 0;
}
/* Sign in — primary guest action in the "···" menu. Solid ink pill so it
   reads as the CTA above the secondary List actions. */
.nav-mobile-overflow-item--primary {
  background: var(--ink);
  color: var(--paper);
  font-weight: 600;
  justify-content: center;
  margin-bottom: 2px;
}
.nav-mobile-overflow-item--primary:hover,
.nav-mobile-overflow-item--primary:focus-visible {
  background: var(--ink);
  color: var(--paper);
  filter: brightness(1.12);
}
/* RealtyX "LIVE" trailing tag in the menu row — small red broadcast cue,
   mirrors the wordmark's X colour. */
.nav-mobile-overflow-row-trail--live {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  color: #d9342b;
}
.nav-mobile-overflow-row-trail {
  display: inline-flex; align-items: center; gap: 4px;
  color: var(--ink-3);
}
.nav-mobile-overflow-divider {
  height: 1px;
  background: var(--line);
  margin: 4px 0;
}
.nav-mobile-overflow-lang-btn {
  padding: 4px 10px;
  border: 0; border-radius: 999px;
  background: transparent;
  color: var(--ink-3);
  font: inherit;
  font-family: var(--mono);
  font-weight: 600; font-size: 12px;
  letter-spacing: 0.04em;
  cursor: pointer;
}
.nav-mobile-overflow-lang-btn.is-active {
  background: var(--ink);
  color: var(--paper);
}
@media (max-width: 800px) {
  .nav-mobile-overflow { display: inline-flex; }
  /* NB: the .nav-list-in-60 hide is restated AFTER its base rule below —
     the base `.nav-list-in-60 { display:inline-block }` is later in source
     order, so a hide placed HERE (above the base) loses the cascade at
     equal specificity. Same trap as .navtab--realtyx. */
}

/* ── "List in 60 Seconds" dropdown — guest primary CTA ───────
   Solid ink pill (matches .btn-primary) with a caret. Click
   reveals a 2-item menu (List a Property / List a Buyer) that
   deep-links into the conversational chatbots at /list-property
   and /find-property. Alpine handles open/close; click-outside +
   Esc close. Menu anchored bottom-right of the button so it
   doesn't bleed off the viewport at any width. */
.nav-list-in-60 {
  position: relative;
  display: inline-block;
}
/* Mobile (<=800px): the guest "List in 60 Seconds" CTA folds into the
   "···" overflow menu (which exposes List a Property / List a Buyer).
   Restated AFTER the base rule above so it wins the cascade — matches the
   navbar collapse boundary so it disappears together with the rest of the
   guest cluster (no 701-800 overflow band). */
@media (max-width: 800px) {
  .nav-list-in-60 { display: none; }
}
.nav-list-in-60-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  white-space: nowrap;
}
.nav-list-in-60-btn[aria-expanded="true"] {
  filter: brightness(0.94);
}
.nav-list-in-60-menu {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 200;
  min-width: 300px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 14px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.10), 0 2px 6px rgba(0, 0, 0, 0.04);
  padding: 6px;
}
.nav-list-in-60-item {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 14px;
  border-radius: 10px;
  color: var(--ink);
  text-decoration: none;
  transition: background 0.12s;
}
.nav-list-in-60-item + .nav-list-in-60-item {
  margin-top: 2px;
}
.nav-list-in-60-item:hover,
.nav-list-in-60-item:focus-visible {
  background: var(--ivory-2);
  outline: none;
}
.nav-list-in-60-item-icon {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 9px;
  background: color-mix(in oklab, var(--saffron-deep, #d8a35e) 14%, var(--paper));
  color: var(--terracotta-deep, var(--saffron-deep, #c04e2e));
}
.nav-list-in-60-item-title {
  display: block;
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
  line-height: 1.2;
}
.nav-list-in-60-item-sub {
  display: block;
  font-size: 12px;
  color: var(--ink-3);
  margin-top: 3px;
  line-height: 1.35;
}
@media (max-width: 700px) {
  .nav-list-in-60-menu { min-width: 260px; }
}

/* ── Matches wide layout (page-inner extends when 3-col is present) */
.matches-wide { max-width: 1600px; }

/* ── Matches 3-col grid (overrides the earlier 2-col rule) ───── */
.matches-layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: 24px;
  align-items: start;
}
@media (min-width: 1100px) {
  .matches-layout { grid-template-columns: 240px 1fr; }
}
@media (min-width: 1300px) {
  .matches-layout { grid-template-columns: 240px 1fr 300px; }
}

/* ── Left rail (Streams / Pipeline / Tags) ──────────────────── */
.lrail {
  display: flex;
  flex-direction: column;
  gap: 14px;
  /* Sticky + hide-on-narrow are owned by the .app-rail primitive
     (Ship B of [[brief_realtyx_sticky_rail_primitive]]). The hide
     behaviour fires via the .app-rail--hide-narrow modifier the
     matches/left-rail partial composes; per-page sticky offset
     comes from the partial's inline --app-rail-top style. */
}
.lrail-section {
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--paper);
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.lrail-head {
  font-size: 10px;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--ink-4);
  margin-bottom: 2px;
}
.lrail-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
}
.lrail-item {
  display: flex;
  align-items: center;
}
.lrail-link {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 7px 4px;
  text-decoration: none;
  color: var(--ink-2);
  border-radius: 6px;
  font-size: 13px;
}
.lrail-link:hover { background: var(--ivory-2); color: var(--ink); }
.lrail-item--active .lrail-link { color: var(--ink); font-weight: 600; background: var(--ivory-2); }
.lrail-label { flex: 1; }
.lrail-count {
  font-size: 11px;
  color: var(--ink-4);
  letter-spacing: 0.02em;
}
.lrail-item--active .lrail-count { color: var(--saffron-deep); }
.lrail-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--saffron);
  flex-shrink: 0;
}

.lrail-pipeline-meta {
  font-size: 11px;
  color: var(--ink-3);
  letter-spacing: 0.04em;
  padding-bottom: 6px;
  border-bottom: 1px dashed var(--line);
}
.lrail-pipeline-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.lrail-pipeline-item {
  display: grid;
  grid-template-columns: 30px 1fr auto;
  align-items: center;
  gap: 8px;
}
.lrail-pipeline-initials {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--ink);
  color: var(--paper);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 600;
}
.lrail-pipeline-body { min-width: 0; }
.lrail-pipeline-title {
  font-size: 13px;
  color: var(--ink);
  font-weight: 500;
  line-height: 1.25;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.lrail-pipeline-sub {
  font-size: 10px;
  color: var(--ink-3);
  letter-spacing: 0.02em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.lrail-pipeline-count {
  font-size: 12px;
  font-weight: 600;
  color: var(--saffron-deep);
}
.lrail-cta {
  font-size: 11px;
  color: var(--ink-3);
  text-decoration: none;
  padding-top: 4px;
  border-top: 1px dashed var(--line);
  font-family: var(--mono);
  letter-spacing: 0.04em;
}
.lrail-cta:hover { color: var(--ink); }

.lrail-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.lrail-tag {
  display: inline-flex;
  align-items: center;
  padding: 4px 10px;
  border-radius: 999px;
  background: var(--ink);
  color: var(--paper);
  font-size: 11px;
  text-decoration: none;
}
.lrail-tag--edit {
  background: transparent;
  color: var(--ink-3);
  border: 1px solid var(--line-2);
  font-size: 10px;
}
.lrail-empty { font-size: 12px; color: var(--ink-3); }

/* ── Filter pills row ───────────────────────────────────────── */
.filter-pills {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 6px 0 18px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 18px;
}
.filter-pills-label {
  font-size: 10px;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--ink-4);
  padding-right: 6px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.filter-pills-label::before {
  content: '';
  width: 12px;
  height: 1px;
  background: var(--ink-4);
}
.filter-pill {
  display: inline-flex;
  align-items: center;
  padding: 7px 14px;
  border-radius: 999px;
  border: 1px solid var(--line-2);
  background: var(--paper);
  color: var(--ink-2);
  font-size: 12px;
  text-decoration: none;
  white-space: nowrap;
}
.filter-pill:hover { border-color: var(--ink-3); color: var(--ink); }
.filter-pill--active {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
  font-weight: 600;
}

/* ── Match pair (4-col refactor) ────────────────────────────── */
.match-pair-grid {
  display: grid;
  grid-template-columns: 1fr 92px 1fr;
  gap: 14px;
  align-items: stretch;
}
@media (min-width: 1200px) {
  /* Desktop: actions rail appears as 4th column. */
  .match-pair-grid { grid-template-columns: 1fr 92px 1fr 220px; }
}
@media (max-width: 800px) {
  .match-pair-grid { grid-template-columns: 1fr; }
}

/* Force score dial + actions-rail col flow on mid-width — the actions
 * rail wraps below feed on 800-1199px and becomes a horizontal row. */
.match-actions {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 14px;
  border-radius: 10px;
  background: var(--ivory-2);
  border: 1px solid var(--line);
  min-width: 0;
}
@media (max-width: 1199px) {
  .match-actions {
    grid-column: 1 / -1;
    flex-direction: row;
    align-items: center;
    flex-wrap: wrap;
  }
}
.match-actions-label {
  font-size: 10px;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.match-reason-chip {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 3px 8px;
  border-radius: 999px;
  font-size: 10px;
  border: 1px solid var(--line-2);
  background: var(--paper);
}
.match-reason-chip--ok { border-color: var(--green); background: var(--green-soft); color: var(--green); }
.match-reason-chip--miss { border-color: var(--red); background: var(--red-soft); color: var(--red); }
.match-actions-cta { display: flex; flex-direction: column; gap: 6px; }
.match-actions-cta .btn { width: 100%; }
@media (max-width: 1199px) {
  .match-actions-cta { flex-direction: row; flex-wrap: wrap; }
  .match-actions-cta .btn { width: auto; }
}
.match-actions-hint { font-size: 10px; color: var(--ink-3); line-height: 1.4; }
.match-actions-mini { padding-top: 6px; border-top: 1px dashed var(--line); }
@media (max-width: 1199px) {
  .match-actions-mini { border-top: none; padding-top: 0; }
}

/* Pair side extras: posted-time, attribution strip. */
.match-side { display: flex; flex-direction: column; gap: 10px; }
.match-side-top {
  display: flex;
  align-items: center;
  gap: 8px;
  justify-content: space-between;
}
.match-side-time, .match-side-badge {
  font-size: 10px;
  color: var(--ink-4);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.match-side-badge {
  padding: 2px 6px;
  border-radius: 4px;
  background: var(--ivory-2);
  border: 1px solid var(--line-2);
}
.match-buyer-ident { min-width: 0; }
.match-attrib {
  display: flex;
  align-items: center;
  gap: 6px;
  padding-top: 8px;
  margin-top: auto;
  border-top: 1px dashed var(--line);
  font-size: 11px;
  color: var(--ink-2);
  flex-wrap: wrap;
}
.match-attrib-initials {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--ink-4);
  color: var(--paper);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 9px;
  letter-spacing: 0;
  flex-shrink: 0;
}
.match-attrib-name { font-weight: 600; color: var(--ink); }
.match-attrib-firm { color: var(--ink-3); font-size: 10px; }
.match-attrib-trust { color: var(--saffron-deep); font-size: 10px; font-weight: 600; }
.match-attrib-role { color: var(--ink-4); font-size: 9px; letter-spacing: 0.08em; text-transform: uppercase; margin-left: auto; }

.match-dial-criteria {
  font-size: 9px;
  color: var(--ink-4);
  letter-spacing: 0.04em;
  text-align: center;
  margin-top: 4px;
}

/* Main column head spacing — eyebrow + h1 now live inside the grid. */
.matches-main-head { margin-bottom: 6px; }
.matches-main { min-width: 0; }

/* ── Right rail · Buyer Pulse list ──────────────────────────── */
.rail-pulse-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.rail-pulse {
  display: grid;
  grid-template-columns: 1fr auto auto;
  align-items: baseline;
  gap: 10px;
  padding-bottom: 7px;
  border-bottom: 1px dashed var(--line);
}
.rail-pulse:last-child { border-bottom: none; padding-bottom: 0; }
.rail-pulse-city {
  font-size: 13px;
  color: var(--ink);
  font-weight: 500;
}
.rail-pulse-total {
  font-size: 10px;
  color: var(--ink-3);
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.rail-pulse-delta {
  font-size: 11px;
  font-weight: 600;
  white-space: nowrap;
}
.rail-pulse-delta--pos  { color: var(--green); }
.rail-pulse-delta--neg  { color: var(--red); }
.rail-pulse-delta--flat { color: var(--ink-4); }

/* ── Navbar tabs (with counts + active state) ────────────────── */
.navbar-tabs {
  display: flex;
  gap: 2px;
  margin-left: 20px;
  flex-wrap: wrap;
  align-items: center;
}
.navtab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 12px;
  min-height: 36px;
  font-size: 13px;
  color: var(--ink-2);
  text-decoration: none;
  border-radius: 8px;
  font-weight: 500;
  border-bottom: 2px solid transparent;
}
.navtab:hover { color: var(--ink); background: var(--ivory-2); }
.navtab--active {
  color: var(--ink);
  background: var(--ivory-2);
  border-bottom-color: var(--saffron);
}
.navtab-count {
  font-family: var(--mono);
  font-size: 10px;
  padding: 2px 6px;
  border-radius: 999px;
  background: var(--ivory-2);
  color: var(--ink-3);
  letter-spacing: 0.02em;
  line-height: 1.2;
}
.navtab--active .navtab-count { background: var(--paper); color: var(--ink-2); }
.navtab-count--hot {
  background: var(--saffron);
  color: var(--ink);
  font-weight: 700;
}

/* Overflow menu — "More ▾" dropdown holding Saved / Directory / Tools /
   Admin so the primary navbar stays at 6 tabs. Built on native <details>
   to avoid an Alpine dependency; outside-click-to-close is a known
   trade-off — clicking the summary again, picking an item, or navigating
   away all close it. */
.navtab-more { position: relative; }
.navtab-more > summary { list-style: none; cursor: pointer; }
.navtab-more > summary::-webkit-details-marker { display: none; }
.navtab-more-summary { user-select: none; }
.navtab-more-caret { font-size: 10px; color: var(--ink-3); }
.navtab-more[open] > .navtab-more-summary {
  background: var(--ivory-2);
  color: var(--ink);
}
.navtab-more-menu {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  z-index: 20;
  min-width: 200px;
  padding: 6px;
  background: var(--paper);
  border: 1px solid color-mix(in oklab, var(--ink) 12%, transparent);
  border-radius: 8px;
  box-shadow: 0 6px 18px rgba(0,0,0,0.08);
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.navtab-more-menu .navtab {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  padding: 8px 12px;
  border-radius: 6px;
  border-bottom: none;
}
.navtab-more-menu .navtab--active,
.navtab-more-menu .navtab:hover {
  background: color-mix(in oklab, var(--saffron) 12%, transparent);
}

/* Profile dropdown — avatar-anchored menu that hosts My profile +
   theme toggle + language switcher + Sign out for authed users.
   Same <details>/<summary> mechanic as .navtab-more; styled to fit
   an avatar trigger instead of a text tab. */
.nav-profile-menu { position: relative; }
.nav-profile-menu > summary { list-style: none; cursor: pointer; display: inline-flex; }
.nav-profile-menu > summary::-webkit-details-marker { display: none; }
.nav-profile-summary { user-select: none; border-radius: 50%; }
.nav-profile-menu[open] > .nav-profile-summary .avatar {
  box-shadow: 0 0 0 2px var(--paper), 0 0 0 3px var(--ink);
}
.nav-profile-menu-panel {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 20;
  min-width: 220px;
  padding: 6px;
  background: var(--paper);
  border: 1px solid color-mix(in oklab, var(--ink) 12%, transparent);
  border-radius: 8px;
  box-shadow: 0 6px 18px rgba(0,0,0,0.08);
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.nav-profile-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 12px;
  border-radius: 6px;
  font-size: 13px;
  color: var(--ink);
  text-decoration: none;
  background: transparent;
  border: 0;
  width: 100%;
  cursor: pointer;
  font-family: inherit;
  text-align: left;
  margin: 0;
}
.nav-profile-item:hover,
.nav-profile-item:focus-within {
  background: color-mix(in oklab, var(--saffron) 12%, transparent);
}
.nav-profile-item-label { flex: 1; }
.nav-profile-item-trail {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--ink-3);
}
.nav-profile-divider {
  height: 1px;
  background: color-mix(in oklab, var(--ink) 10%, transparent);
  margin: 4px 2px;
}
/* Mobile-only workspace links inside the avatar dropdown. On desktop the
   _nav-pills rail + More▾ already expose these, so hide them here to avoid
   duplication; reveal at <=800px where the rail collapses and the bottom-nav
   only carries 5 slots. (Same 800px boundary as the navbar collapse.) */
.nav-profile-workspace { display: none; }
@media (max-width: 800px) {
  .nav-profile-workspace { display: block; }
  .nav-profile-divider.nav-profile-workspace { display: block; }
}
/* Count badge for workspace links in the dropdown (Matches/Leads/etc.). */
.nav-profile-item-count {
  margin-left: auto;
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 500;
  padding: 1px 6px;
  border-radius: 999px;
  line-height: 1.3;
  background: var(--ivory-2);
  color: var(--ink-3);
}
.nav-profile-item-count--hot { background: var(--saffron); color: var(--ink); font-weight: 700; }
.nav-profile-item--active { background: color-mix(in oklab, var(--saffron) 12%, transparent); color: var(--ink); }
/* Language pill inside the dropdown trail. Two compact buttons that
   share the same toggle state as the old top-bar pill. */
.nav-profile-lang-btn {
  font-family: var(--mono);
  font-size: 11px;
  padding: 2px 8px;
  border-radius: 4px;
  border: 1px solid transparent;
  background: transparent;
  color: var(--ink-3);
  cursor: pointer;
}
.nav-profile-lang-btn.is-active {
  color: var(--ink);
  background: var(--ivory-2);
  border-color: color-mix(in oklab, var(--ink) 10%, transparent);
}
.nav-profile-item--logout { padding: 0; }
.nav-profile-logout-btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  padding: 8px 12px;
  border-radius: 6px;
  background: transparent;
  border: 0;
  color: var(--accent, var(--saffron));
  cursor: pointer;
  font-family: inherit;
  font-size: 13px;
  text-align: left;
}
.nav-profile-logout-btn:hover {
  background: color-mix(in oklab, var(--accent, var(--saffron)) 12%, transparent);
}

/* Sprint 2 — RealtyX standalone guest page. 2-col shell: locality-first
   left rail + center stream. Stacks at <960px so the rail collapses
   above the stream on mobile. */
.realtyx-shell {
  display: grid;
  grid-template-columns: 260px minmax(0, 1fr);
  gap: 24px;
  align-items: start;
  margin-top: 16px;
}
@media (max-width: 960px) {
  .realtyx-shell { grid-template-columns: 1fr; }
}
/* D10 — .realtyx-breadcrumb deleted 2026-05-29: zero markup references
   in views; the canonical breadcrumb is <x-breadcrumb> from the
   project_breadcrumb_system MEMORY item. Kept the .realtyx-guest-banner
   below since the orphan-status check should be done independently
   for it (separate audit task). */
.realtyx-guest-banner {
  display: inline-block;
  margin: 12px 0 0;
  padding: 6px 12px;
  background: var(--ivory-2);
  border-radius: 6px;
  font-size: 13px;
  color: var(--ink-2);
}
.feed-rail-current {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
  margin: 4px 0 0;
}
.ph-section-footer {
  margin-top: 12px;
  text-align: center;
}
/* Compact teaser layout on the homepage — activity-stream framing.
   Items render as a single-column stack inside a framed container
   so per-item content variance (a listing with photos vs an event
   with an RSVP button) doesn't pull the layout apart. Alignment is
   automatic because rows don't compete horizontally; the framed
   border + bottom-dividers between rows give the section a unified
   "live feed" visual signature. */
.feed-stream--teaser {
  display: flex;
  flex-direction: column;
  gap: 0;
  max-width: 760px;
  margin: 0 auto;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--paper);
  overflow: hidden;
}
.feed-stream--teaser .feed-item,
.feed-stream--teaser .feed-item-wrapper {
  margin: 0;
  padding: 18px 22px;
  border: none;
  border-bottom: 1px solid var(--line);
  border-radius: 0;
  background: transparent;
}
.feed-stream--teaser .feed-item:last-child,
.feed-stream--teaser .feed-item-wrapper:last-child {
  border-bottom: none;
}
.feed-stream--teaser .feed-item--buyer {
  background: color-mix(in oklab, var(--saffron-soft, oklch(0.94 0.05 80)) 50%, transparent);
}
/* Cap photo collages so a listing item doesn't dwarf the next event
   row — a strip of small thumbnails reads as "media attached" without
   stealing the visual weight from the activity verb / broker name. */
.feed-stream--teaser .feed-listing-images,
.feed-stream--teaser .feed-photos,
.feed-stream--teaser .feed-item .feed-listing-photo,
.feed-stream--teaser .feed-item .feed-image-grid {
  max-height: 96px;
  overflow: hidden;
  border-radius: 8px;
}

/* Sprint 3 — notification bell + dropdown. Authed-only nav element. */
.notif-bell { position: relative; display: inline-block; margin-right: 8px; }
.notif-bell-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 999px;
  background: transparent;
  border: 1px solid var(--ink-line, rgba(0,0,0,0.12));
  color: var(--ink-2);
  cursor: pointer;
}
.notif-bell-btn:hover { background: var(--ivory-2); }
.notif-bell-badge {
  position: absolute;
  top: -4px;
  right: -4px;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 999px;
  background: #d9342b;
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.notif-bell-menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 200;
  width: 340px;
  /* Cap by viewport - notch/indicator inset - navbar (80px) so the
     scrollable menu never extends under the dynamic island or home
     indicator on short notched viewports. Falls back to 480px on
     tall viewports / non-notched devices ([[safe-area-sweep]]). */
  max-height: min(480px, calc(100vh - var(--inset-top) - var(--inset-bottom) - 80px));
  overflow-y: auto;
  background: var(--paper);
  border: 1px solid var(--ink-line, rgba(0,0,0,0.12));
  border-radius: 10px;
  box-shadow: 0 12px 32px rgba(0,0,0,0.10);
}
/* Mobile reflow — the desktop rule above anchors `right: 0` to .notif-bell
   (which is `position: relative`). On a 360-420px viewport the bell sits
   mid-navbar; right-anchoring + the fixed 340px width pushes the menu's
   left edge to ~-100px, clipping every line off the left of the screen.

   Fix: at <=560px the menu becomes a viewport-anchored sheet under the
   navbar. `position: fixed` makes the containing block the viewport
   (not .notif-bell), so left/right insets actually mean "from the
   viewport edge". The 56px navbar height comes from mobile padding
   10px + bell button 36px + 10px = 56 (verified against .navbar-inner
   @media block at L65-68). +6px gap mirrors the desktop top: calc(100% + 6px).

   x-dismissable outside-click still works: it tests DOM containment via
   root.contains(e.target), not visual containment. The menu remains a DOM
   child of .notif-bell regardless of CSS `position: fixed`. (Verified by
   the precedent at .ps-lean-cat-menu @ <=999px which uses the same
   pattern in production.) */
@media (max-width: 560px) {
  .notif-bell-menu {
    position: fixed;
    top: calc(var(--inset-top) + 56px + 6px);
    left: 8px;
    right: 8px;
    width: auto;
    max-height: calc(100vh - var(--inset-top) - var(--inset-bottom) - 64px - var(--bottom-nav-clearance-12, 76px));
  }
}
.notif-bell-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 14px;
  border-bottom: 1px solid var(--ink-line, rgba(0,0,0,0.06));
  font-size: 13px;
}
.notif-bell-readall {
  background: none; border: 0;
  font-size: 11px;
  color: var(--ink-3);
  cursor: pointer;
}
.notif-bell-readall:hover { color: var(--ink); }
.notif-bell-list { padding: 4px; }
.notif-bell-empty { padding: 18px 14px; color: var(--ink-3); font-size: 13px; }
.notif-bell-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 10px;
  border-radius: 6px;
  color: var(--ink);
  text-decoration: none;
  font-size: 13px;
}
.notif-bell-item:hover { background: var(--ivory-2); }
.notif-bell-item.is-unread { font-weight: 600; }
.notif-bell-item.is-unread::before {
  content: '';
  display: inline-block;
  width: 6px; height: 6px;
  border-radius: 999px;
  background: #d9342b;
  margin-right: 6px;
  vertical-align: middle;
}
.notif-bell-time { color: var(--ink-3); font-size: 11px; }
.notif-bell-foot {
  display: block;
  padding: 10px 14px;
  border-top: 1px solid var(--ink-line, rgba(0,0,0,0.06));
  font-size: 12px;
  color: var(--ink-2);
  text-decoration: none;
  text-align: center;
}
.notif-bell-foot:hover { background: var(--ivory-2); color: var(--ink); }

/* Sprint 3 — /saved polish. Posts get a left thumb when photo_url exists;
   Events get a left calendar tile + optional cover thumb. Bare-text rows
   were boring; visual cues make the saved list browsable at a glance. */
.saved-post-row,
.saved-event-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 14px;
  align-items: flex-start;
}
.saved-event-row { grid-template-columns: auto auto minmax(0, 1fr); }
@media (max-width: 560px) {
  .saved-event-row { grid-template-columns: auto minmax(0, 1fr); }
  .saved-event-thumb { display: none; }
}
.saved-post-thumb,
.saved-event-thumb {
  display: block;
  width: 90px;
  height: 90px;
  border-radius: 8px;
  overflow: hidden;
  background: var(--ivory-2);
  flex-shrink: 0;
}
.saved-post-thumb img,
.saved-event-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.saved-post-body,
.saved-event-body { min-width: 0; }

/* Sprint 3 — full /notifications page list. */
.notif-list { list-style: none; margin: 16px 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.notif-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  background: var(--paper);
  border: 1px solid var(--ink-line, rgba(0,0,0,0.08));
  border-radius: 8px;
}
.notif-row.is-unread { border-left: 3px solid #d9342b; }
.notif-row-body { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; text-decoration: none; color: var(--ink); }
.notif-row-text { font-size: 14px; }
.notif-row.is-unread .notif-row-text { font-weight: 600; }
.notif-row-time { color: var(--ink-3); font-size: 11px; }

/* Sprint 3 — Developer chip escape hatch link. Visible only when type
   is inventory_alert AND audience is builder. Subtle — looks like a
   form note, not a primary CTA. */
.compose-dev-jump {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 14px;
  padding: 8px 12px;
  background: var(--ivory-2);
  border-radius: 6px;
  font-size: 12px;
}
.compose-dev-jump a {
  color: var(--ink);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}
.compose-dev-jump a:hover { text-decoration: underline; }

/* Sprint 3 — pinned posts surface at the top of For You + Latest. The
   feed-item--pinned modifier adds a saffron left-accent + sits behind
   the eyebrow strip. Eyebrow is monospace + uppercased ("📌 PINNED BY
   REALTYX") to read as editorial chrome, not part of the post body. */
.feed-item-wrapper.feed-item--pinned {
  position: relative;
  border-left: 3px solid var(--saffron, #d68a00);
  padding-left: 8px;
  margin-left: -11px;
}
.feed-item-pinned-eyebrow {
  display: inline-block;
  margin: 0 0 6px;
  padding: 2px 8px;
  background: var(--saffron, #d68a00);
  color: var(--ink, #000);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  border-radius: 4px;
}

/* Sprint 3 — inline comment preview on feed cards. Top 2 most-recent
   comments stacked tightly below the post body; "view N more →" link
   when the post has further comments. */
.post-comments-preview {
  margin: 12px 0 0;
  padding: 8px 12px;
  background: var(--ivory-2);
  border-radius: 6px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
/* 2-row grid — the canonical chat/comment pattern (Twitter, Reddit,
   Facebook all ship this). Row 1: author auto-grows + timestamp
   parked right. Row 2: body spans the full row. The previous 3-col
   single-row attempt fought a constraint that has no good answer
   on a 360 px viewport — author + body + time can't all fit
   readably on one line. Splitting body to its own row solves the
   root cause: the body always gets full row width to wrap as
   prose instead of every 2-3 words. */
.post-comment-row {
  display: grid;
  grid-template-columns: 1fr auto;
  column-gap: 8px;
  row-gap: 3px;
  align-items: baseline;
  font-size: 12px;
  line-height: 1.4;
}
.post-comment-author {
  grid-column: 1;
  grid-row: 1;
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
  /* min-width: 0 is LOAD-BEARING inside the 1fr grid track —
     without it the grid item's default min-content floor keeps it
     from shrinking below its longest word, so ellipsis never
     fires. Do NOT strip on cleanup. */
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.post-comment-author:hover { text-decoration: underline; }
.post-comment-time {
  grid-column: 2;
  grid-row: 1;
  color: var(--ink-3);
  font-size: 10px;
  white-space: nowrap;
}
.post-comment-body {
  grid-column: 1 / -1;
  grid-row: 2;
  color: var(--ink-2);
  /* min-width: 0 + overflow-wrap: anywhere lets long URLs / no-space
     strings wrap at any char so the body never pushes the card
     wider than its container. word-break: normal pinned explicitly
     so a future UA upgrade can't promote to break-all, which would
     shatter Devanagari conjunct clusters (क्ष, ज्ञ) at virama/ZWJ. */
  min-width: 0;
  overflow-wrap: anywhere;
  word-break: normal;
}
.post-comment-more {
  display: inline-block;
  margin-top: 4px;
  font-size: 11px;
  color: var(--ink-3);
  text-decoration: none;
}
.post-comment-more:hover { color: var(--ink); }

/* Sprint 3 — quote-post inline preview. Embedded card on the quoting
   post showing the source post's author + body snippet. Click anywhere
   on the card to open the source post. */
.post-quote {
  display: block;
  margin: 12px 0;
  padding: 10px 12px;
  border-left: 3px solid var(--saffron, #d68a00);
  background: var(--ivory-2);
  border-radius: 0 6px 6px 0;
  text-decoration: none;
  color: var(--ink);
}
.post-quote:hover { background: var(--ivory); }
.post-quote-head { font-size: 11px; color: var(--ink-3); margin-bottom: 4px; }
.post-quote-eyebrow { letter-spacing: 0.04em; }
.post-quote-author { color: var(--ink-2); font-weight: 600; margin-left: 4px; }
.post-quote-body { font-size: 13px; color: var(--ink-2); line-height: 1.4; }

/* Sprint 3 — composer quote preview (above body field). */
.compose-quote-preview {
  margin-bottom: 14px;
  padding: 10px 12px;
  border-left: 3px solid var(--saffron, #d68a00);
  background: var(--ivory-2);
  border-radius: 0 6px 6px 0;
}
.compose-quote-preview-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 11px;
  color: var(--ink-3);
  margin-bottom: 4px;
}
.compose-quote-clear {
  color: var(--ink-3);
  text-decoration: none;
  font-size: 16px;
  line-height: 1;
  padding: 0 4px;
}
.compose-quote-clear:hover { color: var(--ink); }
.compose-quote-preview-body { font-size: 13px; color: var(--ink-2); }

/* Sprint 2 — inline poll voting (Poll-category posts). Each row is
   a full-width button; the fill bar is an absolutely-positioned span
   sized to the percentage of total votes. Click to vote / switch /
   un-vote (PollVotesController toggle semantics). */
.post-poll {
  margin: 12px 0 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.post-poll-row-form { margin: 0; }
.post-poll-row {
  position: relative;
  display: block;
  width: 100%;
  padding: 10px 12px;
  background: var(--ivory-2);
  border: 1px solid var(--ink-line, rgba(0,0,0,0.08));
  border-radius: 8px;
  font-size: 13px;
  color: var(--ink);
  cursor: pointer;
  text-align: left;
  text-decoration: none;
  overflow: hidden;
}
.post-poll-row:hover { background: var(--ivory); }
.post-poll-row.is-mine {
  background: var(--paper);
  border-color: var(--ink);
}
.post-poll-row-fill {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  background: rgba(255, 138, 0, 0.16);
  z-index: 0;
  transition: width 0.4s ease;
}
.post-poll-row.is-mine .post-poll-row-fill { background: rgba(0, 0, 0, 0.08); }
.post-poll-row-content {
  position: relative;
  z-index: 1;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
}
.post-poll-row-text { font-weight: 500; }
.post-poll-row-count { color: var(--ink-3); font-size: 11px; white-space: nowrap; }
.post-poll-meta { margin: 6px 0 0; font-size: 11px; color: var(--ink-3); }

/* Sprint 2 — feed event mini-card uses the shared calendar tile.
   Date sits on the left; everything else stacks to the right. */
.feed-item-event-row { display: flex; gap: 12px; padding-top: 8px; }
.feed-item-event-body { flex: 1; min-width: 0; }

/* Sprint 2 — event detail (Screen 6). 2-col shell: main + RSVP rail.
   Stacks at <960px so the RSVP rail collapses below main on mobile. */
.event-shell {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 24px;
  align-items: start;
  margin-top: 16px;
}
@media (max-width: 960px) {
  .event-shell { grid-template-columns: 1fr; }
}
.event-main { min-width: 0; }
.event-head {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 16px;
  align-items: flex-start;
  margin-bottom: 16px;
}
.event-head-body { min-width: 0; }
.event-head-title {
  font-size: 26px;
  font-weight: 600;
  margin: 0 0 8px;
  letter-spacing: -0.01em;
}
.event-head-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 8px;
}
.event-head-sub { color: var(--ink-2); margin: 0; }

/* Calendar tile — shared with feed event mini-card. */
.calendar-tile {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: var(--paper);
  border: 1px solid var(--ink-line, rgba(0,0,0,0.12));
  border-radius: 8px;
  padding: 8px 12px;
  text-decoration: none;
  color: var(--ink);
  line-height: 1.1;
  text-align: center;
}
.calendar-tile-weekday {
  font-size: 10px;
  letter-spacing: 0.06em;
  color: var(--ink-3);
  font-weight: 600;
}
.calendar-tile-day {
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 2px 0;
}
.calendar-tile-month {
  font-size: 10px;
  color: var(--ink-2);
  font-weight: 600;
  letter-spacing: 0.06em;
}
.calendar-tile-year { font-size: 10px; color: var(--ink-3); }
.calendar-tile--sm { padding: 4px 8px; }
.calendar-tile--sm .calendar-tile-day { font-size: 16px; }
.calendar-tile--lg { padding: 12px 16px; min-width: 72px; }
.calendar-tile--lg .calendar-tile-day { font-size: 30px; }

.event-meta-row {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  margin: 12px 0 16px;
  padding: 10px 14px;
  background: var(--ivory-2);
  border-radius: 8px;
  font-size: 13px;
}
.event-meta-cell {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--ink-2);
}

.event-cover {
  margin-bottom: 16px;
  border-radius: 12px;
  overflow: hidden;
  aspect-ratio: 16 / 9;
}
.event-cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.event-section { margin-bottom: 24px; }
.event-section-h2 { font-size: 16px; font-weight: 600; margin: 0 0 8px; }
.event-host-card {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px;
  background: var(--paper);
  border: 1px solid var(--ink-line, rgba(0,0,0,0.08));
  border-radius: 8px;
}
.event-host-meta { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }
.event-host-name { font-weight: 600; color: var(--ink); text-decoration: none; }

.event-attendees {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}
.event-attendee-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 999px;
  background: var(--ivory-2);
  border: 2px solid var(--paper);
  color: var(--ink);
  font-weight: 600;
  font-size: 13px;
  text-decoration: none;
  overflow: hidden;
}
.event-attendee-avatar img { width: 100%; height: 100%; object-fit: cover; }
.event-attendee-more {
  margin-left: 8px;
  color: var(--ink-3);
  font-size: 12px;
}

.event-add-cal-buttons { display: flex; flex-wrap: wrap; gap: 8px; }

/* RSVP rail (right) */
.event-rsvp {
  background: var(--paper);
  border: 1px solid var(--ink-line, rgba(0,0,0,0.08));
  border-radius: 12px;
  padding: 16px;
  position: sticky;
  top: 80px;
}
.event-rsvp-h2 { font-size: 14px; font-weight: 600; margin: 0 0 8px; color: var(--ink-3); letter-spacing: 0.04em; text-transform: uppercase; }
.event-rsvp-counts { font-size: 13px; color: var(--ink-2); margin-bottom: 8px; }
.event-rsvp-progress {
  height: 6px;
  background: var(--ivory-2);
  border-radius: 999px;
  margin-bottom: 16px;
  overflow: hidden;
}
.event-rsvp-progress-fill {
  display: block;
  height: 100%;
  background: var(--ink);
  transition: width 0.4s ease;
}
.event-rsvp-form { display: flex; flex-direction: column; gap: 8px; }
.event-rsvp-yes {
  width: 100%;
  padding: 12px;
  font-size: 14px;
  font-weight: 600;
}
.event-rsvp-yes.is-current {
  background: #10b981;
  border-color: #10b981;
}
.event-rsvp-secondary {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
}
.event-rsvp-secondary .is-current {
  background: var(--ink);
  color: var(--paper);
}
.event-rsvp-wa {
  display: block;
  margin-top: 12px;
  font-size: 12px;
  color: var(--ink-3);
  text-decoration: none;
  text-align: center;
}
.event-rsvp-wa:hover { color: var(--ink); text-decoration: underline; }

/* Sprint 2 — onboarding 3-step stepper (Screen 1). Bare-canvas layout
   served from layouts.onboarding (no nav, no chrome). */
.onboarding-bare {
  background: var(--ivory, #f7f3eb);
  min-height: 100vh;
}
.onboarding-shell {
  max-width: 640px;
  margin: 0 auto;
  padding: 48px 20px;
}
.onboarding-stepper {
  list-style: none;
  margin: 0 0 24px;
  padding: 0;
  display: flex;
  gap: 16px;
  justify-content: center;
  flex-wrap: wrap;
}
.onboarding-step {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--ink-3);
}
.onboarding-step-dot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 999px;
  background: var(--ivory-2);
  color: var(--ink-3);
  font-size: 12px;
  font-weight: 600;
}
.onboarding-step--current { color: var(--ink); font-weight: 600; }
.onboarding-step--current .onboarding-step-dot {
  background: var(--ink);
  color: var(--paper);
}
.onboarding-step--done { color: var(--ink-2); }
.onboarding-step--done .onboarding-step-dot {
  background: #10b981;
  color: #fff;
}

.onboarding-card {
  background: var(--paper);
  border: 1px solid var(--ink-line, rgba(0,0,0,0.08));
  border-radius: 12px;
  padding: 24px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.04);
}
.onboarding-h1 {
  font-size: 22px;
  font-weight: 600;
  margin: 0 0 6px;
  letter-spacing: -0.01em;
}
.onboarding-sub {
  color: var(--ink-3);
  font-size: 14px;
  margin: 0 0 20px;
}
.onboarding-form { margin: 0; }

.onboarding-roles {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
  margin-bottom: 20px;
}
@media (max-width: 480px) {
  .onboarding-roles { grid-template-columns: 1fr; }
}
.onboarding-role-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 12px 16px;
  background: var(--ivory-2);
  border: 1px solid var(--ink-line, rgba(0,0,0,0.08));
  border-radius: 8px;
  font-size: 14px;
  font-weight: 500;
  color: var(--ink);
  cursor: pointer;
  transition: transform 0.08s ease;
}
.onboarding-role-chip:hover { background: var(--ivory); }
.onboarding-role-chip.is-active {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}

.onboarding-suggested {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 16px;
}
.onboarding-suggest-chip {
  padding: 6px 12px;
  background: var(--ivory-2);
  border: 1px dashed var(--ink-line, rgba(0,0,0,0.16));
  border-radius: 999px;
  font-size: 12px;
  color: var(--ink-2);
  cursor: pointer;
}
.onboarding-suggest-chip:hover { background: var(--ivory); }
.onboarding-suggest-chip.is-picked {
  opacity: 0.5;
  cursor: not-allowed;
}

.onboarding-picker { position: relative; }
.onboarding-picker-pills {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  padding: 10px;
  border: 1px solid var(--ink-line, rgba(0,0,0,0.12));
  border-radius: 8px;
  min-height: 48px;
}
.onboarding-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: var(--ink);
  color: var(--paper);
  border-radius: 999px;
  padding: 4px 10px;
  font-size: 12px;
}
.onboarding-pill button {
  background: none;
  border: 0;
  color: var(--paper);
  cursor: pointer;
  font-size: 14px;
  padding: 0;
}
.onboarding-picker-input {
  flex: 1;
  min-width: 180px;
  border: 0;
  outline: none;
  background: transparent;
  font-size: var(--fs-input);
}
/* The dropdown is position:absolute with top:100% — it needs a
   positioned ancestor to anchor against. .onboarding-city-input-wrap
   IS relative but only wraps the input + × button, NOT the dropdown.
   Without this rule the dropdown falls back to the body's coordinate
   system and ends up rendered far below the viewport — invisible
   despite x-show being true. */
.onboarding-city-field { position: relative; }
.onboarding-suggest {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 50;
  margin-top: 4px;
  background: var(--paper);
  border: 1px solid var(--ink-line, rgba(0,0,0,0.12));
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
  max-height: 280px;
  overflow-y: auto;
}
.onboarding-suggest-row {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 100%;
  padding: 8px 12px;
  background: transparent;
  border: 0;
  text-align: left;
  cursor: pointer;
}
.onboarding-suggest-row:hover { background: var(--ivory-2); }
.onboarding-counter { margin: 8px 0 0; color: var(--ink-3); font-size: 12px; }

.onboarding-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 20px;
}

/* Sprint 3 — onboarding Step 3 optional price-band chips. Sits below
   the locality picker; multi-select toggle (tap to add/remove). */
.onboarding-priceband-block {
  margin-top: 24px;
  padding-top: 20px;
  border-top: 1px solid var(--ink-line, rgba(0,0,0,0.08));
}
.onboarding-h2 {
  font-size: 16px;
  font-weight: 600;
  margin: 0 0 4px;
  letter-spacing: -0.005em;
}

/* "I work in {city}" selector block on onboarding Step 3. Mirrors
   .compose-field so the picker looks consistent with the rest of
   the form UI. */
.onboarding-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin: 12px 0 8px;
}
.onboarding-field > .form-label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-3);
}
.onboarding-field > .form-note {
  font-size: 12px;
  color: var(--ink-3);
}
/* City autocomplete on Step 3 — input + clear (×) button overlay.
   Replaces the 31k-row <select>. The × clears the picked value back
   to the geo-IP suggestion line + lets the broker retype. */
.onboarding-city-input-wrap {
  position: relative;
}
.onboarding-city-input-wrap > .form-input {
  padding-right: 36px; /* keep room for the × button */
}
.onboarding-city-clear {
  position: absolute;
  right: 8px;
  top: 50%;
  transform: translateY(-50%);
  width: 22px;
  height: 22px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  border: 0;
  background: var(--ivory-2);
  color: var(--ink-3);
  cursor: pointer;
  font-size: 16px;
  line-height: 1;
}
.onboarding-city-clear:hover {
  background: color-mix(in oklab, var(--saffron) 16%, transparent);
  color: var(--ink);
}
.onboarding-priceband-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 12px;
}
.onboarding-priceband-chip {
  padding: 6px 14px;
  background: var(--ivory-2);
  border: 1px solid var(--ink-line, rgba(0,0,0,0.12));
  border-radius: 999px;
  font-size: 13px;
  color: var(--ink-2);
  cursor: pointer;
  transition: background-color 0.08s ease;
}
.onboarding-priceband-chip:hover { background: var(--ivory); }
.onboarding-priceband-chip.is-active {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}

/* Sprint 3 — RERA prompt page (post-onboarding for brokers). */
.onboarding-rera-eyebrow {
  font-size: 11px;
  color: var(--ink-3);
  letter-spacing: 0.06em;
  text-transform: lowercase;
  margin-bottom: 4px;
}
.onboarding-rera-form { margin-top: 16px; }
.onboarding-rera-actions { justify-content: space-between; }
.onboarding-rera-footnote {
  margin-top: 16px;
  padding-top: 12px;
  border-top: 1px solid var(--ink-line, rgba(0,0,0,0.08));
  font-size: 11px;
  color: var(--ink-3);
  line-height: 1.5;
}

/* Sprint 2 — broker profile (Screen 5). 2-col shell: main + right rail.
   Cover banner above the page-inner — full-bleed gradient placeholder
   until the per-locality skyline asset ships. */
.broker-cover {
  width: 100%;
  height: 180px;
  background: linear-gradient(135deg, #5a3a1a 0%, #d68a00 60%, #b54a2e 100%);
  background-size: cover;
  background-position: center;
}
/* Broker-uploaded cover image — inline style sets background-image;
   here we just make sure the image covers the box without repeating
   and override the gradient (the inline background-image shorthand
   from the style attribute already wins on the `background` short-
   hand, but explicit background-color: transparent guards against a
   future refactor that splits the property). */
.broker-cover--img {
  background-color: transparent;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}
.broker-shell {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 280px;
  gap: 24px;
  align-items: start;
  margin-top: -48px; /* lift identity strip onto cover */
}
@media (max-width: 960px) {
  .broker-shell { grid-template-columns: 1fr; margin-top: -32px; }
}
.broker-main { min-width: 0; }
.broker-rail { min-width: 0; }

.broker-head {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 16px;
  align-items: flex-end;
  background: var(--paper);
  border: 1px solid var(--ink-line, rgba(0,0,0,0.08));
  border-radius: 12px;
  padding: 16px;
  margin-bottom: 16px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.04);
}
@media (max-width: 720px) {
  .broker-head { grid-template-columns: auto minmax(0, 1fr); }
  .broker-head-actions { grid-column: 1 / -1; }
}
.broker-head-avatar img,
.broker-head-avatar .x-avatar {
  width: 96px;
  height: 96px;
  border-radius: 999px;
  border: 4px solid var(--paper);
  background: var(--ivory-2);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
  /* Non-square sources were stretching to fill the 96×96 box.
     `cover` crops to fit while preserving aspect ratio. */
  object-fit: cover;
  object-position: center;
}
.broker-head-body { min-width: 0; }
.broker-head-name {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  font-size: 22px;
  margin: 0 0 4px;
  letter-spacing: -0.01em;
}
.broker-head-meta {
  font-size: 12px;
  color: var(--ink-3);
  margin: 0 0 4px;
}
.broker-head-firm {
  font-size: 13px;
  color: var(--ink-2);
  margin: 0;
}
.broker-head-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.btn-icon {
  width: 36px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.broker-stats-row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  margin: 0 0 16px;
  padding: 12px 16px;
  background: var(--paper);
  border: 1px solid var(--ink-line, rgba(0,0,0,0.08));
  border-radius: 12px;
}
.broker-stats-row > div { text-align: center; }
.broker-stats-row dt {
  display: block;
  color: var(--ink-3);
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: lowercase;
}
.broker-stats-row dd {
  margin: 2px 0 0;
  font-weight: 700;
  font-size: 18px;
}
.broker-stat-value { font-variant-numeric: tabular-nums; }
@media (max-width: 560px) {
  .broker-stats-row { grid-template-columns: repeat(2, 1fr); }
}

.broker-about { padding: 16px 0; }
.broker-about-h3 { font-size: 14px; margin: 16px 0 4px; }

.broker-rail .feed-rail-section { margin-bottom: 16px; }
.broker-badges {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.broker-badge {
  background: var(--ivory-2);
  border-radius: 6px;
  padding: 6px 10px;
  font-size: 12px;
  color: var(--ink);
}

.broker-recent-listings {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.broker-recent-listing {
  display: flex;
  flex-direction: column;
  padding: 8px 10px;
  border-radius: 8px;
  background: var(--ivory-2);
  color: var(--ink);
  text-decoration: none;
}
.broker-recent-listing:hover { background: var(--ivory); }
.broker-recent-listing-title { font-size: 13px; font-weight: 500; }

/* Sprint 2 — compose FAB. Authed-only floating button bottom-right. */
.compose-fab {
  position: fixed;
  /* No-crop reflex D12 — safe-area inset so notched-iPhone landscape
     + home-indicator gestures don't clip the FAB. Defaults preserve
     the 24px visual baseline on non-notched devices. */
  right: max(24px, var(--inset-right));
  bottom: max(24px, var(--inset-bottom));
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--ink);
  color: var(--paper);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
  text-decoration: none;
  z-index: 50;
  transition: transform 0.12s ease;
}
.compose-fab:hover { transform: scale(1.04); }
/* Hide on mobile (<=800px): the <x-mobile-bottom-nav> already provides a
   centre "+" Compose FAB at this breakpoint, so the page-level floating
   .compose-fab (bottom-right) was rendering as a SECOND "+" overlapping
   the bottom-nav's "Me" slot. Both route to compose.show — drop the
   redundant one on mobile, keep it on desktop where there is no bottom-nav. */
@media (max-width: 800px) {
  .compose-fab { display: none; }
  /* On phones the <x-mobile-bottom-nav> is fixed at the bottom (64px +
     safe-area). Reserve that space + tighten the page padding so the
     composer's submit row clears the bottom-nav and the modal can use more
     of the short viewport. */
  .compose-page { padding: 12px 12px calc(72px + var(--inset-bottom)); }
  /* The .compose-modal max-height override that lived here previously
     was the desktop card pretending to fit on phones — it fought the
     iOS keyboard, the sticky head, and the mobile-bottom-nav at the
     same time. Retired by the bottom-sheet redesign in the
     `@media (hover:none) and (pointer:coarse)` block further down
     this file; that block reshapes .compose-modal into a full-bleed
     position:fixed sheet on touch viewports. See
     memory/brief_realtyx_compose_sheet.md. */
}

/* Sprint 2 — RealtyX composer modal page. Renders as a full-page
   page-shell with a centered card per the locked mockup B_Single-page modal. */
.compose-page {
  min-height: calc(100vh - 64px);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 24px 16px;
}
.compose-modal {
  width: 100%;
  max-width: 980px;
  background: var(--paper);
  border: 1px solid var(--ink-line, rgba(0,0,0,0.12));
  border-radius: 12px;
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.08);
  /* The composer uses x-trap.noscroll, which locks <body> scroll — so the
     MODAL itself must scroll internally or its bottom (type chips, photo/
     video/poll, submit) is clipped on short viewports with no way to reach
     it. Cap the height to the viewport minus the live-bar/nav (64px) + the
     .compose-page padding (24px × 2) and scroll inside. */
  max-height: calc(100dvh - 64px - 48px);
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
}
.compose-modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 24px;
  border-bottom: 1px solid var(--ink-line, rgba(0,0,0,0.08));
  /* Keep the title + × visible while the body scrolls. */
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--paper);
}
.compose-modal-title {
  font-size: 18px;
  font-weight: 600;
  margin: 0;
  letter-spacing: -0.01em;
}
.compose-modal-close {
  font-size: 28px;
  line-height: 1;
  color: var(--ink-3);
  text-decoration: none;
  padding: 0 8px;
}
.compose-modal-close:hover { color: var(--ink); }

.compose-typebar {
  display: flex;
  gap: 6px;
  padding: 12px 24px;
  border-bottom: 1px solid var(--ink-line, rgba(0,0,0,0.08));
  flex-wrap: wrap;
}
.compose-type-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  /* Rubric D3 48px floor — pill grows from 28->48px tall. Padding
     unchanged; min-height adds breathing. See [[brief_realtyx_tap_44_lint]]. */
  min-height: var(--tap);
  min-width: var(--tap);
  border: 1px solid var(--ink-line, rgba(0,0,0,0.12));
  border-radius: 999px;
  font-size: 13px;
  color: var(--ink-2);
  text-decoration: none;
  cursor: pointer;
  background: transparent;
}
.compose-type-chip:hover { background: var(--ivory-2); }
.compose-type-chip.is-active {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}

.compose-form { padding: 16px 24px 24px; }
.compose-identity {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 16px;
}
.compose-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  background: var(--ink);
  color: var(--paper);
  border-radius: 999px;
  font-weight: 700;
  font-size: 14px;
  /* No-crop reflex D4 — fixed-dimension avatar never gets squeezed
     when the meta text beside it grows. */
  flex-shrink: 0;
}
.compose-identity-name {
  font-weight: 600;
  /* No-crop reflex D2 — long name doesn't push the row past the
     identity card container. */
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.compose-identity-meta {
  color: var(--ink-3); font-size: 12px;
  /* No-crop reflex D2 — meta line shrink + ellipsis on long
     office/firm names. */
  min-width: 0;
  flex: 1 1 auto;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.compose-field { display: block; margin-bottom: 14px; }
.compose-field .form-label {
  display: block;
  font-size: 12px;
  color: var(--ink-3);
  letter-spacing: 0.02em;
  margin-bottom: 4px;
}
.compose-input-title { font-size: 16px; }
.compose-input-body { font-size: var(--fs-input); min-height: 140px; resize: vertical; }

.compose-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}
.compose-action-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  /* Rubric D3 48px floor — chip grows to 48px tall. Padding kept,
     min-height adds breathing. See [[brief_realtyx_tap_44_lint]]. */
  min-height: var(--tap);
  min-width: var(--tap);
  border: 1px solid var(--ink-line, rgba(0,0,0,0.12));
  border-radius: 999px;
  background: transparent;
  font-size: 12px;
  color: var(--ink-2);
  cursor: pointer;
}
.compose-action-chip[disabled] {
  opacity: 0.4;
  cursor: not-allowed;
}
.compose-action-chip.is-active {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}

.compose-tagger { margin-bottom: 16px; position: relative; }
.compose-tagger-head { margin-bottom: 6px; }
.compose-tagger-pills {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  padding: 8px 10px;
  border: 1px solid var(--ink-line, rgba(0,0,0,0.12));
  border-radius: 8px;
  min-height: 40px;
}
.compose-tagger-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: var(--ivory-2);
  border-radius: 999px;
  padding: 4px 10px;
  font-size: 12px;
}
.compose-tagger-pill button {
  background: none;
  border: 0;
  color: var(--ink-3);
  cursor: pointer;
  font-size: 14px;
  padding: 0;
}
.compose-tagger-input {
  flex: 1;
  min-width: 160px;
  border: 0;
  outline: none;
  background: transparent;
  font-size: var(--fs-input);
  padding: 4px 0;
}

.compose-suggest {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 50;
  margin-top: 4px;
  background: var(--paper);
  border: 1px solid var(--ink-line, rgba(0,0,0,0.12));
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
  max-height: 280px;
  overflow-y: auto;
}
.compose-suggest-row {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 100%;
  padding: 8px 12px;
  background: transparent;
  border: 0;
  text-align: left;
  cursor: pointer;
}
.compose-suggest-row:hover { background: var(--ivory-2); }
.compose-suggest-path { font-size: 12px; color: var(--ink-3); }
.compose-suggest-name { font-size: 13px; color: var(--ink); }

/* ── RealtyX composer bottom-sheet (mobile) ──────────────────────────
   Gates on `(hover:none) and (pointer:coarse)` instead of a width
   media query — pointer type predicts keyboard + safe-area behaviour
   (tablets in landscape stay sheet-style; small desktop windows do
   not). The reactive `isMobile` Alpine state in public/js/
   compose-sheet.js mirrors the same media query so x-trap.noscroll
   flips live when an iPad rotates across the breakpoint or a
   desktop window resizes below the threshold.

   Backing JS: composeForm() factory in public/js/compose-sheet.js
   ([[brief_realtyx_compose_sheet]]) — handles iOS keyboard offset
   via `--kbd-offset` on the .compose-modal element. */

@media (hover:none) and (pointer:coarse) {
    /* Strip page-shell padding so the sheet runs edge-to-edge. */
    .compose-page {
        padding: 0;
        min-height: 100dvh;
        align-items: stretch;
    }

    /* Full-bleed bottom-sheet. position: fixed + inset: 0 makes the
       modal physically cover the viewport — this is the body-lock
       REPLACEMENT, paired with .compose-form's overscroll-behavior:
       contain below. The 16px top corners + box-shadow keep the
       visual bottom-sheet vocabulary used by ai-search-sheet. */
    .compose-modal {
        max-width: 100%;
        max-height: 100dvh;
        border-radius: 16px 16px 0 0;
        border-bottom: 0;
        box-shadow: 0 -8px 40px -8px rgba(20, 18, 16, 0.3);
        position: fixed;
        inset: 0;
        display: flex;
        flex-direction: column;
        overflow: hidden;
        z-index: 50;
    }

    /* Header is NOT sticky — only the footer pins. Push below the
       Dynamic Island via `max(14px, var(--inset-top))`. */
    .compose-modal-head {
        position: static;
        padding: max(14px, var(--inset-top)) 16px 14px;
        min-height: 56px;
    }
    .compose-modal-close {
        width: 44px;
        height: 44px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        font-size: 24px;
        margin: -8px;
    }

    /* Type-chip strip scrolls horizontally — wrap+jump-row on phones
       reads as jank during fast taps. Hidden scrollbar (Firefox and
       WebKit). */
    .compose-typebar {
        padding: 10px 12px;
        gap: 8px;
        overflow-x: auto;
        flex-wrap: nowrap;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
    }
    .compose-typebar::-webkit-scrollbar { display: none; }
    /* 44px is the rubric D3 hit-area floor for THIS sheet, deliberately
       discrete (not clamp()) per the brief. The site-wide `--tap` token
       is 48px (see tokens.css); inside the compose sheet we trade 4px
       for chip-row density on small phones. If a future refactor wants
       to align everything on --tap, lift to var(--tap) — the change is
       a one-line token edit because every min-height in this block
       reads the same literal. */
    .compose-type-chip {
        min-height: 44px;
        padding: 10px 14px;
        font-size: 14px;
        flex-shrink: 0;
    }

    /* The form is the ONLY internal scroller. overscroll-behavior:
       contain stops rubber-band drag from leaking to the parent on
       iOS Safari + Android Chrome (the second half of the body-lock
       replacement, paired with .compose-modal position:fixed above). */
    .compose-form {
        padding: 14px 16px 0;
        overflow-y: auto;
        flex: 1 1 auto;
        overscroll-behavior: contain;
        -webkit-overflow-scrolling: touch;
    }

    /* Compound selectors raise specificity above bare .form-input so
       a future source-order shuffle cannot silently re-introduce iOS
       focus-zoom on these fields. The 16px floor is already site-
       wide via the [[fs-input-migration]]; this is a hardening pin. */
    .form-input.compose-input-title,
    .form-input.compose-input-body,
    .compose-tagger-input {
        font-size: var(--fs-input);
    }

    .compose-action-chip {
        min-height: 44px;
        padding: 10px 14px;
        font-size: 13px;
    }

    /* Tag-pill: the visible pill stays compact but the wrapping
       hit-area meets the 44x44 floor — iOS touch-slop is NOT relied
       upon. Negative margin pulls the hit-area back over the pill so
       layout doesn't shift. */
    .compose-tagger-pill {
        min-height: 44px;
        display: inline-flex;
        align-items: center;
    }
    .compose-tagger-pill button {
        min-width: 44px;
        min-height: 44px;
        padding: 4px 8px;
        margin: -8px -4px;
    }

    /* Sticky bottom action bar — pins Post + visible-at chip above
       the safe-area AND tracks the iOS keyboard via the element-
       scoped `--kbd-offset` that public/js/compose-sheet.js writes
       to the .compose-modal $el on visualViewport resize. Default
       0px so Android (no JS handler — UA-gated) falls through to
       just safe-area padding. */
    .compose-footer {
        position: sticky;
        bottom: 0;
        background: var(--paper);
        margin: 0 -16px;
        padding: 12px 16px calc(12px + var(--inset-bottom) + var(--kbd-offset, 0px));
        border-top: 1px solid var(--ink-line, rgba(0,0,0,0.08));
    }
    .compose-footer-buttons .btn {
        min-height: 44px;
    }
}

.compose-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-top: 1px solid var(--ink-line, rgba(0,0,0,0.08));
  padding-top: 16px;
  flex-wrap: wrap;
  gap: 12px;
}
.compose-visible-at { font-size: 12px; color: var(--ink-3); }
.compose-footer-buttons { display: flex; gap: 8px; }

/* Sprint 2 — Save (bookmark) button. Filled icon when already saved. */
.save-item-btn { display: inline-flex; align-items: center; }
.save-item-btn.is-saved { color: var(--saffron, #d68a00); }
.save-item-btn.is-saved svg { color: var(--saffron, #d68a00); }

/* D10 — .realtyx-intent-strip / .realtyx-intent-label / .realtyx-intent-chip
   deleted 2026-05-29: defined in CSS but zero markup references in any
   view (verified via grep). Were drafted for a Sprint-2 RealtyX guest
   page that didn't ship; orphan rules increase file size + cognitive
   load on every CSS edit without adding rendered value. */

/* Sprint 2 — feed item action row. Used by listing / event / post cards. */
.feed-item-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 12px;
  flex-wrap: wrap;
}
.feed-item-actions--inline {
  margin-top: 0;
  padding: 0 16px 12px;
  justify-content: flex-end;
}
/* Split action row — pushes a trailing button group (e.g. listing card
   share + save) to the right while the primary CTAs (Enquire / Contact)
   stay left. margin-left:auto on the group claims the free space in the
   flex row. On wrap it lands right-aligned on its own line. */
.feed-item-actions-end {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
}

/* Sprint 2 — page-global image lightbox. Mounted once in layouts/app. */
.image-lightbox {
  position: fixed;
  inset: 0;
  z-index: 10000;
  background: rgba(0, 0, 0, 0.88);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 32px;
}
.image-lightbox-img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border-radius: 4px;
  box-shadow: 0 16px 64px rgba(0, 0, 0, 0.6);
}
.image-lightbox-close {
  position: absolute;
  /* Notched-iPhone safe-area: dynamic island sits ~47-59px from top
     in portrait, right-notch rail intrudes in landscape. max() floor
     preserves the 16/24px baseline on non-notched devices. The shell
     padding (.image-lightbox) intentionally stays at 32px — see
     [[safe-area-sweep]] scope_out: shrinking the photo to add
     bottom safe-area inside a black backdrop is the wrong trade. */
  top: max(16px, var(--inset-top));
  right: max(24px, var(--inset-right));
  background: rgba(255, 255, 255, 0.1);
  color: #fff;
  border: 0;
  border-radius: 999px;
  width: 40px;
  height: 40px;
  font-size: 24px;
  line-height: 1;
  cursor: pointer;
}
.image-lightbox-close:hover { background: rgba(255, 255, 255, 0.2); }

/* Phase 6 — unified rocket Share button. Replaces .share-whatsapp.
   Compact icon-only variant fits the feed action row before Save.
   The native Web Share API takes priority; the fallback popover
   below renders on browsers without navigator.share (e.g. desktop
   Firefox, older Chrome). */
.share-rocket-wrap {
  position: relative;
  display: inline-block;
}
.share-rocket {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.share-rocket svg {
  color: var(--saffron-deep, #b04a1a);
  transition: transform 0.15s ease;
}
.share-rocket:hover svg {
  transform: translate(1px, -1px) rotate(-8deg);
  color: var(--saffron, #c8541f);
}
.share-rocket--compact { padding-left: 8px; padding-right: 8px; }

/* Fallback popover — anchors below the rocket button. */
.share-rocket-menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 50;
  min-width: 168px;
  padding: 4px;
  background: var(--paper);
  border: 1px solid var(--ink-line, rgba(0,0,0,0.10));
  border-radius: 8px;
  box-shadow: 0 4px 14px rgba(0,0,0,0.08);
  display: flex;
  flex-direction: column;
  gap: 2px;
  /* Bound the popover by viewport - inset rails - 100px navbar+gap
     so a long share-channel list never falls under the home indicator
     or dynamic island on short notched viewports ([[safe-area-sweep]]). */
  max-height: calc(100vh - var(--inset-top) - var(--inset-bottom) - 100px);
  overflow-y: auto;
}
.share-rocket-menu-item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 7px 10px;
  font-size: 13px;
  font-family: inherit;
  color: var(--ink-2);
  background: transparent;
  border: 0;
  border-radius: 5px;
  text-align: left;
  cursor: pointer;
}
.share-rocket-menu-item:hover {
  background: var(--ivory-2);
  color: var(--ink);
}
.share-rocket-menu-item svg {
  flex: 0 0 14px;
  opacity: 0.8;
}

/* "Link copied" toast — anchors near the trigger so the user sees
   the feedback adjacent to the button they clicked. */
.share-rocket-toast {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 60;
  padding: 6px 10px;
  font-size: 11px;
  background: var(--ink);
  color: var(--paper);
  border-radius: 6px;
  pointer-events: none;
  white-space: nowrap;
}

/* Sprint 2 — listing photo grid. Renders 1-3 photos for feed cards. */
.listing-photo-grid {
  display: grid;
  gap: 4px;
  margin: 12px 0;
  border-radius: 8px;
  overflow: hidden;
  aspect-ratio: 16 / 10;
}
.listing-photo-grid--single { grid-template-columns: 1fr; }
.listing-photo-grid--two { grid-template-columns: 1fr 1fr; }
.listing-photo-grid--triple {
  grid-template-columns: 2fr 1fr;
  grid-template-rows: 1fr 1fr;
}
.listing-photo-grid--triple .listing-photo--hero { grid-row: 1 / span 2; }
.listing-photo {
  position: relative;
  display: block;
  overflow: hidden;
  background: var(--ivory-2);
}
.listing-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.4s ease;
}
.listing-photo:hover img { transform: scale(1.03); }
.listing-photo-more {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.45);
  color: #fff;
  font-weight: 600;
  font-size: 13px;
  letter-spacing: 0.02em;
}

/* Sprint 2 — city selector dropdown in the global nav. */
.city-selector {
  position: relative;
  display: inline-block;
  margin-right: 8px;
}
.city-selector-button {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  background: transparent;
  border: 1px solid var(--ink-line, rgba(0,0,0,0.12));
  border-radius: 999px;
  font-size: 12px;
  color: var(--ink-2);
  cursor: pointer;
}
.city-selector-button:hover { background: var(--ivory-2); }
.city-selector-chevron {
  color: var(--ink-3, rgba(0,0,0,0.5));
  flex: none;
  transition: transform 0.15s ease;
}
.city-selector-chevron.is-open { transform: rotate(180deg); }
.city-selector-menu {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  z-index: 200;
  min-width: 200px;
  max-height: 360px;
  overflow-y: auto;
  background: var(--paper);
  border: 1px solid var(--ink-line, rgba(0,0,0,0.12));
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.08);
  padding: 4px;
}
/* Mobile reflow — sibling fix to .notif-bell-menu @ <=560px.
   Same root cause (right:0 anchored to a relatively-positioned wrapper
   in the navbar), same fix (viewport-anchored fixed sheet). Shipping
   both in one commit keeps the two adjacent nav dropdowns visually
   consistent on phones. See the comment block above .notif-bell-menu
   mobile rule for the structural reasoning. */
@media (max-width: 560px) {
  .city-selector-menu {
    position: fixed;
    top: calc(var(--inset-top) + 56px + 4px);
    left: 8px;
    right: 8px;
    min-width: 0;
    width: auto;
    max-height: calc(100vh - var(--inset-top) - var(--inset-bottom) - 64px - var(--bottom-nav-clearance-12, 76px));
  }
}
.city-selector-option {
  display: block;
  width: 100%;
  text-align: left;
  padding: 8px 12px;
  background: transparent;
  border: 0;
  border-radius: 6px;
  font-size: 13px;
  color: var(--ink);
  cursor: pointer;
}
.city-selector-option:hover { background: var(--ivory-2); }
.city-selector-option.is-current { font-weight: 600; }
.city-selector-search {
  display: block;
  width: calc(100% - 8px);
  margin: 4px;
  padding: 6px 10px;
  font-size: 13px;
  background: var(--ivory-2);
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--ink);
  font-family: inherit;
}
.city-selector-search:focus { outline: none; border-color: var(--ink-3); background: var(--paper); }
.city-selector-results { border-bottom: 1px dashed var(--line); padding-bottom: 4px; margin-bottom: 4px; }
.city-selector-empty { padding: 10px 12px; color: var(--ink-4); }
[x-cloak] { display: none !important; }

/* RealtyX — live-feed brand link. The platform's main feature, so the
   nav entrypoint reads as a distinct broadcast-style affordance, not
   plain text. Two coordinated animations carry the "live" signal:
     • The whole pill carries a soft pulsing red glow (box-shadow
       ripple) so the affordance reads from across the page even
       when the X isn't yet caught by the eye.
     • The X is a red letter with the classic opacity blink — the
       discrete pulse cue that says "live".
   "Realty" + "X" render as ONE tight word — the anchor is inline-flex
   with gap:0, both spans are zero-margin, no whitespace between them
   in the markup. Respects prefers-reduced-motion. */
.navtab--realtyx {
  display: inline-flex;
  align-items: baseline;
  gap: 0;
  font-weight: 700;
  font-size: 15px;
  letter-spacing: -0.005em;
  margin-right: 6px;
  padding: 7px 14px;
  border-radius: 599px;
  background: color-mix(in oklab, #d9342b 10%, transparent);
  border: 1px solid color-mix(in oklab, #d9342b 32%, transparent);
  transition: background 0.18s ease, border-color 0.18s ease, transform 0.18s ease;
  /* Continuous soft red glow expands and fades every 2s. The breath
     catches peripheral vision; the X blink inside is the discrete
     "live now" beat. */
  /* animation: realtyx-pill-glow 2s ease-in-out infinite; */
}
/* Hide on phone — earlier @media rule at line ~85 was overridden
   by the base display:inline-flex above (later source wins at equal
   specificity). Restating here AFTER the base rule fixes the cascade.
   Guests still reach RealtyX via /realtyx; authed users via bottom-nav.
   800px to match the navbar collapse (was 700, which left RealtyX showing
   in the 701-800 overflow band alongside the lang pill + List CTA). */
@media (max-width: 800px) {
  .navtab--realtyx { display: none; }
}
.navtab--realtyx:hover {
  background: color-mix(in oklab, #d9342b 18%, transparent);
  border-color: color-mix(in oklab, #d9342b 52%, transparent);
  transform: translateY(-0.5px);
}
@keyframes realtyx-pill-glow {
  0%, 100% { box-shadow: 0 0 0 0 rgba(217, 52, 43, 0); }
  50%      { box-shadow: 0 0 14px 2px rgba(217, 52, 43, 0.42); }
}
.navtab-realtyx-lead {
  /* "Realty" portion — zero margins on both sides so the X butts
     directly against the y. */
  margin: 0;
  padding: 0;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.navtab-realtyx-x,
.mbn-realtyx-x {
  /* X — red letter with subtle outer glow + opacity blink. The blink
     is the classic broadcast-LIVE cue; the text-shadow keeps the X
     legible/highlighted between blinks so the resting state isn't a
     plain red letter. */
  display: inline-block;
  margin: 0 0 0 0.02em;
  padding: 0;
  color: #d9342b;
  font-weight: 800;
  font-size: 1.05em;
  letter-spacing: -0.04em;
  text-shadow: 0 0 8px rgba(217, 52, 43, 0.55);
  animation: realtyx-blink 1.4s ease-in-out infinite;
}
@keyframes realtyx-blink {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.32; }
}
@media (prefers-reduced-motion: reduce) {
  .navtab--realtyx { animation: none; }
  .navtab-realtyx-x,
  .mbn-realtyx-x {
    animation: none;
    opacity: 1;
  }
}

/* ── Matches-head sort dropdown + h1 subscript ──────────────── */
.matches-main-head { margin-bottom: 14px; }
.matches-h1-sub {
  font-size: 13px;
  color: var(--ink-4);
  letter-spacing: 0.04em;
  font-weight: 500;
  font-family: var(--mono);
  margin-left: 8px;
}
.matches-sort {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-wrap: wrap;
  margin-top: 8px;
}
.matches-sort-label {
  font-size: 10px;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--ink-4);
  padding-right: 8px;
}
.matches-sort-opt {
  padding: 6px 12px;
  font-size: 12px;
  border-radius: 6px;
  color: var(--ink-2);
  text-decoration: none;
  border: 1px solid transparent;
}
.matches-sort-opt:hover { color: var(--ink); }
.matches-sort-opt--active {
  color: var(--ink);
  font-weight: 600;
  border-bottom: 2px solid var(--saffron);
  border-radius: 0;
  padding-bottom: 4px;
}
/* Lifecycle state tabs — Active / Closed selector above the filter
   pills. Mirrors the matches-sort-opt accent on active. */
.matches-state-tabs {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid var(--line-2);
  margin: 12px 0 14px;
}
.matches-state-tab {
  padding: 8px 14px;
  font-size: 14px;
  color: var(--ink-3);
  text-decoration: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.matches-state-tab:hover { color: var(--ink); }
.matches-state-tab--active {
  color: var(--ink);
  font-weight: 600;
  border-bottom-color: var(--saffron);
}
.matches-state-tab .mono { color: var(--ink-4); }
.matches-state-tab--active .mono { color: var(--saffron-deep, #d8a35e); }

/* DESKTOP DEFAULT — desktop view of /matches is unchanged from before
   the Intros PR. The .matches-tabs-row wrapper goes display:contents
   so its children (.matches-state-tabs + .matches-intros-btn) float
   to the .crm-filter-quick parent exactly as if the wrapper didn't
   exist. The Intros pill itself is hidden because desktop already has
   the top-nav Intros badge; adding a second saffron entry-point would
   crowd the chrome. The pill comes back ONLY ≤800 px (mobile lacks
   the top-nav text labels). */
.matches-tabs-row { display: contents; }
.matches-intros-btn { display: none; }

/* MOBILE — reassert the wrapper as a flex row and bring the pill
   back. crm-filter-quick gains flex-wrap so matches-tabs-row can
   take the full first row (state-tabs left, Intros right) while the
   pill scroll-lane wraps to row 2. */
@media (max-width: 800px) {
  .crm-filter-quick { flex-wrap: wrap; }
  .matches-tabs-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    flex: 1 1 100%;       /* claim the full first row */
  }
  .matches-tabs-row .matches-state-tabs { margin-top: 0; margin-bottom: 0; }

  /* Intros button — dark/ink filled pill so it stands out as a
     primary destination, matching the prominence of the selected
     "Active" tab on the segmented control. Paper text + saffron
     count badge on the dark fill (the badge inverts vs the
     in-tab-frame ivory variants elsewhere on the strip). */
  .matches-intros-btn {
    position: relative;
    min-height: var(--tap);
    min-width: var(--tap);
    display: inline-flex; align-items: center; gap: 6px;
    padding: 4px 14px;
    margin-block: -6px;
    background: var(--ink);
    border: 1px solid var(--ink);
    border-radius: 999px;
    font: 600 13px/1 var(--sans);
    color: var(--paper);
    text-decoration: none;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
    white-space: nowrap;
    transition: opacity 120ms ease;
    flex: 0 0 auto;
  }
  .matches-intros-btn:hover { opacity: 0.92; }
  .matches-intros-btn:focus-visible {
    outline: 2px solid var(--saffron, #c8541f);
    outline-offset: 2px;
  }
  /* Separator + count badge on the dark pill — the separator
     becomes paper-with-opacity (vs --ink-3 elsewhere) and the
     count badge stays saffron so the urgency cue carries. */
  .matches-intros-btn .matches-intros-btn-sep {
    color: color-mix(in oklab, var(--paper) 60%, transparent);
  }
  .matches-intros-btn .matches-intros-btn-badge {
    background: var(--saffron, #c8541f);
    color: var(--paper);
  }
  .matches-intros-btn .matches-intros-btn-newdot { background: var(--saffron, #c8541f); }
}
.matches-intros-btn-sep { color: var(--ink-3); font-weight: 400; }
.matches-intros-btn-badge {
  background: var(--saffron, #c8541f);
  color: var(--paper);
  font: 600 10px/1 var(--sans);
  padding: 2px 6px;
  border-radius: 999px;
}

/* ── Digest banner (dark, gradient, the prototype's version) ── */
.digest-banner {
  display: grid;
  grid-template-columns: 48px 1fr auto;
  gap: 14px;
  align-items: center;
  padding: 16px 20px;
  border-radius: 12px;
  background:
    radial-gradient(circle at 90% -20%, color-mix(in oklab, var(--saffron) 30%, transparent) 0%, transparent 60%),
    var(--ink);
  color: var(--paper);
  position: relative;
  overflow: hidden;
}
.digest-banner-icon {
  width: 44px;
  height: 44px;
  border-radius: 10px;
  background: color-mix(in oklab, var(--saffron) 90%, var(--ink));
  color: var(--ink);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.digest-banner-eyebrow {
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: color-mix(in oklab, var(--saffron) 70%, transparent);
  margin-bottom: 4px;
}
.digest-banner-title {
  font-family: var(--serif);
  font-size: 20px;
  line-height: 1.3;
  color: var(--paper);
}
.digest-banner-sub {
  font-size: 11px;
  color: color-mix(in oklab, var(--paper) 60%, transparent);
  letter-spacing: 0.02em;
  margin-top: 4px;
}
.digest-banner-actions { display: flex; gap: 8px; flex-shrink: 0; }
.digest-banner-actions .btn-accent { background: var(--saffron); color: var(--ink); }
@media (max-width: 700px) {
  .digest-banner { grid-template-columns: 40px 1fr; gap: 10px; padding: 12px 14px; }
  .digest-banner-icon { width: 40px; height: 40px; }
  .digest-banner-title { font-size: 17px; }
  .digest-banner-actions { grid-column: 1 / -1; }
}

/* ── Hottest buyer segments rail card ──────────────────────── */
.rail-segment-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.rail-segment {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding-bottom: 6px;
  border-bottom: 1px dashed var(--line);
}
.rail-segment:last-child { border-bottom: none; padding-bottom: 0; }
.rail-segment-label { font-size: 13px; color: var(--ink); font-weight: 500; }
.rail-segment-count {
  font-size: 10px;
  color: var(--saffron-deep);
  letter-spacing: 0.02em;
  font-weight: 600;
}

/* ── Top match-makers rail card ─────────────────────────────── */
.rail-matchmakers-head {
  display: grid;
  grid-template-columns: 1fr 40px 50px;
  gap: 8px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--line);
  font-size: 9px;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.rail-mm-col { text-align: right; }
.rail-matchmakers-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
}
.rail-matchmaker {
  display: grid;
  grid-template-columns: 24px 1fr 40px 50px;
  align-items: center;
  gap: 8px;
  padding: 6px 0;
  border-bottom: 1px dashed var(--line);
}
.rail-matchmaker:last-child { border-bottom: none; }
.rail-mm-rank { font-size: 11px; color: var(--ink-3); text-align: center; }
.rail-mm-name {
  font-size: 12px;
  color: var(--ink);
  font-weight: 500;
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rail-mm-name:hover { text-decoration: underline; }
.rail-mm-closed { color: var(--green); font-weight: 600; }

/* ── Sub-nav (Matches · Buyers · Listings) ──────────────────────── */
.subnav {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 6px;
  margin: 0 0 20px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 999px;
  width: fit-content;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.04em;
}
.subnav-tab {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 8px 16px;
  border-radius: 999px;
  color: var(--ink-3);
  text-decoration: none;
  font-weight: 600;
  text-transform: uppercase;
  transition: background 0.15s ease, color 0.15s ease;
}
.subnav-tab:hover {
  color: var(--ink);
  background: color-mix(in oklab, var(--ink) 6%, transparent);
}
.subnav-tab--active {
  background: var(--ink);
  color: var(--paper);
}
.subnav-tab--active:hover {
  background: var(--ink);
  color: var(--paper);
}
.subnav-tab-plus {
  color: var(--saffron);
  font-weight: 700;
}
.subnav-tab--active .subnav-tab-plus {
  color: var(--saffron);
}

/* ── Buyers row-actions dropdown (Edit / Archive / Mark closed) ───
   Replaces a previous all-inline-style block that looked unstyled on
   the dark theme. Owner-only `<details>` widget — trigger is the ⋯
   button, menu reveals below + right-aligned. */
.buyer-actions {
  position: relative;
  display: inline-block;
}
.buyer-actions-trigger {
  cursor: pointer;
  padding: 2px 8px;
  border-radius: 4px;
  list-style: none;
  color: var(--ink-3);
  user-select: none;
  font-size: 18px;
  line-height: 1;
}
.buyer-actions-trigger::-webkit-details-marker { display: none; }
.buyer-actions-trigger:hover { background: var(--ivory-2); color: var(--ink); }
.buyer-actions[open] .buyer-actions-trigger { background: var(--ivory-2); color: var(--ink); }

.buyer-actions-menu {
  position: absolute;
  right: 0;
  top: calc(100% + 4px);
  z-index: 10;
  min-width: 180px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 4px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.10);
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.buyer-actions-form { margin: 0; }
.buyer-actions-item {
  display: block;
  width: 100%;
  padding: 8px 12px;
  background: transparent;
  border: 0;
  border-radius: 5px;
  text-align: left;
  font-family: inherit;
  font-size: 13px;
  color: var(--ink-2);
  cursor: pointer;
  text-decoration: none;
  transition: background 0.12s, color 0.12s;
}
.buyer-actions-item:hover { background: var(--ivory-2); color: var(--ink); }
.buyer-actions-item--danger { color: var(--red); }
.buyer-actions-item--danger:hover { background: var(--red-soft); color: var(--red); }

/* ── Directory pages (buyers + listings) ─────────────────────────── */
.dir-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: 20px;
  flex-wrap: wrap;
}
.dir-head .page-h1 { margin: 6px 0 4px; }
.dir-head .page-sub {
  color: var(--ink-3);
  font-size: 14px;
  max-width: 540px;
  line-height: 1.5;
}
.dir-head-cta { flex-shrink: 0; }

.dir-filters {
  display: grid;
  grid-template-columns: 1.6fr 1fr 1fr 1fr auto auto;
  gap: 8px;
  margin-bottom: 14px;
  align-items: center;
}
.dir-filters .form-input {
  font-size: var(--fs-input);
  padding: 10px 12px;
}
@media (max-width: 900px) {
  .dir-filters { grid-template-columns: 1fr 1fr; }
  .dir-filters .btn,
  .dir-filters button { grid-column: span 2; }
}

.dir-sort {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 14px;
  font-size: 12px;
}
/* "My listings" page-eyebrow that replaces the dropped Mine|Global
   toggle. Renders as a slightly-larger mono label sitting on the
   left of the quick-filter strip. */
.dir-sort-label {
  font-size: 13px;
  color: var(--ink);
  font-weight: 600;
}
/* Scope the listings dashboard's crm-filter-quick to flex so the
   children participate in a real flex row. The shared base rule
   uses display:contents (hoists children up to the parent for the
   mobile-shared filter-quick chassis), which makes margin-left:auto
   on .dir-srp-link inert. Without this override the Browse-all link
   wraps to a new line flush-left on desktop instead of right-aligning
   next to "My listings". Mobile is unaffected — the @800px media
   already promotes the wrapper to flex. */
.dir-filters-wrap .crm-filter-quick {
  display: flex;
  align-items: center;
  gap: 12px;
}
/* "Browse all properties →" link replacing the Global tab. Routes
   to the canonical public SRP. Styled as a quiet secondary action so
   it doesn't compete with the ⚙ Filters button for primary attention.
   On mobile the link wraps to its own row to keep "My listings" +
   Filters readable on 360 px. */
.dir-srp-link {
  margin-left: auto;
  padding: 8px 12px;
  font-size: 13px;
  white-space: nowrap;
  color: var(--ink-2);
}
.dir-srp-link:hover {
  color: var(--ink);
  background: var(--ivory-2, #efe8db);
}
@media (max-width: 800px) {
  .dir-srp-link {
    margin-left: 0;
    order: 3;
    flex: 1 1 100%;
    text-align: center;
    border: 1px solid var(--line);
    border-radius: 999px;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
}

.dir-table {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 12px;
  /* overflow:visible (not :hidden) so the .buyer-actions kebab dropdown
     can escape the table boundary — the menu uses position:absolute and
     would otherwise get clipped at the table edge, especially on the
     last row where the dropdown opens downward into nothing. Corner
     clipping for row hover backgrounds moves onto the first/last row
     selectors below. */
  overflow: visible;
}
.dir-row {
  display: grid;
  gap: 12px;
  padding: 14px 16px;
  align-items: center;
  border-bottom: 1px solid var(--line);
  color: var(--ink);
  text-decoration: none;
  transition: background 0.1s ease;
}
.dir-row:first-child {
  border-top-left-radius: 11px;
  border-top-right-radius: 11px;
}
.dir-row:last-child {
  border-bottom: none;
  border-bottom-left-radius: 11px;
  border-bottom-right-radius: 11px;
}
.dir-row--link:hover { background: color-mix(in oklab, var(--saffron) 6%, transparent); }
.dir-row--head {
  background: color-mix(in oklab, var(--ink) 4%, transparent);
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
  font-weight: 600;
}
.dir-table--buyers .dir-row {
  grid-template-columns: 40px 2.4fr 1.2fr 1.4fr 1.1fr 1.4fr 0.7fr;
}
.dir-table--listings .dir-row {
  grid-template-columns: 40px 2.6fr 1.2fr 1.4fr 1.3fr 0.8fr 1.2fr;
}
@media (max-width: 900px) {
  .dir-table--buyers .dir-row,
  .dir-table--listings .dir-row {
    grid-template-columns: 32px 1fr 1fr;
    grid-auto-flow: dense;
  }
  .dir-row--head { display: none; }
}

.dir-rank {
  font-size: 11px;
  color: var(--ink-3);
  text-align: center;
}
.dir-ident {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}
.dir-initials {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 999px;
  background: color-mix(in oklab, var(--saffron) 20%, var(--paper));
  color: var(--ink);
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 600;
  flex-shrink: 0;
}
.dir-ident-body { min-width: 0; }
.dir-ident-title {
  font-weight: 500;
  font-size: 14px;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.dir-ident-sub {
  font-size: 11px;
  color: var(--ink-3);
  margin-top: 2px;
}

.dir-budget-label,
.dir-price {
  font-weight: 600;
  font-size: 14px;
  color: var(--ink);
}
.dir-budget-tx {
  font-size: 10px;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-top: 2px;
}

.dir-city-name {
  display: block;
  font-size: 13px;
  color: var(--ink);
}
.dir-city-urg {
  display: block;
  font-size: 10px;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-top: 2px;
}

/* B10 (2026-05-18) — locality sub-line under city name on the dashboard
   row. Surfaces the buyer's locality preferences from the presenter's
   locality_names array; truncated to two entries to keep the row clean. */
.dir-city-loc {
  display: block;
  font-size: 11px;
  color: var(--ink-2);
  margin-top: 2px;
}

/* Dashboard broker column "missing" placeholder when the join row
   has no broker (legacy data hygiene case). */
.dir-broker--missing {
  color: var(--ink-3);
}

.dir-config {
  font-size: 12px;
  color: var(--ink-2);
}

.dir-broker {
  display: inline-flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  color: var(--ink);
  text-decoration: none;
}
.dir-broker:hover .dir-broker-name { text-decoration: underline; }
.dir-broker-name {
  font-size: 13px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.dir-broker-trust {
  font-size: 10px;
  color: var(--ink-3);
}

.dir-count {
  font-size: 14px;
  font-weight: 600;
  text-align: right;
  color: var(--ink);
}

.dir-source-chip {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.dir-source-chip--cache {
  background: color-mix(in oklab, var(--ink) 8%, transparent);
  color: var(--ink-2);
}
.dir-source-chip--local {
  background: color-mix(in oklab, var(--saffron) 20%, transparent);
  color: var(--ink);
}

.directory-pagination {
  margin-top: 18px;
  display: flex;
  justify-content: center;
}

/* ── Address hero (locality lead field on Compose) ──────────────── */
.address-hero {
  position: relative;
  background: color-mix(in oklab, var(--saffron) 8%, var(--paper));
  border: 1px solid color-mix(in oklab, var(--saffron) 50%, var(--line));
  border-radius: 12px;
  padding: 18px 20px 14px;
  margin: 6px 0 18px;
  box-shadow: 0 2px 12px color-mix(in oklab, var(--saffron) 12%, transparent);
}
.address-hero-eyebrow {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: color-mix(in oklab, var(--saffron) 70%, var(--ink));
  margin-bottom: 8px;
}
.address-hero .form-input {
  font-size: 16px;
  padding: 12px 14px;
  border-color: color-mix(in oklab, var(--saffron) 50%, var(--line));
}
.address-hero .form-input:focus {
  border-color: var(--saffron);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--saffron) 24%, transparent);
}

/* Auto-filled triplet sitting under the hero — visually subordinate. */
.address-derived {
  margin-bottom: 12px;
}

/* Read-only display element styled like an input but inert. */
.form-input--readonly {
  display: flex;
  align-items: center;
  background: color-mix(in oklab, var(--ink) 4%, var(--paper));
  color: var(--ink-2);
  font-style: normal;
  min-height: 40px;
  user-select: text;
  cursor: default;
}
.form-input--readonly:empty::before {
  content: '—';
  color: var(--ink-4);
}

/* ── Locality autocomplete (x-locality-autocomplete) ─────────────── */
.ac-locality { position: relative; }
.ac-society { position: relative; }

/* Multi mode — chip rail with inline input. Looks like a single text
   field but contains chips for picked localities. */
.ac-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 8px 10px;
  min-height: 48px;
  cursor: text;
  font-size: 14px;
}
.ac-chips:focus-within {
  border-color: var(--saffron);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--saffron) 24%, transparent);
}
.ac-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 4px 4px 10px;
  background: color-mix(in oklab, var(--saffron) 18%, var(--paper));
  border: 1px solid color-mix(in oklab, var(--saffron) 40%, var(--line));
  border-radius: 999px;
  font-size: 13px;
  color: var(--ink);
  font-weight: 500;
}
.ac-chip-remove {
  width: 22px;
  height: 22px;
  border: 0;
  border-radius: 999px;
  background: color-mix(in oklab, var(--ink) 8%, transparent);
  color: var(--ink-2);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.ac-chip-remove:hover {
  background: color-mix(in oklab, var(--ink) 18%, transparent);
  color: var(--ink);
}
.ac-chips-input {
  flex: 1;
  min-width: 140px;
  border: 0;
  outline: none;
  background: transparent;
  font: inherit;
  color: var(--ink);
  padding: 4px 0;
}
.ac-chips-input::placeholder { color: var(--ink-4); }

/* Inline city-conflict warning shown inside the dropdown panel. */
.ac-conflict {
  padding: 10px 12px;
  font-size: 12px;
  color: color-mix(in oklab, #c64a3a 70%, var(--ink));
  background: color-mix(in oklab, var(--terracotta) 8%, transparent);
  border-radius: 6px;
  margin: 4px;
}

/* ── Listing CRUD — owner action strip + status banners ──────────── */
.listing-status-banner {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 16px;
  border-radius: 10px;
  margin-bottom: 16px;
  font-size: 13px;
  line-height: 1.5;
}
.listing-status-banner--closed {
  background: color-mix(in oklab, var(--ink) 5%, var(--paper));
  border: 1px solid var(--line);
}
.listing-status-badge {
  display: inline-flex;
  padding: 4px 10px;
  border-radius: 999px;
  background: var(--ink);
  color: var(--paper);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  flex-shrink: 0;
}
.listing-status-text { color: var(--ink-2); }

.listing-owner-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 18px;
  padding: 12px 16px;
  background: color-mix(in oklab, var(--saffron) 6%, var(--paper));
  border: 1px solid color-mix(in oklab, var(--saffron) 30%, var(--line));
  border-radius: 10px;
}
.listing-owner-actions-danger {
  margin-left: auto;
  color: color-mix(in oklab, #c64a3a 70%, var(--ink));
}
/* Mobile: shrink labels via per-button suffix spans + tighten
   button chrome so all three (Edit / Mark sold / Withdraw) fit
   in a single row on 360 px. The "listing" / "/ closed" suffixes
   are anchored in the Blade and CSS-hidden here; the verbose
   labels stay on desktop. Min-height stays at 44 px so the row
   meets the tap floor on the per-button hit area. */
@media (max-width: 800px) {
  .listing-owner-actions {
    padding: 8px 10px;
    gap: 6px;
    margin-bottom: 12px;
  }
  .listing-owner-actions .btn {
    padding: 10px 12px;
    font-size: 13px;
    min-height: 44px;
    flex: 1 1 auto;
  }
  .listing-owner-actions-danger {
    margin-left: 0;
  }
  .listing-owner-actions-suffix {
    display: none;
  }
}
.listing-owner-confirm {
  flex: 1 1 100%;
  margin-top: 10px;
  padding: 12px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 8px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.listing-owner-confirm--danger {
  border-color: color-mix(in oklab, #c64a3a 50%, var(--line));
  background: color-mix(in oklab, #c64a3a 4%, var(--paper));
}
.listing-owner-confirm-text {
  font-size: 13px;
  color: var(--ink-2);
  line-height: 1.5;
  margin: 0;
}
.listing-owner-confirm-actions {
  display: flex;
  gap: 8px;
}
.btn-danger {
  background: var(--terracotta);
  color: var(--paper);
  border: 1px solid var(--terracotta);
}
.btn-danger:hover {
  background: color-mix(in oklab, var(--terracotta) 85%, black);
  color: var(--paper);
}

/* Existing photos rail on Edit form (read-only thumbnails). */
.photo-thumbs--existing {
  margin: 0 0 14px;
  padding: 12px;
  background: color-mix(in oklab, var(--ink) 4%, var(--paper));
  border-radius: 10px;
}
.photo-thumbs--existing .photo-thumb {
  border-color: color-mix(in oklab, var(--ink) 10%, var(--line));
}
.photo-thumbs--existing figcaption {
  padding: 6px 8px;
  font-size: 11px;
  color: var(--ink-3);
  border-top: 1px solid var(--line);
}
.ac-dropdown {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  z-index: 50;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: 0 8px 24px color-mix(in oklab, var(--ink) 12%, transparent);
  max-height: 320px;
  overflow-y: auto;
  padding: 4px;
}
.ac-option {
  display: flex;
  flex-direction: column;
  width: 100%;
  text-align: left;
  background: transparent;
  border: 0;
  border-radius: 6px;
  padding: 10px 12px;
  cursor: pointer;
  color: var(--ink);
  transition: background 0.1s;
}
.ac-option:hover,
.ac-option--cursor {
  background: color-mix(in oklab, var(--saffron) 10%, transparent);
}
.ac-option-main {
  font-size: 14px;
  font-weight: 500;
  line-height: 1.3;
}
.ac-option-sub {
  font-size: 11px;
  color: var(--ink-3);
  margin-top: 2px;
  letter-spacing: 0.02em;
}

/* Compose autocomplete v2 — richer society dropdown card.
   Head row: name + status pills (Verified / RERA / Brochure).
   Sub row: builder · locality, city (existing .ac-option-sub).
   Keyfacts row: BHK range · price range · possession · units · new launch.
   Desc row: description_short (truncated, italic).
   Renders only on .ac-option--v2 to leave other ac- usages untouched. */
.ac-option--v2 {
  gap: 3px;
}
.ac-option-head {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.ac-option-keyfacts {
  font-size: 11px;
  color: var(--ink-2);
  margin-top: 1px;
}
.ac-option-desc {
  font-size: 12px;
  color: var(--ink-3);
  font-style: italic;
  line-height: 1.35;
  margin-top: 3px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.ac-option-pill {
  display: inline-flex;
  align-items: center;
  padding: 1px 6px;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.02em;
  border: 1px solid var(--line);
  line-height: 1.3;
}
.ac-option-pill--verified {
  background: #ecfdf5;
  color: #065f46;
  border-color: #6ee7b7;
}
.ac-option-pill--rera {
  background: #eef2ff;
  color: #3730a3;
  border-color: #a5b4fc;
}
.ac-option-pill--cache {
  background: color-mix(in oklab, var(--ink) 5%, var(--paper));
  color: var(--ink-3);
}
.ac-loading,
.ac-empty {
  padding: 12px;
  font-size: 12px;
  color: var(--ink-3);
  text-align: center;
}

/* ── /preview component gallery ───────────────────────────────────────
   Chrome must never compete with the previewed component. Sidebar +
   labels in muted ink; canvas areas in --paper to match real production
   surrounds; minimal vertical rhythm.
─────────────────────────────────────────────────────────────────────── */
.preview-shell {
  display: grid;
  grid-template-columns: 240px minmax(0, 1fr);
  gap: 32px;
  align-items: start;
}
@media (max-width: 800px) {
  .preview-shell { grid-template-columns: 1fr; }
}

.preview-sidebar {
  position: sticky;
  top: 80px;
  border-right: 1px solid var(--line);
  padding-right: 20px;
}
.preview-sidebar-title {
  font-size: 22px;
  font-weight: 600;
  color: var(--ink);
  display: block;
  margin: 4px 0 8px;
  text-decoration: none;
}
.preview-sidebar-sub {
  font-size: 11px;
  color: var(--ink-3);
  line-height: 1.5;
  margin-bottom: 16px;
}
.preview-sidebar-sub code {
  font-family: var(--mono);
  font-size: 10.5px;
  background: var(--ivory-2);
  padding: 1px 5px;
  border-radius: 3px;
}

.preview-nav { display: flex; flex-direction: column; gap: 14px; }
.preview-nav-group { display: flex; flex-direction: column; gap: 4px; }
.preview-nav-heading {
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 2px;
}
.preview-nav-link {
  font-size: 13px;
  color: var(--ink-2);
  text-decoration: none;
  padding: 4px 8px;
  border-radius: 4px;
  border-left: 2px solid transparent;
  margin-left: -2px;
}
.preview-nav-link:hover { color: var(--ink); background: var(--ivory-2); }
.preview-nav-link.is-active {
  color: var(--ink);
  border-left-color: var(--saffron);
  font-weight: 500;
}

.preview-main { min-width: 0; }
.preview-header { margin-bottom: 28px; }

/* Card grid on the index page */
.preview-section { margin-bottom: 36px; }
.preview-section-heading {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 12px;
}
.preview-card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 14px;
}
.preview-card {
  display: block;
  padding: 16px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--paper);
  text-decoration: none;
  color: inherit;
  transition: border-color 0.12s ease, transform 0.12s ease;
}
.preview-card:hover {
  border-color: var(--ink-3);
  transform: translateY(-1px);
}
.preview-card-title { font-size: 16px; font-weight: 500; color: var(--ink); }
.preview-card-desc { font-size: 12px; color: var(--ink-3); margin-top: 4px; line-height: 1.45; }
.preview-card-slug { font-size: 10px; color: var(--ink-3); margin-top: 10px; opacity: 0.7; }

/* Variant grids on individual preview pages */
.preview-block { margin-bottom: 36px; }
.preview-block-heading {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 6px;
}
.preview-block-sub {
  font-size: 12px;
  color: var(--ink-3);
  line-height: 1.55;
  margin-bottom: 14px;
  max-width: 60ch;
}
.preview-block-sub code {
  font-family: var(--mono);
  font-size: 11px;
  background: var(--ivory-2);
  padding: 1px 5px;
  border-radius: 3px;
}

.preview-grid {
  display: grid;
  gap: 12px;
}
.preview-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.preview-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 700px) {
  .preview-grid--2, .preview-grid--3 { grid-template-columns: 1fr; }
}

.preview-cell {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: 6px;
  overflow: hidden;
  background: var(--paper);
}
.preview-cell-label {
  padding: 6px 10px;
  font-size: 10px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-3);
  background: var(--ivory-2);
  border-bottom: 1px solid var(--line);
}
.preview-cell-canvas {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  flex-wrap: wrap;
  gap: 8px;
  padding: 18px;
  min-height: 56px;
}
.preview-cell-canvas--empty { color: var(--ink-3); }
.preview-empty-hint { font-size: 11px; opacity: 0.6; }

/* Variant table for matrix layouts (e.g. button variants × sizes) */
.preview-table {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: 6px;
  overflow: hidden;
  background: var(--paper);
}
.preview-table-row {
  display: grid;
  grid-template-columns: 120px repeat(auto-fit, minmax(160px, 1fr));
  align-items: center;
  border-bottom: 1px solid var(--line);
}
.preview-table-row:last-child { border-bottom: none; }
.preview-table-row--head {
  background: var(--ivory-2);
  font-size: 10px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.preview-table-row--head > span { padding: 8px 16px; }
.preview-table-row > span {
  padding: 14px 16px;
}
.preview-table-row .preview-cell-canvas {
  padding: 0;
  min-height: 0;
}

/* ── Listing-detail preview directions (.pl-*) ─────────────────────────
   Shared markup for A/B/C with direction-specific overrides. Forward-compat:
   when we lock a direction, port these classes verbatim into the production
   listing-detail page CSS — token-driven, no preview-specific assumptions.
─────────────────────────────────────────────────────────────────────── */
.pl-page { font-family: var(--sans, inherit); color: var(--ink); }

/* Breadcrumb */
.pl-breadcrumb {
  margin: 8px 0 14px;
  color: var(--ink-3);
  letter-spacing: 0.02em;
}
.pl-breadcrumb a { color: var(--ink-3); text-decoration: none; }
.pl-breadcrumb a:hover { color: var(--ink); text-decoration: underline; }
.pl-breadcrumb span { color: var(--ink); font-weight: 500; }
.pl-breadcrumb .pl-breadcrumb-sep { color: var(--ink-3); font-weight: 400; margin: 0 4px; }
.pl-breadcrumb--on-overlay { color: var(--paper); margin: 0 0 12px; }
.pl-breadcrumb--on-overlay a, .pl-breadcrumb--on-overlay span { color: var(--paper); }
.pl-breadcrumb--on-overlay .pl-breadcrumb-sep { color: var(--paper); }

/* HERO shells per direction */
.pl-hero { display: grid; gap: 22px; margin-bottom: 32px; align-items: stretch; }
.pl-hero-a { grid-template-columns: minmax(0, 1.6fr) minmax(280px, 1fr); }
.pl-hero-b { grid-template-columns: minmax(0, 1.4fr) minmax(320px, 1fr); }
@media (max-width: 900px) {
  .pl-hero-a, .pl-hero-b { grid-template-columns: 1fr; }
}

/* Photo placeholders (real photos in production) */
.pl-photo-mosaic {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr;
  grid-template-rows: 180px 180px;
  gap: 6px;
  border-radius: 10px;
  overflow: hidden;
}
.pl-photo-mosaic > :first-child { grid-row: 1 / span 2; }
@media (max-width: 700px) {
  /* Mobile: hero full width, secondaries scroll horizontally below.
     Every photo is reachable by scrolling. */
  .pl-photo-mosaic {
    grid-template-columns: 1fr;
    grid-template-rows: 240px;
    grid-auto-rows: 140px;
  }
  .pl-photo-mosaic > :first-child { grid-row: auto; }
}
.pl-photo-placeholder {
  background: linear-gradient(135deg, #d8c7a3, #e4d4b3);
  color: #5c4a2c;
  font-size: 11px;
  font-family: var(--mono);
  text-align: center;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 120px;
  padding: 12px;
  border-radius: 4px;
  letter-spacing: 0.04em;
  /* Containment for <img> children — without overflow:hidden +
     position:relative, portrait photos bleed out of their grid cell
     and overlap neighbouring tiles, and the inner <img> ignores the
     placeholder dimensions (rendered at intrinsic size). */
  position: relative;
  overflow: hidden;
}
.pl-photo-placeholder > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.pl-photo-placeholder--hero { min-height: 360px; font-size: 13px; }
.pl-photo-placeholder--small { min-height: 120px; }
/* Broken-image fallback — `<img onerror>` adds .is-broken to the
   parent placeholder and removes the failing img. The cell stays in
   the layout (no collapsed grid) and shows a subtle "Photo
   unavailable" treatment instead of a torn-image icon. */
.pl-photo-placeholder.is-broken {
  background: linear-gradient(135deg, #efe9da, #f5efde);
  color: #8b7a4d;
  font-style: italic;
}
.pl-photo-placeholder.is-broken::after {
  content: "Photo unavailable";
}

/* Photo tile = clickable button. Reset browser button defaults so
   it visually matches a div (no border, no system background, no
   focus-ring offset that breaks the grid). */
button.pl-photo-tile {
  border: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
}
button.pl-photo-tile:hover img,
button.pl-photo-tile:focus-visible img {
  transform: scale(1.02);
}
button.pl-photo-tile img {
  transition: transform 0.25s ease;
}
button.pl-photo-tile:focus-visible {
  outline: 2px solid var(--saffron-deep, #d8a35e);
  outline-offset: 2px;
}

.pl-photo-placeholder--floorplan { min-height: 200px; background: linear-gradient(135deg, #e8e3d6, #f0ead8); color: #6a5d3f; }
.pl-photo-placeholder--mag { min-height: 240px; }
.pl-photo-more {
  background: linear-gradient(135deg, var(--ink-3), var(--ink-2));
  color: var(--paper);
}
.pl-photo-meta { margin-top: 8px; color: var(--ink-3); }

/* Hero rail (A + B) */
.pl-hero-rail-inner {
  position: sticky;
  top: 80px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 18px;
}
.pl-hero-title {
  font-size: 22px;
  font-weight: 600;
  line-height: 1.25;
  margin: 0 0 4px;
  color: var(--ink);
}
.pl-hero-title--b { font-size: 20px; margin-top: 4px; }
.pl-hero-locality { color: var(--ink-3); margin-bottom: 14px; letter-spacing: 0.02em; }

.pl-hero-price-block { padding: 12px 0; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); margin-bottom: 14px; }
.pl-hero-price-block--b { border-top: none; padding-top: 4px; }
.pl-hero-price { font-size: 28px; font-weight: 600; letter-spacing: -0.01em; color: var(--ink); }
.pl-hero-price-meta { color: var(--ink-3); margin-top: 4px; }
.pl-pill { padding: 1px 6px; border-radius: 3px; font-size: 10px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; }
.pl-pill--neg { background: var(--saffron); color: var(--ink); }

.pl-emi-badge {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  margin-top: 8px;
  padding: 4px 10px;
  background: var(--ivory-2);
  border: 1px solid var(--line);
  border-radius: 6px;
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
}
.pl-emi-badge .small { font-weight: 400; color: var(--ink-3); }

.pl-hero-stats-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-bottom: 14px; }
/* min-width:0 lets each grid track shrink below its content's intrinsic
   width. Without it a long stat value (Status = "Ready To Move") inflates
   its 1fr track past the rail and pushes the whole row — and the rail's
   width:100% CTA buttons — off the right edge on narrow phones. */
.pl-hero-stat { display: flex; flex-direction: column; min-width: 0; padding: 8px; background: var(--ivory-2); border-radius: 6px; }
.pl-hero-stat-value { font-size: 14px; font-weight: 600; overflow-wrap: anywhere; }
.pl-hero-stat-label { font-size: 10px; color: var(--ink-3); margin-top: 2px; letter-spacing: 0.04em; text-transform: uppercase; }

/* Trust pills */
.pl-trust-row { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 14px; }
.pl-trust-pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px; border-radius: 999px; font-size: 11px; font-weight: 500;
  border: 1px solid var(--line); background: var(--paper); color: var(--ink-2);
  text-decoration: none;
}
.pl-trust-pill--rera { background: #1a3d1f; color: #d8e8db; border-color: #1a3d1f; }
.pl-trust-pill--rera:hover { background: #2a5d2f; }
.pl-trust-pill--rera .pl-trust-pill-label { font-family: var(--mono); font-size: 9px; letter-spacing: 0.06em; opacity: 0.8; }
.pl-trust-pill--verified { background: var(--green-soft); color: #355d1f; border-color: #c8d8b0; }
.pl-trust-pill--vastu { background: var(--saffron); color: var(--ink); border-color: var(--saffron); }
.pl-trust-row--c { margin-bottom: 12px; }
.pl-trust-row--c .pl-trust-pill { font-size: 10px; padding: 3px 8px; }

/* Broker card (gated phone, ungated identity) */
.pl-broker-card {
  border-top: 1px solid var(--line);
  padding-top: 14px;
}
.pl-broker-card--compact { padding-top: 10px; }
.pl-broker-head { display: flex; gap: 12px; align-items: center; margin-bottom: 10px; }
.pl-broker-avatar {
  width: 48px; height: 48px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.pl-broker-avatar-initials { font-weight: 600; color: var(--ink); font-size: 16px; }
.pl-broker-id { flex: 1; min-width: 0; }
.pl-broker-name-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.pl-broker-name { font-weight: 600; font-size: 14px; color: var(--ink); }
.pl-broker-firm { color: var(--ink-2); margin-top: 2px; font-size: 12px; }
.pl-broker-meta { color: var(--ink-3); margin-top: 4px; font-size: 10.5px; display: flex; gap: 4px; flex-wrap: wrap; }
.pl-broker-meta .dot { color: var(--ink-3); }

.pl-broker-stats { display: flex; gap: 12px; margin: 10px 0 12px; padding: 8px 10px; background: var(--ivory-2); border-radius: 6px; }
.pl-broker-stat { display: flex; flex-direction: column; align-items: flex-start; flex: 1; }
.pl-broker-stat-value { font-weight: 600; font-size: 13px; }
.pl-broker-stat-label { font-size: 9px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-3); margin-top: 1px; }

.pl-broker-actions { display: flex; flex-direction: column; gap: 8px; }
.pl-broker-actions--b { flex-direction: row; flex-wrap: wrap; margin: 12px 0 14px; }
.pl-broker-actions--b .btn { flex: 1; min-width: 140px; }
.pl-broker-actions--c { display: flex; gap: 8px; }
.pl-broker-action-primary { width: 100%; }
.pl-broker-action-secondary { width: 100%; }
.pl-broker-action-tertiary { width: 100%; }
.pl-broker-foot { color: var(--ink-3); margin-top: 10px; font-size: 10.5px; padding-top: 10px; border-top: 1px dashed var(--line); }

/* Direction B — broker hero (above the price block) */
.pl-hero-rail--b .pl-hero-rail-inner { padding: 16px; }
.pl-broker-hero {
  display: flex; gap: 14px; align-items: center;
  padding-bottom: 14px; border-bottom: 1px solid var(--line); margin-bottom: 12px;
}
.pl-broker-hero-avatar { width: 56px; height: 56px; border-radius: 50%; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.pl-broker-hero-initials { font-weight: 600; font-size: 18px; color: var(--ink); }
.pl-broker-hero-id { flex: 1; min-width: 0; }
.pl-broker-hero-name-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.pl-broker-hero-name { font-weight: 600; font-size: 16px; color: var(--ink); }
.pl-broker-hero-firm { color: var(--ink-2); margin-top: 2px; font-size: 12px; }
.pl-broker-hero-meta { color: var(--ink-3); margin-top: 3px; font-size: 11px; }
.pl-broker-hero-stats { color: var(--ink-2); margin-top: 6px; font-size: 11px; display: flex; gap: 6px; flex-wrap: wrap; }
.pl-broker-hero--c { padding-bottom: 0; border-bottom: none; margin-bottom: 0; }

.pl-mini-map { margin-top: 12px; }
.pl-map-placeholder--mini { min-height: 120px; }
.pl-mini-map-meta { color: var(--ink-3); margin-top: 4px; }

/* Direction C — full-bleed map hero */
.pl-direction-c .pl-page { background: var(--ivory); }
.pl-hero-c { position: relative; margin: -20px -20px 24px; min-height: 540px; }
@media (max-width: 700px) { .pl-hero-c { margin: -20px -16px 16px; min-height: 420px; } }
.pl-map-fullbleed {
  position: relative;
  height: 540px;
  background:
    radial-gradient(circle at 60% 40%, rgba(255,255,255,0.4) 0%, transparent 30%),
    linear-gradient(135deg, #c8d4d8 0%, #b8c4c8 50%, #a8b4b8 100%);
  display: flex; align-items: center; justify-content: center; flex-direction: column;
  border-radius: 0;
}
@media (max-width: 700px) { .pl-map-fullbleed { height: 420px; } }
.pl-map-fullbleed-pin { position: relative; }
.pl-map-pin-pulse {
  position: absolute; inset: -16px; border-radius: 50%;
  background: var(--saffron);
  opacity: 0.4;
  animation: pl-pulse 2s ease-out infinite;
}
@keyframes pl-pulse {
  0% { transform: scale(0.8); opacity: 0.8; }
  100% { transform: scale(2); opacity: 0; }
}
.pl-map-fullbleed-meta {
  position: absolute; bottom: 12px; left: 50%; transform: translateX(-50%);
  background: rgba(0,0,0,0.7); color: var(--paper);
  padding: 6px 12px; border-radius: 4px; text-align: center;
}
.pl-hero-c-overlay {
  position: absolute; top: 24px; right: 24px;
  width: 360px; max-width: calc(100% - 48px);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 18px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.12);
}
@media (max-width: 700px) {
  .pl-hero-c-overlay {
    position: absolute; bottom: 16px; top: auto; right: 16px; left: 16px;
    width: auto;
  }
}
.pl-hero-title--c { font-size: 18px; margin-bottom: 6px; }
.pl-hero-price-block--c { padding: 10px 0; border: none; margin-bottom: 10px; }

/* Map block (mid-page) */
.pl-map-block { margin: 14px 0; border-radius: 10px; overflow: hidden; border: 1px solid var(--line); }
.pl-map-placeholder {
  background: linear-gradient(135deg, #c8d4d8 0%, #b8c4c8 100%);
  min-height: 280px;
  display: flex; align-items: center; justify-content: center; flex-direction: column;
  position: relative;
}
.pl-map-pin svg { color: var(--saffron); }
.pl-map-stub-label {
  margin-top: 12px;
  background: rgba(0,0,0,0.7); color: var(--paper);
  padding: 6px 12px; border-radius: 4px; text-align: center; line-height: 1.4;
}

/* Sections & blocks */
.pl-section { margin: 24px 0; }
.pl-section-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.pl-section-title { font-size: 18px; font-weight: 600; color: var(--ink); margin: 0 0 12px; }
.pl-mag-h2 { font-size: 22px; font-weight: 600; line-height: 1.2; color: var(--ink); margin: 4px 0 12px; }
.pl-mag-eyebrow { color: var(--ink-3); letter-spacing: 0.08em; text-transform: uppercase; margin-bottom: 4px; }
.pl-mag-block { margin: 28px 0; padding: 20px 0; border-top: 1px solid var(--line); }
.pl-mag-block:first-of-type { border-top: none; }
.pl-mag-block--two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 32px; }
@media (max-width: 800px) { .pl-mag-block--two-col { grid-template-columns: 1fr; gap: 16px; } }
.pl-mag-photos { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }
@media (max-width: 700px) { .pl-mag-photos { grid-template-columns: 1fr; } }
.pl-mag-photos-caption { color: var(--ink-3); margin-top: 8px; }

/* Highlights row */
.pl-highlights { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; }
@media (max-width: 700px) { .pl-highlights { grid-template-columns: repeat(2, 1fr); } }
.pl-highlights--mag { padding: 0; }
.pl-h-tile { padding: 14px 16px; background: var(--paper); border: 1px solid var(--line); border-radius: 8px; }
.pl-h-tile-value { font-size: 20px; font-weight: 600; color: var(--ink); line-height: 1.2; }
.pl-h-tile-value .small { font-size: 12px; font-weight: 400; color: var(--ink-3); }
.pl-h-tile-label { font-size: 10px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--ink-3); margin-top: 4px; }

/* Tags */
.pl-tags { display: flex; flex-wrap: wrap; gap: 6px; }
.pl-tag-pill {
  padding: 3px 10px; border-radius: 999px; font-size: 11px; font-weight: 500;
  background: var(--ivory-2); color: var(--ink-2); border: 1px solid var(--line);
}

/* Prose */
.pl-prose-block { background: var(--paper); border: 1px solid var(--line); border-radius: 10px; padding: 18px; }
.pl-prose { line-height: 1.6; color: var(--ink); margin: 0 0 8px; }
.pl-prose-meta { color: var(--ink-3); }
.pl-lang-toggle {
  display: inline-flex; gap: 4px; font-size: 11px; align-items: center;
  background: var(--ivory-2); border: 1px solid var(--line); border-radius: 999px; padding: 2px;
}
.pl-lang-toggle button { background: transparent; border: 0; padding: 3px 10px; border-radius: 999px; cursor: pointer; color: var(--ink-3); font-family: var(--mono); }
.pl-lang-toggle button.is-active { background: var(--ink); color: var(--paper); }
.pl-lang-toggle span { color: var(--ink-3); padding: 0 2px; }

/* Detail grid (config + area breakdown) */
.pl-detail-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 8px 16px; }
.pl-detail-item { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px dotted var(--line); font-size: 13px; }
.pl-detail-label { color: var(--ink-3); }

/* Amenities */
.pl-amenity-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 10px; }
.pl-amenity-tile { display: flex; align-items: center; gap: 8px; padding: 10px 12px; background: var(--paper); border: 1px solid var(--line); border-radius: 8px; }
.pl-amenity-icon { color: var(--ink-2); display: flex; }
.pl-amenity-label { font-size: 12px; color: var(--ink); }

/* Floor plans */
.pl-floorplans-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }
@media (max-width: 700px) { .pl-floorplans-grid { grid-template-columns: 1fr; } }
.pl-floorplan-card { background: var(--paper); border: 1px solid var(--line); border-radius: 8px; overflow: hidden; }
.pl-floorplan-meta { padding: 8px 12px; color: var(--ink-3); }

/* Commute pills + POI panels */
.pl-commute-pills { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
.pl-commute-pill { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; background: var(--ivory-2); border: 1px solid var(--line); border-radius: 999px; font-size: 11px; }
.pl-poi-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 12px; margin-top: 14px; }
.pl-poi-panel { background: var(--paper); border: 1px solid var(--line); border-radius: 8px; padding: 12px 14px; }
.pl-poi-panel-head { display: flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 600; color: var(--ink); margin-bottom: 8px; padding-bottom: 6px; border-bottom: 1px solid var(--line); }
.pl-poi-panel-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 8px; }
.pl-poi-name { font-size: 13px; color: var(--ink); }
.pl-poi-meta { color: var(--ink-3); margin-top: 1px; }

/* Sparkline */
.pl-sparkline { display: flex; align-items: flex-end; gap: 4px; height: 100px; padding: 14px 0 30px; border-bottom: 1px dotted var(--line); position: relative; }
.pl-sparkline-bar {
  flex: 1; min-width: 16px;
  background: linear-gradient(to top, var(--saffron), var(--saffron-deep, #d8a35e));
  border-radius: 2px 2px 0 0;
  position: relative;
  min-height: 6px;
}
.pl-sparkline-month {
  position: absolute; bottom: -22px; left: 50%; transform: translateX(-50%);
  font-size: 9px; color: var(--ink-3); letter-spacing: 0.04em;
}
.pl-sparkline-caption { color: var(--ink-3); margin-top: 12px; }

/* Builder block */
.pl-builder-row { display: flex; gap: 14px; flex-wrap: wrap; margin-bottom: 12px; }
.pl-builder-stat { padding: 10px 16px; background: var(--ivory-2); border-radius: 6px; flex: 1; min-width: 120px; }
.pl-builder-stat-value { font-size: 18px; font-weight: 600; color: var(--ink); }
.pl-builder-stat-label { font-size: 10px; color: var(--ink-3); letter-spacing: 0.04em; text-transform: uppercase; margin-top: 2px; }
.pl-builder-recent-label { color: var(--ink-3); margin-bottom: 6px; }
.pl-builder-recent-list { list-style: none; padding: 0; margin: 0; }
.pl-builder-recent-list li { display: flex; justify-content: space-between; padding: 6px 0; border-bottom: 1px dotted var(--line); font-size: 13px; }
.pl-escrow-note { margin-top: 14px; padding: 10px 14px; background: var(--green-soft); border: 1px solid #c8d8b0; border-radius: 6px; font-size: 12px; color: #355d1f; line-height: 1.5; }

/* Comparables */
.pl-comparables-carousel {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  /* Negative margins + matching padding bleed the carousel to the
   * column edges so cards can scroll beyond the body-main column's
   * normal padding without looking clipped. */
  margin: 0 -4px;
  padding: 4px 4px 12px;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  /* Thin, low-contrast scrollbar — present (a11y signal that the
   * row is scrollable) but unobtrusive. */
  scrollbar-width: thin;
  scrollbar-color: var(--line, #e6dfd1) transparent;
}
.pl-comparables-carousel::-webkit-scrollbar { height: 6px; }
.pl-comparables-carousel::-webkit-scrollbar-track { background: transparent; }
.pl-comparables-carousel::-webkit-scrollbar-thumb {
  background: var(--line, #e6dfd1);
  border-radius: 3px;
}
.pl-comparables-carousel::-webkit-scrollbar-thumb:hover {
  background: var(--ink-3, #888);
}
.pl-comparables-carousel .pl-comparable-card {
  /* Fixed card width keeps the carousel scannable. 240px = ~3 cards
   * visible above the fold on a 720px-wide body-main column on
   * desktop; 1.5 on mobile (peek next card to hint scrollability). */
  flex: 0 0 240px;
  scroll-snap-align: start;
}
@media (max-width: 700px) {
  /* Mobile: full-bleed to the screen edges so the leftmost card aligns
   * with the page padding and the carousel feels like a native swipe row. */
  .pl-comparables-carousel { margin: 0 -16px; padding: 4px 16px 12px; }
  .pl-comparables-carousel .pl-comparable-card { flex: 0 0 220px; }
}
.pl-comparable-card {
  background: var(--paper); border: 1px solid var(--line); border-radius: 8px; overflow: hidden;
  text-decoration: none; color: var(--ink); display: flex; flex-direction: column;
  transition: border-color 0.12s ease;
}
.pl-comparable-card:hover { border-color: var(--ink-3); }
.pl-comparable-body { padding: 10px 12px; }
.pl-comparable-title { font-size: 13px; font-weight: 500; color: var(--ink); line-height: 1.4; }
.pl-comparable-price { font-size: 14px; font-weight: 600; margin-top: 4px; }
.pl-comparable-meta { color: var(--ink-3); margin-top: 2px; }
.pl-comparable-badges { display: flex; gap: 4px; margin-top: 6px; }
.pl-mini-badge { padding: 1px 6px; font-size: 9px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; border-radius: 3px; }
.pl-mini-badge--roi { background: #1a3d8c; color: #fff; }
/* Freshness pill on comparable carousel cards — renamed from
 * --verified to --refreshed so "Verified" stays ROI-Verified-exclusive. */
.pl-mini-badge--refreshed { background: var(--green); color: #ffffff; }
.pl-comparable-gap { margin-top: 6px; color: var(--ink-3); }

/* Comparable card thumbnail — first photo from the listing rendered
 * with a 4:3 aspect-ratio wrapper so cards stay uniform regardless
 * of source image size. Photo count chip overlays bottom-right. */
.pl-comparable-thumb {
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 3;
  background: #f3eee5;
  overflow: hidden;
}
/* Comparable-card fallback CTA — shown when no peer listings exist for
 * this locality+BHK. The icon thumb shares the regular thumb's 4:3
 * footprint so the carousel doesn't reflow, but uses paper bg + magnifier
 * glyph to read as "search more" rather than "broken image". */
.pl-comparable-cta-thumb {
  width: 100%;
  aspect-ratio: 4 / 3;
  background: var(--paper);
  border-bottom: 1px solid var(--line);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-3);
}
.pl-comparable-card--cta:hover .pl-comparable-cta-thumb { color: var(--ink); }
.pl-comparable-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.pl-comparable-thumb-count {
  position: absolute;
  bottom: 8px;
  right: 8px;
  padding: 2px 8px;
  background: rgba(0, 0, 0, 0.55);
  color: var(--paper);
  border-radius: 999px;
  font-size: 10px;
  letter-spacing: 0.03em;
}

/* Q&A */
.pl-qa-list { display: flex; flex-direction: column; gap: 14px; }
.pl-qa-pair { padding: 12px 14px; background: var(--paper); border: 1px solid var(--line); border-radius: 8px; }
.pl-qa-q-row, .pl-qa-a-row { display: flex; gap: 10px; align-items: flex-start; padding: 4px 0; }
.pl-qa-a-row { padding-top: 8px; border-top: 1px dotted var(--line); margin-top: 8px; }
.pl-qa-q-mark, .pl-qa-a-mark { font-weight: 600; font-size: 11px; color: var(--ink-3); width: 16px; text-align: center; flex-shrink: 0; padding-top: 2px; }
.pl-qa-q-text { font-weight: 500; color: var(--ink); }
.pl-qa-a-text { color: var(--ink-2); line-height: 1.5; }
.pl-qa-q-meta, .pl-qa-a-meta { color: var(--ink-3); margin-top: 2px; }

/* FAQ */
.pl-faq-list { display: flex; flex-direction: column; gap: 6px; }
.pl-faq { background: var(--paper); border: 1px solid var(--line); border-radius: 8px; overflow: hidden; }
.pl-faq[open] { border-color: var(--ink-3); }
.pl-faq-q { padding: 12px 14px; cursor: pointer; font-weight: 500; color: var(--ink); list-style: none; user-select: none; }
.pl-faq-q::-webkit-details-marker { display: none; }
.pl-faq-q::before { content: "+ "; color: var(--ink-3); font-family: var(--mono); }
.pl-faq[open] .pl-faq-q::before { content: "− "; color: var(--ink); }
.pl-faq-a { padding: 0 14px 12px; color: var(--ink-2); line-height: 1.55; margin: 0; }
.pl-faq-meta { color: var(--ink-3); margin-top: 8px; }

/* Sticky bottom CTA (mobile) */
.pl-sticky-cta {
  display: none;
  position: fixed; bottom: 0; left: 0; right: 0;
  background: var(--paper); border-top: 1px solid var(--line);
  padding: 8px 12px max(8px, var(--inset-bottom)) 12px;
  gap: 8px;
  z-index: 100;
  box-shadow: 0 -4px 12px rgba(0,0,0,0.06);
}
@media (max-width: 700px) {
  .pl-sticky-cta { display: flex; }
  .pl-page { padding-bottom: calc(80px + var(--inset-bottom)); }
}
.pl-sticky-cta-btn {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  background: var(--paper); border: 1px solid var(--line); border-radius: 8px;
  padding: 8px 4px; gap: 2px; cursor: pointer;
  font-family: var(--mono);
}
.pl-sticky-cta-btn--call { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.pl-sticky-cta-btn--wa { background: #25d366; color: #fff; border-color: #25d366; }
.pl-sticky-cta-btn--visit { color: var(--ink-2); }
.pl-sticky-cta-label { font-size: 10px; letter-spacing: 0.04em; text-transform: uppercase; }

/* OTP sheet (bottom-sheet stub) */
.pl-otp-sheet {
  position: fixed; inset: 0; z-index: 1000;
  display: none;
  pointer-events: none;
}
.pl-otp-sheet.is-open { display: block; pointer-events: auto; }
.pl-otp-sheet-backdrop { position: absolute; inset: 0; background: rgba(0,0,0,0.5); animation: pl-fade-in 0.2s ease; }
.pl-otp-sheet-panel {
  position: absolute; bottom: 0; left: 0; right: 0;
  max-width: 480px; margin: 0 auto;
  background: var(--paper);
  border-radius: 16px 16px 0 0;
  padding: 22px 22px max(32px, var(--inset-bottom));
  animation: pl-slide-up 0.24s cubic-bezier(.2,.8,.2,1);
  /* Make the panel itself a scroll container so the form can be
     reached when content (name + phone + email + message textarea
     + Buy/Rent/Sell chips + DPDP checkbox + Send button + footer)
     overflows the viewport. Without this, openSheet() correctly
     locks body scroll but the panel ALSO can't scroll → submit
     button is unreachable. 100dvh handles iOS soft-keyboard
     resize; min() leaves a 16 px breathing margin from the top.
     overscroll-behavior:contain stops the body underneath from
     rubber-band-scrolling when the panel scroll reaches its ends. */
  max-height: min(90vh, 100dvh - 16px);
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}
@media (min-width: 700px) {
  .pl-otp-sheet-panel { bottom: 50%; transform: translateY(50%); border-radius: 16px; }
}
.pl-otp-sheet-grip { width: 36px; height: 4px; background: var(--line-2, var(--line)); border-radius: 2px; margin: 0 auto 14px; }
.pl-otp-title { font-size: 18px; font-weight: 600; margin: 0 0 6px; color: var(--ink); }
.pl-otp-sub { color: var(--ink-2); font-size: 13px; line-height: 1.5; margin: 0 0 16px; }
.pl-otp-step[data-step="2"]:not(.is-active) { display: none; }
.pl-otp-step[data-step="1"][data-step="done"] { display: none; }
.pl-otp-submit { margin-top: 12px; width: 100%; }
.pl-otp-meta { color: var(--ink-3); margin-top: 10px; text-align: center; }
.pl-otp-phone { display: block; text-align: center; font-size: 26px; font-weight: 600; padding: 16px 0; margin: 12px 0; background: var(--ivory-2); border-radius: 8px; color: var(--ink); text-decoration: none; }
.pl-otp-actions { display: flex; gap: 10px; margin-top: 12px; }
.pl-otp-actions .btn { flex: 1; }

@keyframes pl-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes pl-slide-up { from { transform: translateY(20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }

/* OTP-sheet form helpers — scoped to .pl-otp-sheet so the bare-
   .form-field / .form-label overrides don't leak globally and reset
   every other form on the site. The earlier global rules at L431/L437
   are intentional defaults. */
.pl-otp-sheet .form-field { display: block; margin: 10px 0; }
.pl-otp-sheet .form-label { display: block; font-size: 11px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--ink-3); margin-bottom: 4px; font-family: var(--mono); }
.pl-otp-sheet .form-input-row { display: flex; align-items: stretch; gap: 6px; }
.pl-otp-sheet .form-input-prefix { padding: 8px 12px; background: var(--ivory-2); border: 1px solid var(--line); border-radius: 6px; color: var(--ink-2); font-weight: 500; align-self: stretch; display: flex; align-items: center; }

/* ── Direction B v2 augmentations (cars + hotels research, 2026-04-30) ──── */

/* Preview-only: variant toggle for "verified vs new broker" */
.pl-preview-toggle {
  display: inline-flex; align-items: center; gap: 6px;
  margin: 0 0 14px;
  padding: 4px 6px;
  background: var(--ivory-2);
  border: 1px dashed var(--line);
  border-radius: 999px;
  color: var(--ink-3);
}
.pl-preview-toggle a { color: var(--ink-3); text-decoration: none; padding: 3px 10px; border-radius: 999px; }
.pl-preview-toggle a.is-active { background: var(--ink); color: var(--paper); }

/* Mosaic 1+4 + "View all" trigger overlaid on the last tile */
.pl-photo-mosaic--airbnb {
  position: relative;
  display: grid;
  grid-template-columns: 2fr 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  gap: 6px;
  border-radius: 10px;
  overflow: hidden;
}
.pl-photo-mosaic--airbnb > :first-child { grid-row: 1 / span 2; }
.pl-photo-modal-trigger {
  position: absolute;
  bottom: 12px; right: 12px;
  background: rgba(255,255,255,0.95);
  border: 1px solid var(--ink-2);
  color: var(--ink);
  padding: 6px 14px;
  border-radius: 6px;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(0,0,0,0.12);
}
.pl-photo-modal-trigger:hover { background: var(--paper); }
@media (max-width: 700px) {
  .pl-photo-mosaic--airbnb { grid-template-columns: 1fr; grid-template-rows: auto; }
  .pl-photo-mosaic--airbnb > :first-child { grid-row: auto; }
  .pl-photo-mosaic--airbnb > :nth-child(n+3) { display: none; }
}

/* Honest social proof — never red, never urgent. Just a quiet line. */
.pl-social-proof {
  display: flex; align-items: center; gap: 8px;
  margin: 0 0 14px;
  padding: 6px 10px;
  background: var(--ivory-2);
  border-left: 2px solid var(--saffron-deep, #d8a35e);
  border-radius: 4px;
  color: var(--ink-2);
}
.pl-social-proof-icon {
  width: 8px; height: 8px;
  background: var(--saffron-deep, #d8a35e);
  border-radius: 50%;
  display: inline-block;
}

/* CarGurus-style deal-rating pill */
.pl-hero-price-row {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.pl-deal-rating {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px;
  border-radius: 4px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.pl-deal-rating-label { font-weight: 700; }
.pl-deal-rating-delta { font-size: 11px; opacity: 0.9; }
.pl-deal-rating--great { background: #1a3d1f; color: #d8e8db; }
.pl-deal-rating--good  { background: #355d1f; color: var(--green-soft); }
.pl-deal-rating--fair  { background: var(--cream); color: #5c4a2c; border: 1px solid #d8c7a3; }
.pl-deal-rating--above_market { background: #5c2c2c; color: #fde8e8; }
.pl-deal-rating-basis { color: var(--ink-3); margin-top: 4px; line-height: 1.4; }

/* Three-badge trust architecture (orthogonal axes) */
.pl-trust-row--triple {
  display: flex; flex-direction: column; gap: 6px;
  margin: 14px 0 10px;
  padding: 10px 12px;
  background: var(--ivory-2);
  border-radius: 8px;
  border-left: 3px solid var(--saffron);
}
.pl-trust-row--triple .pl-trust-pill {
  display: flex; align-items: center; gap: 8px;
  padding: 4px 10px;
  background: var(--paper);
  border: 1px solid var(--line);
  width: fit-content;
}
.pl-trust-pill-axis {
  font-size: 9px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
  border-right: 1px solid var(--line);
  padding-right: 8px;
}
.pl-trust-pill--roi-stack .pl-trust-pill-value { color: #1a3d8c; font-weight: 600; }
.pl-trust-pill--listing-stack .pl-trust-pill-value { color: #355d1f; font-weight: 500; }
.pl-trust-pill--top-stack .pl-trust-pill-value { color: var(--saffron-deep, #d8a35e); font-weight: 600; }

/* Broker hero "New on ROI" pill */
.pl-broker-new-pill {
  display: inline-block;
  padding: 2px 8px;
  background: var(--ink);
  color: var(--paper);
  border-radius: 999px;
  font-size: 9px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-weight: 600;
}
.pl-broker-stat--new .pl-broker-stat-value {
  font-size: 12px;
  background: var(--ink);
  color: var(--paper);
  padding: 2px 8px;
  border-radius: 4px;
}

/* Imperfections section — quiet honest disclosure, NOT red/scary */
.pl-imperfections {
  background: var(--ivory-2);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 18px 20px;
  margin: 24px 0 32px;
}
.pl-imperfections-mono { color: var(--ink-3); }
.pl-imperfections-list {
  list-style: none; padding: 0; margin: 12px 0 0;
  display: flex; flex-direction: column; gap: 12px;
}
.pl-imperfection {
  display: grid;
  grid-template-columns: 88px 1fr;
  gap: 16px;
  padding: 10px 12px;
  background: var(--paper);
  border-radius: 6px;
  border: 1px solid var(--line);
}
.pl-imperfection-kind {
  align-self: flex-start;
  padding: 2px 8px;
  background: var(--ivory-2);
  border-radius: 999px;
  text-align: center;
  color: var(--ink-3);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.pl-imperfection-label { font-size: 13px; font-weight: 500; color: var(--ink); margin-bottom: 4px; }
.pl-imperfection-note { color: var(--ink-2); line-height: 1.5; font-size: 12px; }
.pl-imperfection-photo-flag { display: inline-block; margin-top: 6px; color: var(--ink-3); }

/* Intent chips (request-to-book step 1) */
.pl-otp-sheet-panel--wide { max-width: 540px; }
.pl-otp-form-section { margin-bottom: 18px; }
.pl-intent-chip-row {
  display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px;
}
.pl-intent-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px;
  border: 1.5px solid var(--line);
  background: var(--paper);
  border-radius: 999px;
  font-size: 12px;
  cursor: pointer;
  transition: border-color 0.12s, background 0.12s;
}
.pl-intent-chip input { display: none; }
.pl-intent-chip:hover { border-color: var(--ink-3); }
.pl-intent-chip:has(input:checked) {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--paper);
}
.pl-intent-chip-icon { font-size: 14px; }
.pl-intent-chip-label { font-weight: 500; }

.pl-budget-row select { width: 100%; }

.pl-slot-row { display: flex; flex-wrap: wrap; gap: 6px; }
.pl-slot-pill {
  padding: 6px 12px;
  border: 1.5px solid var(--line);
  background: var(--paper);
  border-radius: 6px;
  font-size: 12px;
  cursor: pointer;
  font-family: inherit;
  color: var(--ink-2);
}
.pl-slot-pill:hover { border-color: var(--ink-3); }
.pl-slot-pill.is-active { border-color: var(--ink); background: var(--ink); color: var(--paper); }
.pl-slot-pill--more { color: var(--ink-3); border-style: dashed; }

/* OTP step display: only one active at a time. Transition fades
   between active/inactive when state flips. */
.pl-otp-step { display: none; transition: opacity 0.2s; }
.pl-otp-step.is-active { display: block; }

/* Pending state cards (request-to-book step 2 + 3) */
.pl-otp-pending-card,
.pl-otp-revealed-id {
  background: var(--ivory-2);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 12px 14px;
  margin: 10px 0;
}
.pl-otp-pending-row,
.pl-otp-revealed-row {
  display: flex; justify-content: space-between; align-items: center;
  padding: 6px 0;
  border-bottom: 1px dotted var(--line);
}
.pl-otp-pending-row:last-child,
.pl-otp-revealed-row:last-child { border-bottom: none; }
.pl-otp-pending-label { color: var(--ink-3); font-size: 11px; letter-spacing: 0.04em; text-transform: uppercase; }
.pl-otp-pending-value { color: var(--ink); font-weight: 500; font-size: 13px; }

/* Photo modal */
.pl-photo-modal {
  position: fixed; inset: 0; z-index: 1100;
  display: none;
  pointer-events: none;
}
.pl-photo-modal.is-open { display: block; pointer-events: auto; }
.pl-photo-modal-backdrop {
  position: absolute; inset: 0;
  background: rgba(0,0,0,0.85);
  animation: pl-fade-in 0.2s ease;
}
.pl-photo-modal-panel {
  position: absolute;
  top: 5%; bottom: 5%; left: 5%; right: 5%;
  background: var(--paper);
  border-radius: 12px;
  display: flex; flex-direction: column;
  overflow: hidden;
}
@media (max-width: 700px) {
  .pl-photo-modal-panel { top: 0; bottom: 0; left: 0; right: 0; border-radius: 0; }
}
.pl-photo-modal-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 20px;
  border-bottom: 1px solid var(--line);
}
.pl-photo-modal-title { font-size: 16px; font-weight: 600; margin: 0; color: var(--ink); }
.pl-photo-modal-close {
  background: transparent; border: 0; cursor: pointer;
  font-size: 24px; line-height: 1; color: var(--ink-2);
  width: 32px; height: 32px; border-radius: 4px;
}
.pl-photo-modal-close:hover { background: var(--ivory-2); color: var(--ink); }
.pl-photo-modal-tabs {
  display: flex; gap: 4px; overflow-x: auto;
  padding: 12px 20px;
  border-bottom: 1px solid var(--line);
  background: var(--paper);
}
.pl-photo-modal-tab {
  background: transparent; border: 1px solid var(--line);
  padding: 6px 12px; border-radius: 999px;
  font-size: 11px; cursor: pointer; color: var(--ink-2);
  display: inline-flex; align-items: center; gap: 6px;
  white-space: nowrap;
  font-family: inherit;
}
.pl-photo-modal-tab:hover { background: var(--ivory-2); }
.pl-photo-modal-tab.is-active { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.pl-photo-modal-tab-count {
  font-family: var(--mono);
  font-size: 10px;
  background: rgba(0,0,0,0.1);
  padding: 1px 6px;
  border-radius: 999px;
}
.pl-photo-modal-tab.is-active .pl-photo-modal-tab-count { background: rgba(255,255,255,0.2); }
.pl-photo-modal-body {
  flex: 1; overflow-y: auto;
  padding: 20px;
}
.pl-photo-modal-cat-block { margin-bottom: 28px; }
.pl-photo-modal-cat-heading {
  font-size: 14px; font-weight: 600; color: var(--ink);
  margin: 0 0 10px;
}
.pl-photo-modal-cat-heading .small { color: var(--ink-3); font-weight: 400; }
.pl-photo-modal-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 8px;
}
.pl-photo-placeholder--modal { min-height: 180px; }

/* ── Mobile preview frame (iPhone wrapper + iframe) ────────────────── */
.pl-mobile-preview-wrap {
  display: grid;
  grid-template-columns: 1fr minmax(420px, 460px) 280px;
  gap: 32px;
  align-items: start;
}
@media (max-width: 1099px) {
  .pl-mobile-preview-wrap { grid-template-columns: 1fr; }
}

.pl-mobile-preview-meta {
  display: flex; flex-direction: column; gap: 14px;
  color: var(--ink-3);
  line-height: 1.6;
  position: sticky;
  top: 80px;
}
.pl-mobile-preview-controls {
  display: flex; flex-direction: column; gap: 8px;
}
.pl-mobile-preview-controls .btn { justify-content: flex-start; }

.pl-mobile-frame {
  width: 414px;
  margin: 0 auto;
  background: var(--ink);
  border-radius: 48px;
  padding: 12px;
  box-shadow:
    0 0 0 2px #000,
    0 24px 48px rgba(0,0,0,0.18);
  position: relative;
}
.pl-mobile-frame-status-bar {
  position: relative;
  display: flex; align-items: center; justify-content: space-between;
  padding: 6px 24px 8px;
  color: var(--paper);
  font-size: 13px;
}
.pl-mobile-status-time { font-weight: 600; letter-spacing: -0.02em; font-family: -apple-system, system-ui; font-size: 14px; }
.pl-mobile-status-icons { font-size: 11px; letter-spacing: 1px; opacity: 0.85; }
.pl-mobile-dynamic-island {
  position: absolute;
  top: 4px; left: 50%;
  transform: translateX(-50%);
  width: 110px; height: 32px;
  background: #000;
  border-radius: 999px;
}
.pl-mobile-iframe {
  display: block;
  width: 390px;
  height: 844px;
  border: 0;
  background: var(--paper);
  border-radius: 32px;
  margin: 0 auto;
  /* iframe content scrolls inside the frame */
  overflow: hidden;
}
.pl-mobile-frame-home {
  width: 130px; height: 5px;
  background: var(--paper);
  border-radius: 3px;
  margin: 8px auto 4px;
  opacity: 0.9;
}

.pl-mobile-preview-notes {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 16px;
  position: sticky;
  top: 80px;
}
.pl-mobile-notes-heading {
  font-size: 13px; font-weight: 600; color: var(--ink); margin-bottom: 10px;
}
.pl-mobile-notes-list {
  list-style: none; padding: 0; margin: 0;
  display: flex; flex-direction: column; gap: 8px;
  color: var(--ink-2);
  line-height: 1.5;
}
.pl-mobile-notes-list li {
  padding-left: 18px;
  position: relative;
}
.pl-mobile-notes-list li::before {
  content: "✓";
  position: absolute;
  left: 0; top: 0;
  color: #355d1f;
  font-weight: 600;
}

/* ── Direction A — mobile-specific tightening ──────────────────────────
   .pl-direction-a is on the LIVE public PDP wrapper (not just the preview
   iframe), so these rules ship to real phones. Breakpoint widened
   460 -> 540px (2026-06-08): at 460px every phone >460px logical width
   (iPhone Pro Max = 430 ok, but Pixel 8 Pro = 448, many Androids 450-480)
   fell through to the <=900px collapse only — so the stacked actions,
   page gutter, and 2-col highlights silently never ran. 540px captures
   all common portrait phones while staying clear of the 560/600px blocks
   used elsewhere. */
@media (max-width: 540px) {
  /* Real-phone gutter. (Was 0 4px — that near-zero value was tuned for the
     preview iframe, which carried its own shell padding; on a physical
     device it read as broken edge-to-edge.) */
  .pl-direction-a .pl-page { padding: 0 12px; }

  /* Hero gallery: hero photo on top + 1 small + "+more" tile in a row */
  .pl-hero-a .pl-photo-mosaic {
    grid-template-columns: 1fr;
    grid-template-rows: 280px;
  }
  .pl-hero-a .pl-photo-mosaic > :first-child {
    grid-row: 1;
    min-height: 280px;
  }
  .pl-hero-a .pl-photo-placeholder--hero { font-size: 12px; }

  /* Title slightly smaller */
  .pl-direction-a .pl-hero-title { font-size: 18px; line-height: 1.3; }

  /* Price visually larger; per-sqft + EMI fit on next lines */
  .pl-direction-a .pl-hero-price { font-size: 26px; }
  .pl-direction-a .pl-emi-badge { display: flex; width: 100%; justify-content: space-between; }

  /* Trust pills wrap cleanly with adequate tap area */
  .pl-direction-a .pl-trust-pill { padding: 6px 12px; font-size: 12px; }

  /* Broker card actions are stacked, full-width buttons */
  .pl-direction-a .pl-broker-actions { gap: 10px; }
  .pl-direction-a .pl-broker-actions .btn { padding: 12px 14px; font-size: 14px; }

  /* Sticky bottom bar: bigger tap targets + breathing room */
  .pl-sticky-cta { padding: 10px 12px 14px; gap: 10px; }
  .pl-sticky-cta-btn { padding: 12px 4px; }
  .pl-sticky-cta-label { font-size: 11px; }

  /* Below-fold sections — tighter padding so content doesn't feel cramped */
  .pl-direction-a .pl-section { margin: 18px 0; }
  .pl-direction-a .pl-section-title { font-size: 16px; }
  .pl-direction-a .pl-highlights { grid-template-columns: repeat(2, 1fr); }
  .pl-direction-a .pl-h-tile { padding: 10px 12px; }
  .pl-direction-a .pl-h-tile-value { font-size: 16px; }
  .pl-direction-a .pl-poi-grid { grid-template-columns: 1fr; }
}

/* The mobile iframe shows the full app chrome too — make sure layouts.app
   header is mobile-friendly inside the frame. The main app handles this
   already via responsive breakpoints. */

/* ── Public Search Page B5.1 (.ps-*) ───────────────────────────────────
   SpareRoom-shape: hero + tabs + filter chips + split-pane map+list.
   Forward-compat: when this locks, port verbatim into the production
   search controllers' Blade. */

.ps-shell { display: flex; flex-direction: column; gap: 0; }
.ps-shell-head {
  display: flex; flex-direction: column; gap: 0px;
  margin-bottom: 18px;
}

/* HERO search bar */
.ps-hero {
  background: var(--ivory-2);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 18px 20px;
}
.ps-hero-search {
  display: grid;
  grid-template-columns: 1fr 100px 100px;
  gap: 8px;
  align-items: stretch;
}
@media (max-width: 600px) {
  .ps-hero-search { grid-template-columns: 1fr; }
}
.ps-hero-search-input {
  display: flex; align-items: center; gap: 8px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 0 12px;
  color: var(--ink-3);
}
.ps-hero-search-input input {
  flex: 1;
  border: 0; outline: none; background: transparent;
  padding: 12px 0;
  font-size: var(--fs-input);
  color: var(--ink);
  font-family: inherit;
}
.ps-hero-search-select,
.ps-hero-search-submit {
  height: auto;
  border-radius: 8px;
  font-family: inherit;
}
.ps-hero-search-select {
  background: var(--paper);
  border: 1px solid var(--line);
  padding: 10px 14px;
  font-size: var(--fs-input);
  color: var(--ink);
}
.ps-hero-meta { color: var(--ink-3); margin-top: 8px; }

/* Tab pills */
.ps-tabs {
  display: flex; gap: 4px;
  border-bottom: 1px solid var(--line);
  padding: 0 4px;
}
.ps-tab {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 12px 20px 14px;
  text-decoration: none;
  color: var(--ink-3);
  border-bottom: 3px solid transparent;
  margin-bottom: -1px;
  font-weight: 500;
  font-size: 14px;
  white-space: nowrap;
}
.ps-tab:hover { color: var(--ink-2); }
.ps-tab.is-active {
  color: var(--ink);
  border-bottom-color: var(--saffron);
  font-weight: 600;
}
.ps-tab-count {
  font-size: 11px;
  color: var(--ink-3);
  background: var(--ivory-2);
  padding: 1px 8px;
  border-radius: 999px;
}
.ps-tab.is-active .ps-tab-count {
  background: var(--ink);
  color: var(--paper);
}
.ps-tab-new {
  background: var(--saffron);
  color: var(--ink);
  font-size: 9px;
  letter-spacing: 0.06em;
  padding: 2px 6px;
  border-radius: 3px;
  font-weight: 700;
}

/* Filter chip strip (Baymard horizontal). Three-part layout:
   .ps-filter-chips (filter tokens, scroll-on-mobile),
   .ps-filter-actions (More-filters + Sort, always visible). */
.ps-filter-strip {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 0;
  border-bottom: 1px solid var(--line);
  margin-bottom: 16px;
}
@media (max-width: 800px) {
  .ps-filter-strip {
    flex-direction: column; align-items: stretch;
    /* Sticky to the navbar's bottom edge. The navbar is sticky at
       top:0 with padding 14px 32px on desktop / 14px 16px on mobile,
       so its rendered height varies with content. 60px is a safe
       upper bound for one-line nav (logo + buttons). The calc()
       extends the offset by safe-area-inset-top so notched devices
       (iPhone X+) keep the strip below the navbar even when the
       navbar grows by the inset. When mobile bottom-nav ships, this
       inversion frees the top of the viewport — top: 0 suffices. */
    position: sticky; top: calc(60px + var(--inset-top)); z-index: 10;
    background: var(--paper);
    padding: 8px 16px;
    margin: 0 -16px 16px;
    gap: 8px;
  }
}
.ps-filter-chips {
  display: flex; flex-wrap: wrap; gap: 6px;
  overflow-x: auto; flex: 1;
  min-width: 0;
}
@media (max-width: 800px) {
  /* Mobile: chips become a horizontal scroller. Hides the native
     scrollbar (touch users don't need it) but keeps overflow-x:auto
     so swipe / two-finger trackpad scroll works. flex-shrink: 0 on
     each chip via the chip rule below prevents squeeze. */
  .ps-filter-chips {
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    /* Bleed the scroller to the screen edges so the first chip's
       left padding visually aligns with the page gutter. */
    margin: 0 -16px;
    padding: 2px 16px;
  }
  .ps-filter-chips::-webkit-scrollbar { display: none; }
}

/* Actions group — More-filters + Sort. Always visible regardless
   of how many active chips are in the scroller. On desktop sits
   to the right of the chip strip; on mobile drops below as a row. */
.ps-filter-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
}
@media (max-width: 800px) {
  .ps-filter-actions {
    justify-content: space-between;
    width: 100%;
  }
}
.ps-filter-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px;
  border: 1px solid var(--line);
  background: var(--paper);
  border-radius: 999px;
  font-size: 12px;
  color: var(--ink-2);
  cursor: pointer;
  font-family: inherit;
  white-space: nowrap;
  /* Inside a horizontal scroller, prevent squeeze when there are
     enough chips to overflow. flex-shrink: 0 keeps each chip at
     its natural width so the user actually has to scroll. */
  flex-shrink: 0;
  text-decoration: none;
  transition: border-color 0.12s, background 0.12s;
}
@media (max-width: 800px) {
  /* Touch-friendly hit targets — Apple HIG 44px / Material 48dp.
     Bumping the chip to ~36px tall + slightly larger horizontal
     padding lands close enough that fat-thumb taps don't miss. */
  .ps-filter-chip {
    padding: 8px 14px;
    font-size: 13px;
    min-height: 36px;
  }
  .ps-filter-chip-select {
    min-height: 36px;
  }
  .ps-filter-chip-select-input {
    padding: 8px 24px 8px 4px;
  }
}
.ps-filter-chip:hover { border-color: var(--ink-3); }
.ps-filter-chip.is-active {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
  font-weight: 500;
}
.ps-filter-chip-x { opacity: 0.7; font-size: 13px; }
.ps-filter-chip-caret { font-size: 9px; opacity: 0.7; }

/* SRP More-filters drawer — slide-in panel from the right
   (bottom-sheet on mobile). Triggered by the "+ More filters"
   chip via the `more-filters:open` window event. */
.ps-drawer-overlay {
  position: fixed;
  inset: 0;
  z-index: 1300;
  display: flex;
  justify-content: flex-end;
  pointer-events: auto;
}
.ps-drawer-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0,0,0,0.45);
  animation: ps-drawer-fade 0.18s ease-out;
}
.ps-drawer {
  position: relative;
  display: flex;
  flex-direction: column;
  width: min(420px, 100vw);
  max-width: 100%;
  height: 100%;
  background: var(--paper);
  box-shadow: -8px 0 24px rgba(0,0,0,0.18);
  animation: ps-drawer-slide-in 0.22s cubic-bezier(0.2, 0.8, 0.4, 1);
  overflow: hidden;
}
.ps-drawer-head {
  display: flex; justify-content: space-between; align-items: center;
  padding: 18px 22px;
  border-bottom: 1px solid var(--line);
  flex: 0 0 auto;
}
.ps-drawer-head h3 {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
  color: var(--ink);
  letter-spacing: -0.01em;
}
.ps-drawer-close {
  appearance: none;
  background: transparent;
  border: 0;
  font-size: 28px;
  line-height: 1;
  color: var(--ink-2);
  cursor: pointer;
  padding: 0 4px;
  transition: color 0.12s;
}
.ps-drawer-close:hover { color: var(--ink); }
.ps-drawer-body {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 18px 22px;
  display: flex;
  flex-direction: column;
  gap: 22px;
}
.ps-drawer-fieldset {
  border: 0;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.ps-drawer-legend {
  font-size: 11px;
  font-family: var(--mono);
  font-weight: 600;
  color: var(--ink-3);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  margin-bottom: 4px;
  padding: 0;
}
.ps-drawer-radio {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  cursor: pointer;
  font-size: 13px;
  color: var(--ink);
  transition: border-color 0.12s, background 0.12s;
}
.ps-drawer-radio:hover { border-color: var(--ink-3); }
.ps-drawer-radio input[type="radio"] {
  width: 14px; height: 14px;
  accent-color: var(--saffron-deep, #d8a35e);
  margin: 0;
  cursor: pointer;
}
.ps-drawer-radio:has(input:checked) {
  background: rgba(255,193,77,0.12);
  border-color: var(--saffron-deep, #d8a35e);
  font-weight: 600;
}
/* Checkbox row — same visual language as ps-drawer-radio so the
   drawer reads as a single coherent control set. Used for booleans
   (rera_only, oc_only, gated_only). */
.ps-drawer-checkbox {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  cursor: pointer;
  font-size: 13px;
  color: var(--ink);
  transition: border-color 0.12s, background 0.12s;
}
.ps-drawer-checkbox:hover { border-color: var(--ink-3); }
.ps-drawer-checkbox input[type="checkbox"] {
  width: 14px; height: 14px;
  accent-color: var(--saffron-deep, #d8a35e);
  margin: 0;
  cursor: pointer;
}
.ps-drawer-checkbox:has(input:checked) {
  background: rgba(255,193,77,0.12);
  border-color: var(--saffron-deep, #d8a35e);
  font-weight: 600;
}
.ps-drawer-coming-soon {
  padding: 12px 14px;
  background: var(--ivory-2, rgba(216,163,94,0.08));
  border-radius: 8px;
  color: var(--ink-3);
  line-height: 1.5;
}
/* Min–max numeric range row (Area filter) — shared by the SRP drawer
   and the hero More-filters drawer. */
.ps-drawer-range {
  display: flex;
  align-items: center;
  gap: 10px;
}
.ps-drawer-range-input {
  flex: 1 1 0;
  min-width: 0;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--paper);
  font-family: inherit;
  font-size: 14px; /* fs-input-allow — narrow drawer cell, follow-up: --fs-input-sm */
  color: var(--ink);
}
.ps-drawer-range-input:focus {
  outline: none;
  border-color: var(--saffron-deep, #d8a35e);
}
.ps-drawer-range-input::placeholder { color: var(--ink-3); }
.ps-drawer-range-sep { color: var(--ink-3); flex: 0 0 auto; }
.ps-drawer-foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  padding: 16px 22px max(16px, var(--inset-bottom));
  border-top: 1px solid var(--line);
  flex: 0 0 auto;
  background: var(--paper);
}
.ps-drawer-foot .btn { flex: 0 1 auto; }
.ps-drawer-foot .btn-primary { flex: 1; min-width: 0; }

@keyframes ps-drawer-slide-in {
  from { transform: translateX(100%); }
  to   { transform: translateX(0); }
}
@keyframes ps-drawer-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* Mobile — bottom-sheet pattern. Drawer slides up from the bottom,
   takes 88vh, rounded top corners. Animation flipped to vertical. */
@media (max-width: 700px) {
  .ps-drawer-overlay { align-items: flex-end; justify-content: stretch; }
  .ps-drawer {
    width: 100%;
    max-width: 100%;
    height: 88vh;
    border-radius: 16px 16px 0 0;
    animation: ps-drawer-slide-up 0.22s cubic-bezier(0.2, 0.8, 0.4, 1);
  }
  @keyframes ps-drawer-slide-up {
    from { transform: translateY(100%); }
    to   { transform: translateY(0); }
  }
}

/* Chip-shaped <select> wrapper — used by the Transaction +
   Possession dropdowns on the SRP filter strip. The form is laid
   out as a chip; the native <select> inside is styled to inherit
   the chip's look so it reads as a token, not a free-floating
   form control. */
.ps-filter-chip-select {
  display: inline-flex; align-items: center;
  padding: 0 4px 0 10px;
  border: 1px solid var(--line);
  background: var(--paper);
  border-radius: 999px;
  font-size: 12px; /* fs-input-allow — dense filter strip, follow-up: --fs-input-sm */
  color: var(--ink-2);
  font-family: inherit;
  font-weight: 500;
  white-space: nowrap;
  transition: border-color 0.12s, background 0.12s;
}
.ps-filter-chip-select:hover { border-color: var(--ink-3); }
.ps-filter-chip-select.is-active {
  background: rgba(255,193,77,0.22);
  border-color: var(--saffron-deep, #d8a35e);
  color: var(--ink);
  font-weight: 600;
}
.ps-filter-chip-select-input {
  appearance: none;
  -webkit-appearance: none;
  border: none;
  background: transparent;
  padding: 7px 24px 7px 4px;
  font: inherit;
  color: inherit;
  cursor: pointer;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='8' height='6' viewBox='0 0 8 6' fill='%237a6b4f'><polygon points='0,0 8,0 4,6'/></svg>");
  background-repeat: no-repeat;
  background-position: right 8px center;
}
.ps-filter-chip-select-input:focus { outline: none; }
/* More-filters trigger — highlighted (solid saffron accent) since the
   secondary filters (RERA / OC / Gated, + more coming) now live behind
   it; it's the gateway, so it shouldn't read as a dim/dashed afterthought.
   The .is-active state (a drawer filter is set) still flips to the
   ink-filled chip via the base .ps-filter-chip.is-active rule. */
.ps-filter-chip--more {
  border-style: solid;
  border-color: var(--saffron-deep, #b07d3c);
  color: var(--saffron-deep, #b07d3c);
  font-weight: 600;
  background: color-mix(in oklab, var(--saffron-soft, #fde7c4) 35%, var(--paper));
}
.ps-filter-chip--more:hover {
  background: color-mix(in oklab, var(--saffron-soft, #fde7c4) 60%, var(--paper));
}
.ps-filter-meta { display: flex; align-items: center; gap: 8px; color: var(--ink-3); white-space: nowrap; }
.ps-filter-sort {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 4px 8px;
  font-family: inherit;
  font-size: 12px;
}

/* ──────────────────────────────────────────────────────────────
   Unified search engine — shared across home hero + SRP top.
   Phase 3 slice (tabs only). Form / chips / slider land in later
   phases. See plans/ok-do-it-smooth-octopus.md for the full design.
   ────────────────────────────────────────────────────────────── */

.search-engine {
  display: block;
  margin-bottom: 16px;
}
.search-engine--hero { padding: 8px 0; }
/* .search-engine--srp-bar { padding: 4px 0 12px; } */

.search-engine-tabs {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.search-engine-tabs-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}
.search-engine-tabs-row--transaction {
  /* Slightly tighter row for the 1-3 transaction tabs — keeps
     them visually distinct from the wider category row. */
  padding-bottom: 4px;
  border-bottom: 1px dashed var(--line);
}
.search-engine-tabs-row--category {
  padding-top: 2px;
}

.search-engine-tab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 14px;
  border: 1px solid var(--line);
  background: var(--paper);
  border-radius: 999px;
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-2);
  cursor: pointer;
  font-family: inherit;
  text-decoration: none;
  white-space: nowrap;
  flex-shrink: 0;
  transition: border-color 0.12s, background 0.12s, color 0.12s;
}
.search-engine-tab:hover {
  border-color: var(--ink-3);
  color: var(--ink);
}
.search-engine-tab.is-active {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--paper);
  font-weight: 600;
}
.search-engine-tab--category {
  /* Category-row tabs are slightly smaller font / more compact
     so the 8-tab row fits one line on desktop. Mobile wraps
     naturally. */
  font-size: 11px;
  padding: 6px 12px;
}

/* Hero mode — tabs distribute full-width with each tab equally-
   sized (flex: 1 1 0). Matches the legacy .ph-hero-tabs--intent
   layout the home page shipped with: Buy/Rent/Lease split the row
   in thirds, the 8 category tabs split the row in eighths, text
   centered in each tab. SRP-bar mode keeps the compact content-
   sized pills (no override below) because the SRP bar is denser
   and equal-width tabs would waste horizontal space. */
.search-engine-tabs--hero .search-engine-tabs-row {
  width: 100%;
}
.search-engine-tabs--hero .search-engine-tab {
  flex: 1 1 0;
  min-width: 0;
  justify-content: center;
  text-align: center;
}
.search-engine-tabs--hero .search-engine-tabs-row--transaction {
  margin-bottom: 6px;
}
.search-engine-tabs--hero .search-engine-tabs-row--category {
  margin-bottom: 14px;
}

/* Mobile — SRP-bar mode tabs become horizontal-scroll (denser,
   matches the .ps-filter-chips strip pattern). Hero mode tabs
   keep their full-width wrap behavior so visitors see every
   category at a glance on small screens too. */
@media (max-width: 800px) {
  .search-engine-tabs--srp-bar .search-engine-tabs-row {
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    margin: 0 -16px;
    padding: 2px 16px;
  }
  .search-engine-tabs--srp-bar .search-engine-tabs-row::-webkit-scrollbar { display: none; }
  .search-engine-tab,
  .search-engine-tab--category {
    min-height: 34px;
    padding: 7px 14px;
  }
  /* Hero mode: undo the desktop flex:1 1 0 (equal-width squeeze).
     At 430px viewport divided 8 ways each tab gets ~50px, but
     labels like "Residential" / "Holiday Home" / "Agricultural"
     need 80-95px — combined with white-space:nowrap on .search-
     engine-tab, the text overflows the chip background and bleeds
     into adjacent chips. Instead let chips be content-sized and
     wrap across multiple rows (parent already has flex-wrap:wrap),
     so every category stays visible + readable. */
  .search-engine-tabs--hero .search-engine-tab {
    flex: 0 0 auto;
  }
}

/* Search engine chip row — category-aware sub-axis picker.
   One group per axis (commercial subtype / pg gender / sharing /
   coliving brand / plot zoning / agricultural subtype / holiday
   capacity / min-stay). Each group is [label]: [option pills].
   Residential renders nothing here (no categoryChips). */
.search-engine-chips {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px 0 4px;
  border-top: 1px dashed var(--line);
  margin-top: 8px;
}
.search-engine-chip-group {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
.search-engine-chip-label {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-3);
  flex-shrink: 0;
  min-width: 72px;
}
.search-engine-chip-options {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}
.search-engine-chip {
  display: inline-flex;
  align-items: center;
  padding: 6px 12px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--paper);
  color: var(--ink-2);
  font-size: 12px;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.search-engine-chip:hover {
  background: var(--ivory-2);
  border-color: var(--ink-3);
  color: var(--ink);
}
.search-engine-chip.is-active {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--paper);
  font-weight: 600;
}
.search-engine-chips--srp-bar {
  /* Tighter padding on the SRP variant so the chip row sits close
     to the tabs above and the (future) form below. */
  padding: 10px 0 2px;
}

/* Mobile — chip-options become horizontal-scroll so a long option
   list (e.g. 10 plot zoning slugs) doesn't wrap to 3 rows on
   narrow viewports. The label stays sticky-left as a header for
   the scroller. */
@media (max-width: 800px) {
  .search-engine-chip-group {
    align-items: flex-start;
    flex-direction: column;
    gap: 6px;
  }
  .search-engine-chip-label {
    min-width: 0;
  }
  .search-engine-chip-options {
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    margin: 0 -16px;
    padding: 2px 16px;
    width: calc(100% + 32px);
  }
  .search-engine-chip-options::-webkit-scrollbar { display: none; }
  .search-engine-chip {
    min-height: 34px;
    padding: 7px 14px;
    flex-shrink: 0;
  }
}

/* Search engine budget slider — dual-thumb range.
   Mirrors .ph-budget-slider-* visual treatment so the SRP slider
   looks identical to the home hero's. Renamed (not aliased) so
   Phase 7 can delete the .ph- variants without affecting the SRP. */
.search-engine-budget {
  display: block;
  margin-top: 12px;
  padding: 12px 0 4px;
  border-top: 1px dashed var(--line);
}
.search-engine-budget--srp-bar {
  padding: 10px 0 2px;
}
.search-engine-budget-head {
  display: flex; align-items: baseline; justify-content: space-between;
  margin-bottom: 8px;
  gap: 12px;
}
.search-engine-budget-label {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-3);
}
.search-engine-budget-meta {
  color: var(--ink-2);
}
.search-engine-budget-handles {
  display: flex; gap: 12px; margin-bottom: 12px;
}
.search-engine-budget-pill {
  display: inline-block;
  padding: 4px 10px;
  background: var(--ink);
  color: var(--paper);
  border-radius: 4px;
  font-size: 11px;
  font-weight: 600;
  font-family: var(--mono);
  letter-spacing: 0.04em;
}
.search-engine-budget-track {
  position: relative;
  height: 4px;
  /* The unfilled rail must read against BOTH the light page bg and the
     dark mobile budget panel. Plain var(--line) sat at ~1.35 contrast on
     the dark panel (oklch L 0.32 vs 0.25) — effectively invisible. Mix
     toward --ink so the rail has presence on either surface; the saffron
     fill (below) marks the selected span. */
  background: color-mix(in oklab, var(--ink) 30%, transparent);
  border-radius: 2px;
}
.search-engine-budget-track-fill {
  position: absolute;
  top: 0; bottom: 0;
  background: var(--saffron-deep, #d8a35e);
  border-radius: 2px;
}

/* Two-thumb dual-range frame. Same overlay technique as the home
   hero: the visual track sits in the middle; two transparent
   <input type="range"> controls overlay it; only the thumbs
   receive pointer events. */
.search-engine-budget-frame {
  position: relative;
  height: 18px;
  margin: 6px 0 22px;
}
.search-engine-budget-frame .search-engine-budget-track {
  position: absolute;
  top: 50%;
  left: 0; right: 0;
  margin: 0;
  transform: translateY(-50%);
}
.search-engine-budget-input {
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 100%;
  margin: 0;
  background: transparent;
  pointer-events: none;
  -webkit-appearance: none;
  appearance: none;
}
.search-engine-budget-input:focus { outline: none; }

.search-engine-budget-input::-webkit-slider-runnable-track {
  background: transparent; border: none; height: 100%;
}
.search-engine-budget-input::-moz-range-track {
  background: transparent; border: none; height: 100%;
}

.search-engine-budget-input::-webkit-slider-thumb {
  -webkit-appearance: none;
  pointer-events: auto;
  width: 16px; height: 16px;
  background: var(--paper);
  border: 2px solid var(--saffron-deep, #d8a35e);
  border-radius: 50%;
  cursor: grab;
  box-shadow: 0 1px 3px rgba(0,0,0,0.15);
}
.search-engine-budget-input::-moz-range-thumb {
  pointer-events: auto;
  width: 16px; height: 16px;
  background: var(--paper);
  border: 2px solid var(--saffron-deep, #d8a35e);
  border-radius: 50%;
  cursor: grab;
  box-shadow: 0 1px 3px rgba(0,0,0,0.15);
}
.search-engine-budget-input:active::-webkit-slider-thumb { cursor: grabbing; }
.search-engine-budget-input:active::-moz-range-thumb { cursor: grabbing; }
.search-engine-budget-input:focus-visible::-webkit-slider-thumb {
  box-shadow: 0 0 0 4px rgba(216,163,94,0.25);
}
.search-engine-budget-input:focus-visible::-moz-range-thumb {
  box-shadow: 0 0 0 4px rgba(216,163,94,0.25);
}

/* Lower-bound input wins clicks at the left edge; upper-bound at
   the right. Without this stacking the upper input would steal the
   left half because both share the same DOM position. */
.search-engine-budget-input--upper { z-index: 3; }
.search-engine-budget-input--lower { z-index: 4; }

.search-engine-budget-axis {
  display: flex; justify-content: space-between;
  /* --ink-3 (oklch L 0.66) on the dark panel (0.25) read faint at 10px —
     reported "text not visible". --ink-2 lifts contrast; 11px for size. */
  color: var(--ink-2);
  font-size: 11px;
}

/* Mobile — enlarge the slider touch target. The thumb was 24px on a
   28px-tall frame, which left a thin vertical hit zone that was fiddly
   to grab with a finger (reported "budget slider still has issue"). Bump
   the thumb to 28px and the frame to 40px so the effective hit area is
   ~40px tall (the inputs fill 100% height → the whole frame band is the
   grab zone). The two number inputs above remain the PRECISE path; the
   slider is for rough setting on this wide ₹1L–₹50Cr range. */
@media (max-width: 800px) {
  .search-engine-budget-input::-webkit-slider-thumb {
    width: 28px; height: 28px;
  }
  .search-engine-budget-input::-moz-range-thumb {
    width: 28px; height: 28px;
  }
  .search-engine-budget-frame {
    height: 40px;
  }
}

/* Hero-only blocks below the search engine — popular-search chips +
   flywheel stats. Mirror of .ph-hero-search-hints + .ph-hero-stats
   so visual treatment matches the live home hero; renamed so Phase 7
   can delete the .ph- variants without breakage. */
.search-engine-popular-chips {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px;
  margin-top: 5px;
}
.search-engine-popular-chips-eyebrow { color: var(--ink-3); }
.search-engine-popular-chip {
  padding: 4px 10px;
  border: 1px solid var(--line);
  background: var(--paper);
  border-radius: 999px;
  font-size: 11px;
  color: var(--ink-2);
  text-decoration: none;
}
.search-engine-popular-chip:hover {
  border-color: var(--ink-3);
  color: var(--ink);
}

.search-engine-flywheel-stats {
  display: flex; flex-wrap: wrap; gap: 6px;
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px dashed var(--line);
  color: var(--ink-3);
}
.search-engine-flywheel-stats b { color: var(--ink); font-weight: 600; }
.search-engine-flywheel-stat-dot { color: var(--ink-3); }
.search-engine-flywheel-stat-link {
  color: var(--saffron-deep, #d8a35e);
  text-decoration: none;
  margin-left: auto;
}
.search-engine-flywheel-stat-link:hover { text-decoration: underline; }
/* Trailing dot suppression: when the last child before the link is
   a stat-dot, hide it so the row reads `… · X stat · How it works ↗`
   not `… · X stat · · How it works ↗`. */
.search-engine-flywheel-stat-dot:last-of-type {
  display: none;
}

/* Split pane: results + map.
   Default = single-column (mode === 'list'). The map is in DOM but
   hidden via .is-hidden, and the results column takes the full row.
   .ps-split--map-active flips to a 3fr/2fr grid (map LEFT, results
   RIGHT) only when the broker toggles into map mode.
   FIX 2026-05-30: base was 3fr/2fr unconditionally, which left a
   40% empty band on the right of the results in list mode (Noida
   SRP cards appeared offset to the left). The comment block below
   already documented this as the intent — the rule didn't match. */
.ps-split {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
  align-items: start;
}
/* When the map column is hidden via the SRP_MAP_ENABLED feature
   flag, suppress the mobile "Map" toggle button that would have
   opened the (absent) map sheet. The single-column grid is now
   the default on .ps-split, so no grid-template override needed
   here — kept the modifier class for the mobile-button hide. */
.ps-split--no-map .ps-mobile-map-btn { display: none; }

/* Phase 3 (revised) — toggle-gated split-pane.

   Default (mode === 'list'): single-column results, no map.
   When user toggles to map mode, Alpine sets .ps-split--map-active
   on the wrapper. Desktop then shows MAP on the LEFT (~60%) +
   RESULTS on the RIGHT (~40%). Mobile collapses to single-column
   with only the map visible (results column hidden); the map's
   "Back to list" button is the route home. */

.ps-split--map-active {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
  gap: 16px;
  align-items: start;
}
.ps-split--map-active .srp-map {
  position: sticky;
  top: 16px;
  max-height: calc(100vh - 32px);
  min-height: 70vh;
}

/* Element-level hide for the map when mode !== 'map'. CSS class
   used in lieu of x-show because x-show writes inline display:none
   which the desktop grid would otherwise override. */
.is-hidden { display: none !important; }

@media (max-width: 999px) {
  .ps-split { grid-template-columns: 1fr; }
  .ps-split-map { display: none; }
  .ps-split-map.is-mobile-open {
    display: flex;
    position: fixed; inset: 0; z-index: 1200;
    flex-direction: column; padding: 16px; background: var(--paper);
  }
  .ps-split--map-active {
    grid-template-columns: 1fr;
  }
  .ps-split--map-active .srp-map {
    position: static;
    max-height: none;
    min-height: 80vh;
  }
  /* Mobile in map mode: results column hidden, map only.
     The map partial has its own "Back to list" button. */
  .ps-split--map-active .ps-split-results {
    display: none;
  }
}

.ps-split-results {
  display: flex; flex-direction: column; gap: 10px;
}
.ps-results-head {
  display: flex; justify-content: space-between; align-items: center;
  padding: 4px 2px 12px;
  color: var(--ink-3);
  border-bottom: 1px dotted var(--line);
}
.ps-results-head b { color: var(--ink); }

/* ──────────────────────────────────────────────────────────────────
   LEAN-TOP SRP (desktop ≥1000px). Ported + renamed from the approved
   srp-v3 preview. Collapses the dense top chrome into a Redfin/Zillow
   3-row shape. DESKTOP-ONLY: everything here is gated to ≥1000px so the
   shipped srp-v2 mobile chrome is byte-for-byte untouched. The single
   <x-search-engine> form is reflowed in place (never re-mounted); only
   stateless elements (Category dropdown, row-3 bar, end-of-scroll
   intro) are net-new here. Cards stay srp-v2 — no card CSS here.
   ────────────────────────────────────────────────────────────────── */

/* Lean-only elements are hidden below the desktop breakpoint (mobile
   keeps the shipped srp-v2 chrome). MUST sit BEFORE the @media block so
   that at ≥1000px the media rules' display values win on source order
   (equal specificity → later-in-source wins). */
.ps-lean-cat,
.ps-lean-about,
.ps-lean-about-link,
.ps-lean-bhk-only { display: none; }

@media (min-width: 1000px) {

  /* Content that exists for mobile only — hidden on the desktop lean
     top (e.g. the locality intro, which moves to #about-locality). */
  /* Visibility utility — must beat any element `display` (e.g. the
     refine-strip normalization sets .ps-filter-chip{display:inline-flex}
     later in this block, which would otherwise un-hide the decluttered
     RERA/OC/Gated/transaction chips). !important is correct for a
     hide-utility — it always wins. */
  .ps-lean-hide-on-desktop { display: none !important; }
  .ps-lean-about-link { display: inline; }

  /* The search bar + peer tabs scroll away with the page (NOT sticky).
     Only the refine strip below pins (see .ps-filter-strip rule). Just a
     little desktop compaction here. */
  .ps-shell-head { gap: 8px; margin-bottom: 0; padding-top: 8px; }
  .ps-shell-head .ps-tabs { padding-top: 0; }

  /* Refine strip pins under the navbar on scroll. It's a direct child of
     the tall .ps-shell (moved out of .ps-shell-head), so it stays fixed
     throughout the results while the search bar + H1 above scroll off.
     The desktop navbar is a TWO-LINE brand stack (14px pad + 22px wordmark
     + 4px + 18px·1.05 tagline + 14px pad + 1px border ≈ 74px), so pin at
     74px — 60px would let the strip tuck under the navbar. (Mobile keeps
     60px below: its navbar is the slimmer ~54px single-line ROI mark.)
     Opaque background + shadow so cards scroll cleanly underneath. */
  .ps-filter-strip {
    position: sticky;
    top: calc(74px + var(--inset-top));
    z-index: 19; /* sits under the sticky navbar (z-index:20) */
    /* LEFT-CLUSTER the controls — overrides the base justify-content:
       space-between. On this wide full-bleed bar, space-between marooned
       the filters at the far-left and More/Sort at the far-right with a
       huge dead void between them. flex-start groups everything into one
       tidy left-aligned toolbar; the divider on .ps-filter-actions below
       keeps "primary filters | actions" legible. */
    justify-content: flex-start;
    gap: 10px;
    /* Full-bleed band: bg + shadow span edge-to-edge like the navbar while
       the controls stay inset to the page gutter (overflow-x:clip on body
       absorbs the 1px overshoot). Subtle color-mix fill (theme-agnostic:
       nudges --paper a hair toward --ink in BOTH light & dark) + a single
       bottom hairline + soft shadow — reads as one surface without the
       boxy double-border frame the top border gave it at rest. */
    margin: 0 calc(50% - 50vw) 16px;
    padding: 10px calc(50vw - 50%);
    background: color-mix(in oklab, var(--paper) 94%, var(--ink) 6%);
    border-top: none;
    border-bottom: 1px solid var(--line);
    box-shadow: 0 8px 18px -12px rgba(0, 0, 0, 0.30);
  }
  .ps-filter-strip .ps-filter-chips { flex: 0 0 auto; gap: 8px; }
  /* Divider between the primary filter chips and the secondary actions
     (More-filters + Sort) so the left-clustered row still reads grouped. */
  .ps-filter-strip .ps-filter-actions {
    flex: 0 0 auto;
    gap: 10px;
    margin-left: 4px;
    padding-left: 16px;
    border-left: 1px solid var(--line);
  }
  .ps-filter-strip .ps-filter-meta { color: var(--ink-2); font-size: 13px; }

  /* Row 1 — inline the Category dropdown with the search form. The
     search-engine block lays its direct children out as a wrapping flex
     row: [Category ▾] + form share row 1; budget wraps to its own row
     below. (Chips are hidden — see below.) */
  .search-engine--srp-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 12px; }
  .search-engine--srp-bar > .search-engine-tabs { flex: 0 0 auto; }
  .search-engine--srp-bar > .ph-hero-search { flex: 1 1 460px; }

  /* Bedrooms (BHK) picker — desktop-only refine control (residential). */
  .ps-lean-bhk-only { display: inline-flex; }

  /* SUBTYPE / category pills are redundant on desktop — the refine strip
     below already exposes the same sub-axis filters (Subtype ▾, PG
     gender, etc.). Hide the prominent pill row to keep the top lean. */
  .search-engine-chips--srp-bar { display: none; }

  /* The chip strip uses overflow-x:auto (mobile horizontal scroll), which
     also clips overflow-y — cutting off the absolute Budget popover. On
     desktop the (decluttered) chips fit without scrolling, so let overflow
     be visible here and the popover can extend below the strip. */
  .ps-filter-chips { overflow: visible; }

  /* ── 3-up card grid (desktop) ──────────────────────────────────
     The 1-up full-width card was too stretched / info-sparse. On desktop
     show THREE cards per row as vertical cards (photo on top). The card
     markup is already dense (stat tiles + trust + Contact CTA) and stacks
     vertically on its own ≤700px breakpoint — here we just force the
     vertical (single-column) layout at the 3-up width. Mobile (<1000px)
     keeps the shipped srp-v2 single-column list untouched. Buyers list is
     excluded (its own card; buyer SRP is a stub). When the map splits the
     page, the results column is narrow → fall back to one per row. */
  /* Scoped under .ps-split-results so these win over the base
     .ps-results-list / .ps-card--property rules that appear LATER in the
     file (equal specificity → later-in-source would otherwise win). */
  .ps-split-results .ps-results-list:not(.ps-results-list--buyers) {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;   /* three per row on desktop */
    gap: 14px;
  }
  .ps-split--map-active .ps-results-list:not(.ps-results-list--buyers) {
    grid-template-columns: 1fr;
  }
  .ps-split-results .ps-card--property { grid-template-columns: 1fr; }
  /* Drop the per-card Contact CTA on the desktop 3-up grid — the whole
     card is already a link to the listing (where contact lives), so the
     button is redundant and removing it squeezes the cards tighter.
     Mobile srp-v2 keeps its full-width Contact CTA (a shipped element). */
  .ps-split-results .ps-card-cta-row { display: none; }

  /* ── Refine-strip control sizing (desktop) ─────────────────────
     Normalize Budget / Bedrooms / Possession / ROI / More filters / Sort
     to ONE pill size — same height, padding, radius, font — so the strip
     reads as a tidy uniform row (they were 26–40px tall with mixed radii;
     Sort was a square 6px-radius select). Mobile srp-v2 keeps its sizing. */
  .ps-filter-chip,
  .ps-filter-chip-select,
  .ps-lean-budget-trigger {
    min-height: 38px;
    height: 38px;
    box-sizing: border-box;
    border-radius: 999px;
    font-size: 13px; /* fs-input-allow — grouped chip+select rule, follow-up: split + --fs-input-sm */
    display: inline-flex;
    align-items: center;
  }
  .ps-filter-chip,
  .ps-lean-budget-trigger { padding: 0 14px; }
  .ps-filter-chip-select { padding: 0 4px 0 14px; }
  /* select sits flush — the wrapper's min-height + align-center do the
     vertical centering, so kill the input's own vertical padding. */
  .ps-filter-chip-select-input { padding: 0 22px 0 4px; }
  /* Sort is a native <select> — match the pill size without forcing flex
     on a form control (which can render oddly). */
  .ps-filter-sort {
    height: 38px;
    box-sizing: border-box;
    border-radius: 999px;
    font-size: 13px;
    padding: 0 30px 0 14px;
    vertical-align: middle;
  }

  /* Category dropdown — collapses the two-row transaction+category tabs
     into one disclosure. Stateless <a> anchors (no Alpine), so it's safe
     to render alongside the mobile tab rows (which CSS hides ≥1000px). */
  .ps-lean-cat { position: relative; display: inline-block; }
  .ps-lean-cat > summary {
    list-style: none;
    display: inline-flex; align-items: center; gap: 8px;
    /* Match the row-1 city/locality/Search controls' height (~52px,
       from .ph-hero-search-cell's 10px padding + label + input) so the
       Category dropdown doesn't read as a smaller pill. */
    min-height: 52px;
    padding: 0 14px;
    background: var(--ink);
    color: var(--paper);
    border: 1px solid var(--ink);
    border-radius: 8px;
    font-size: 13px; font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
  }
  .ps-lean-cat > summary::-webkit-details-marker { display: none; }
  .ps-lean-cat > summary .ps-lean-cat-caret { font-size: 9px; opacity: 0.7; }
  .ps-lean-cat[open] > summary { border-radius: 8px 8px 0 0; }
  .ps-lean-cat-menu {
    position: absolute;
    top: calc(100% + 6px); left: 0;
    min-width: 280px;
    padding: 8px;
    background: var(--paper);
    border: 1px solid var(--ink);
    border-radius: 10px;
    box-shadow: 0 8px 24px rgba(20, 18, 16, 0.12);
    z-index: 30;
  }
  .ps-lean-cat-group { padding: 4px 0; }
  .ps-lean-cat-group + .ps-lean-cat-group { border-top: 1px solid var(--line); }
  .ps-lean-cat-group-label {
    font-family: var(--mono); font-size: 9px; letter-spacing: 0.08em;
    text-transform: uppercase; color: var(--ink-3);
    padding: 4px 10px 2px;
  }
  .ps-lean-cat-link {
    display: block;
    padding: 7px 10px;
    border-radius: 6px;
    font-size: 13px; color: var(--ink); text-decoration: none;
    white-space: nowrap;
  }
  .ps-lean-cat-link:hover { background: var(--ivory-2, #efe8db); }
  .ps-lean-cat-link.is-active { background: var(--ink); color: var(--paper); font-weight: 600; }

  /* "About {locality} ↓" jump link beside the H1 (desktop only). Hops to
     the end-of-scroll #about-locality block. (No row-3 result-bar: the
     List/Map toggle stays in .ps-results-head to keep the srpMap Alpine
     scope untouched — the map is the fragile bit.) */
  .ps-lean-about-link {
    font-family: var(--mono); font-size: 11px; font-weight: 500;
    color: var(--saffron-deep, #b07d3c);
    text-decoration: none; margin-left: 12px; letter-spacing: 0.02em;
    white-space: nowrap;
  }
  .ps-lean-about-link:hover { text-decoration: underline; }

  /* End-of-scroll "About {locality}" block — the locality intro, moved
     below the cards (Zillow/Redfin convention). Desktop-only; the mobile
     intro stays in its original above-cards position.
     NOTE: the intro prose is intentionally DUPLICATED in the DOM —
     .ps-locality-intro.ps-lean-hide-on-desktop (mobile) AND
     #about-locality.ps-lean-about (desktop). Only one shows per breakpoint.
     Both render the same server-side $intro['html']; keep in sync. If the
     intro ever becomes JS-reactive, refactor to render once + reposition. */
  .ps-lean-about {
    margin: 24px 0 18px;
    padding: 20px 22px;
    background: var(--ivory-2, #efe8db);
    border-radius: 10px;
    scroll-margin-top: calc(140px + var(--inset-top));
  }
  .ps-lean-about-head {
    font-size: 16px; font-weight: 600; margin: 0 0 8px;
    color: var(--ink); letter-spacing: -0.01em;
  }
  .ps-lean-about-body { font-size: 14px; line-height: 1.6; color: var(--ink-2); margin: 0; }

  /* On desktop SRP the two-row tab nav is replaced by the Category
     dropdown above. Scoped to srp-bar so the homepage hero tabs are
     never touched. */
  .search-engine-tabs--srp-bar .search-engine-tabs-row { display: none; }
  /* Re-show the end-of-scroll about block on desktop (the default-hide
     group above sets it to none for mobile; its styling rule sets no
     display). .ps-lean-cat already gets inline-block from its own rule. */
  .ps-lean-about { display: block; }
}

/* ════════════════════════════════════════════════════════════════════
   LEAN-MOBILE PORT (shipped — applies to all SRPs)

   Brings the desktop lean Category dropdown to MOBILE: the .ps-lean-cat
   <details> is the category nav on phones too (a bottom SHEET), and the
   two scrolling tab rows + sub-axis pill row are hidden — so mobile gets
   the same "one nav control + one sticky strip" feel as desktop.

   The .ps-lean-cat dropdown already ships in the srp-bar DOM (it's CSS-
   hidden below 1000px by the base group above); these rules show it and
   supply the visual surface the desktop-only @min-width:1000px block held.
   All .ps-lean-cat VISUAL rules are gated @max-width:999px so they never
   override the desktop absolute-dropdown styling above. The structural
   hides (tab rows / chips / transaction) are unconditional but scoped to
   srp-bar / transaction, so the homepage hero (never renders .ps-lean-cat)
   is untouched and desktop (already hid the rows ≥1000px) is unaffected. */

/* Show the Category dropdown on mobile (the base hide group sets
   .ps-lean-cat{display:none}; this wins on higher specificity). The
   desktop @min-width:1000px rule re-sets display:inline-block + absolute
   positioning, so this is mobile-effective only. */
.ps-lean-cat { position: relative; }

/* Hide the two tab rows + sub-axis pill row for srp-bar — the dropdown
   replaces them at every breakpoint. (Desktop already hid the rows
   ≥1000px; this just extends it down. Homepage hero is mode="hero" and
   never matches --srp-bar, so its tabs are untouched.) */
.search-engine-tabs--srp-bar .search-engine-tabs-row,
.search-engine-chips--srp-bar { display: none !important; }

/* Hide the redundant Transaction (Sale/Rent/Lease) select from the refine
   strip: the Category dropdown's bottom sheet now owns transaction on
   mobile too ("Residential · Buy"), so the strip's transaction chip is a
   duplicate — same reasoning as desktop (.ps-lean-hide-on-desktop). Target
   ONLY the transaction form; the other .ps-lean-hide-on-desktop chips
   (BHK ×-chip, RERA/OC/Gated) stay visible on mobile. */
.ps-filter-chip-select:has(select[name="transaction"]) {
  display: none !important;
}

@media (max-width: 999px) {
  /* Show the dropdown on mobile (base group hid it). */
  .ps-lean-cat { display: inline-flex; }

  /* Summary pill — mirror the desktop dark pill, bumped to the 44px tap
     floor (D3). */
  .ps-lean-cat > summary {
    list-style: none;
    display: inline-flex; align-items: center; gap: 8px;
    min-height: 44px;
    padding: 0 16px;
    background: var(--ink);
    color: var(--paper);
    border: 1px solid var(--ink);
    border-radius: 8px;
    font-size: 14px; font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
  }
  .ps-lean-cat > summary::-webkit-details-marker { display: none; }
  .ps-lean-cat > summary .ps-lean-cat-caret { font-size: 9px; opacity: 0.7; }

  /* Menu surface (the desktop visual base lives in @min-width:1000px, so
     mobile had none) + flip to a fixed bottom sheet like the budget panel
     (mirrors .ps-lean-budget-panel @≤999px). */
  .ps-lean-cat-menu {
    position: fixed;
    /* Clear the fixed .mobile-bottom-nav (64px + home indicator) — same
       fix as the budget sheet, so the lower category rows aren't hidden
       behind the bottom nav. */
    left: 12px; right: 12px; top: auto;
    bottom: var(--bottom-nav-clearance-12);
    min-width: 0; width: auto;
    z-index: 1000;
    max-height: 70dvh; overflow-y: auto;
    padding: 8px;
    background: var(--paper);
    border: 1px solid var(--ink);
    border-radius: 10px;
    box-shadow: 0 -8px 40px -8px rgba(20, 18, 16, 0.3);
  }
  .ps-lean-cat-group { padding: 4px 0; }
  .ps-lean-cat-group + .ps-lean-cat-group { border-top: 1px solid var(--line); }
  .ps-lean-cat-group-label {
    font-family: var(--mono); font-size: 10px; letter-spacing: 0.08em;
    text-transform: uppercase; color: var(--ink-3);
    padding: 6px 10px 4px;
  }
  /* Links to the 44px tap floor (D3) — bigger than the desktop 7px-pad. */
  .ps-lean-cat-link {
    display: flex; align-items: center;
    min-height: 44px;
    padding: 8px 12px;
    border-radius: 6px;
    font-size: 14px; color: var(--ink); text-decoration: none;
    white-space: nowrap;
  }
  .ps-lean-cat-link.is-active { background: var(--ink); color: var(--paper); font-weight: 600; }

  /* ── Refine-strip declutter (lean mobile) ──────────────────────────
     Free vertical space for cards by folding secondary controls into
     the dropdowns / More-filters drawer, leaving the strip as just the
     PRIMARY refine controls: Category ▾ · Bedrooms ▾ · Budget ▾ ·
     Possession ▾ · More filters. */

  /* #1/#3 — show the Bedrooms ▾ select on mobile (was .ps-lean-bhk-only,
     desktop-only). Residential + New Launch (default→residential copy)
     get a real BHK picker instead of only a post-hoc ×-chip. The base
     hide group sets display:none; this re-shows it. */
  .ps-lean-bhk-only { display: inline-flex !important; }

  /* …and hide the now-redundant mobile BHK ×-chip + the RERA/OC/Gated
     toggle chips (#5). All carry .ps-lean-hide-on-desktop and are
     reachable in the More-filters drawer (RERA/OC/Gated) or via the
     Bedrooms select (BHK). Transaction is already hidden separately
     above. This is the same fold the desktop lean does. */
  .ps-filter-chip.ps-lean-hide-on-desktop { display: none !important; }

  /* #4 — fold Sort into the More-filters drawer; hide the strip Sort
     form (.ps-filter-meta) so the actions row is just "+ More filters".
     The drawer's relocated Sort fieldset (.ps-drawer-sort-mobile) is
     shown via its own self-contained rule below. */
  .ps-filter-meta { display: none !important; }

  /* #3 — normalize EVERY refine-strip control to one 44px pill on mobile.
     Pre-fix they were a 40/44/56 mix: Category/Budget were bumped to 44,
     but .ps-filter-chip / .ps-filter-chip-select carried min-height:40 +
     10px padding that (with the wrapped <select>) computed to ~56px. Pin
     all to a flat 44px box with border-box + centered content so the row
     reads as one consistent rhythm (mirrors the desktop 38px normalization
     at L10379). */
  .ps-lean-cat > summary,
  .ps-lean-budget-trigger,
  .ps-filter-chip,
  .ps-filter-chip-select,
  .ps-filter-chip--more {
    min-height: 44px;
    height: 44px;
    box-sizing: border-box;
    padding-top: 0; padding-bottom: 0;
    display: inline-flex; align-items: center;
  }
  /* The native <select> inside the chip-select wrapper must fill the 44px
     so the whole pill is the tap target (not a short select floating in
     a tall box). */
  .ps-filter-chip-select-input {
    /* align-self: stretch; */
    display: inline-flex; align-items: center;
  }

  /* #2 — ONE strip. The base mobile rule stacks the strip as two rows
     (.ps-filter-chips scroller + .ps-filter-actions below). Collapse to a
     single horizontal scroll row so "+ More filters" flows right after
     the last chip (ROI Verified) instead of dropping to its own row.
     display:contents dissolves the two wrapper divs so their children
     (the chips, then the More button) become direct flex items of the
     strip in DOM order: …ROI Verified · + More filters. */
  .ps-filter-strip {
    flex-direction: row;
    flex-wrap: nowrap;
    align-items: center;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    gap: 8px;
  }
  .ps-filter-strip::-webkit-scrollbar { display: none; }
  .ps-filter-chips,
  .ps-filter-actions {
    display: contents;
  }
  /* Keep each pill from being squeezed by the scroller. */
  .ps-filter-strip > .ps-filter-chips > *,
  .ps-filter-strip > .ps-filter-actions > * {
    flex: 0 0 auto;
  }
}

/* Drawer Sort fieldset — mobile-only. Base hides it (desktop keeps Sort
   as a visible strip control, .ps-filter-meta); the @media re-shows it
   ≤999px. Self-contained base-then-media pair so source order is correct
   regardless of the lean block above. */
.ps-drawer-sort-mobile { display: none; }
@media (max-width: 999px) {
  .ps-drawer-sort-mobile { display: block; }
}

/* ── Compact "Budget ▾" dropdown (preview srp-v3 shape) ──────────────
   A refine-strip chip that opens a small popover (number inputs + slim
   slider + Clear/Apply). NOT desktop-gated — it's the single budget
   control on both breakpoints (the panel goes full-width on phones).
   The slim slider reuses the .search-engine-budget-frame/track/input
   rules above. */
.ps-lean-budget { position: relative; display: inline-block; }
/* Budget trigger pill — matches its strip siblings (.ps-filter-chip /
   .ps-filter-chip-select): same border / radius / paper bg / 12px ink-2.
   It's a <button> (was <summary> before the x-teleport rewrite), so
   appearance:none strips the default light button chrome that made it
   read as filled/inconsistent. */
.ps-lean-budget-trigger {
  appearance: none; -webkit-appearance: none;
  list-style: none;
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 38px;
  padding: 0 14px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--paper);
  font-family: inherit;
  font-size: 12px; font-weight: 500; color: var(--ink-2);
  white-space: nowrap; cursor: pointer;
}

/* Teleported overlay (rendered at <body> level via x-teleport, so NO
   overflow/sticky ancestor can clip the fixed panel — the Safari bug).
   Full-screen click-catcher: @click.self closes the panel (standard popover
   dismiss) on BOTH breakpoints — so pointer-events must be auto (was none,
   which is why click-outside had to live on the panel and caused the
   tap-twice race). Desktop: transparent catcher + anchored panel. Mobile:
   dimming backdrop + flush bottom-sheet. */
.ps-lean-budget-overlay {
  position: fixed; inset: 0;
  z-index: 1000;
  pointer-events: auto;
}
.ps-lean-budget-backdrop { display: none; }   /* desktop: no dim layer */

.ps-lean-budget-trigger { cursor: pointer; }
.ps-lean-budget.is-open .ps-lean-budget-trigger { border-color: var(--ink); color: var(--ink); }
.ps-lean-budget-val { font-family: var(--mono); font-size: 11px; color: var(--ink-3); }
.ps-lean-budget-caret { font-size: 11px; color: var(--ink-2); }

.ps-lean-budget-panel {
  /* Teleported to <body>, so position:fixed at the trigger anchor (vars
     set by toggle() from the trigger rect). Re-enable pointer-events that
     the overlay turned off. */
  position: fixed;
  top: var(--anchor-top, 80px); left: var(--anchor-left, 16px);
  pointer-events: auto;
  width: 320px;
  max-width: calc(100vw - 24px);
  padding: 14px;
  background: var(--paper);
  border: 1px solid var(--ink);
  border-radius: 10px;
  box-shadow: 0 8px 24px rgba(20, 18, 16, 0.14);
}
.ps-lean-budget-head {
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.06em;
  /* --ink-3 read faint on the dark mobile panel ("text not visible") —
     lift to --ink-2 for AA-ish contrast on both themes. */
  text-transform: uppercase; color: var(--ink-2); margin: 0 0 8px;
}
.ps-lean-budget-nums { display: flex; gap: 10px; margin-bottom: 12px; }
.ps-lean-budget-num {
  flex: 1; min-width: 0;
  padding: 9px 12px;
  background: var(--ivory-2, #efe8db);
  border: 1px solid var(--line); border-radius: 6px;
  font-family: var(--mono); font-size: 12px; color: var(--ink); outline: none;
}
.ps-lean-budget-num:focus { border-color: var(--ink); background: var(--paper); }

/* Band presets — primary MOBILE budget control. Hidden on desktop (the
   drag-slider is the desktop control); shown ≤999px where the native
   dual-range slider doesn't render reliably on iOS Safari. A tappable
   wrapped grid of pills; one tap sets the range + submits. */
  /* Band presets — shown on BOTH desktop and mobile (quick common picks;
     one tap auto-applies). Desktop ALSO keeps the drag-slider below for
     fine-tuning; mobile hides the slider (iOS-fragile) and relies on
     bands + number inputs. */
.ps-lean-budget-bands {
  display: flex; flex-wrap: wrap; gap: 8px;
  margin-bottom: 10px;
}
.ps-lean-budget-band {
  flex: 0 0 auto;
  min-height: 36px;
  padding: 0 14px;
  display: inline-flex; align-items: center;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 999px;
  font: inherit; font-size: 13px; color: var(--ink-2);
  cursor: pointer;
  white-space: nowrap;
}
.ps-lean-budget-band.is-active {
  background: var(--ink); color: var(--paper); border-color: var(--ink); font-weight: 600;
}
@media (max-width: 999px) {
  /* Mobile: bigger tap target on the bands; hide the drag-slider + axis
     (the iOS-fragile bits). The two ₹ number inputs above stay. */
  .ps-lean-budget-band { min-height: 40px; }
  .ps-lean-budget-bands { margin-bottom: 4px; }
  .ps-lean-budget-panel .search-engine-budget-frame,
  .ps-lean-budget-panel .ps-lean-budget-axis { display: none; }
}

.ps-lean-budget-axis {
  display: flex; justify-content: space-between;
  /* ₹1L … ₹50Cr axis — lifted from --ink-3 10px to --ink-2 11px for
     legibility on the dark panel. */
  font-family: var(--mono); font-size: 11px; color: var(--ink-2);
  margin: 6px 0 12px;
}
.ps-lean-budget-actions {
  display: flex; justify-content: space-between; align-items: center;
  padding-top: 10px; border-top: 1px solid var(--line);
}
.ps-lean-budget-clear {
  background: transparent; border: 0; padding: 0;
  font-family: var(--mono); font-size: 11px; color: var(--ink-3);
  text-decoration: underline; cursor: pointer;
}
.ps-lean-budget-apply {
  padding: 8px 18px;
  background: var(--ink); color: var(--paper);
  border: 0; border-radius: 6px;
  font: inherit; font-size: 12px; font-weight: 600; cursor: pointer;
}
/* Phones: the chip strip is a horizontal scroller (overflow-x:auto), which
   would clip an absolute popover. So on mobile the panel becomes a fixed
   bottom-sheet — it escapes the strip's overflow entirely and is thumb-
   friendly. Desktop keeps the anchored dropdown above. */
@media (max-width: 999px) {
  /* Mobile: the teleported overlay catches taps (backdrop dims the page)
     and the panel is a flush bottom-sheet. */
  .ps-lean-budget-overlay { pointer-events: auto; }
  .ps-lean-budget-backdrop {
    display: block;
    position: fixed; inset: 0;
    z-index: 1000;
    background: rgba(0, 0, 0, 0.4);
  }
  .ps-lean-budget-panel {
    position: fixed;
    /* FLUSH bottom-sheet — pinned to the bottom EDGE of the viewport
       (bottom:0, full-width), like the working More-filters drawer.
       Teleported to <body> so the strip's overflow:auto can't clip it
       (the Safari "invisible until scroll" bug). flush bottom:0 also can't
       drift ~965px down the way the old bottom:calc(64px+…) box did on
       tall iOS viewports. Inner padding-bottom clears the nav/home bar. */
    left: 0; right: 0; bottom: 0; top: auto;
    width: auto;
    max-width: none;
    z-index: 1001;                 /* above the backdrop */
    background: var(--paper);
    border: 1px solid var(--ink);
    border-bottom: none;
    border-radius: 16px 16px 0 0;
    padding-bottom: var(--bottom-nav-clearance-14);
    /* Cap height + scroll. vh fallback FIRST for iOS Safari < 15.4. */
    max-height: 85vh;
    max-height: 85dvh;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    z-index: 1000;
    animation: ps-budget-sheet-up 0.2s cubic-bezier(0.2, 0.8, 0.4, 1);
    box-shadow: 0 -8px 40px -8px rgba(20, 18, 16, 0.3);
  }
  @keyframes ps-budget-sheet-up {
    from { transform: translateY(100%); }
    to   { transform: translateY(0); }
  }
}

.ps-mobile-map-btn {
  display: none;
  align-items: center; gap: 6px;
  padding: 5px 12px;
  border: 1px solid var(--line);
  background: var(--paper);
  border-radius: 999px;
  font-size: 12px;
  color: var(--ink-2);
  cursor: pointer;
  font-family: inherit;
}
@media (max-width: 1000px) {
  .ps-mobile-map-btn { display: inline-flex; }
}

.ps-results-list { display: flex; flex-direction: column; gap: 12px; }
.ps-results-list--buyers { gap: 14px; }

.ps-load-more {
  display: flex; justify-content: center;
  padding: 18px 0;
  border-top: 1px dotted var(--line);
  margin-top: 16px;
}

/* Property card */
.ps-card {
  display: flex; flex-direction: column;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 10px;
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  transition: border-color 0.12s ease, transform 0.12s ease;
}
.ps-card:hover {
  border-color: var(--ink-3);
  transform: translateY(-1px);
}
.ps-card--property { display: grid; grid-template-columns: 260px 1fr; }
@media (max-width: 700px) {
  .ps-card--property { grid-template-columns: 1fr; }
}
.ps-card-photo {
  position: relative;
  aspect-ratio: 16/10;
  background: linear-gradient(135deg, #d8c7a3, #e4d4b3);
  overflow: hidden;
  /* Belt + braces — when the card grid forces a row taller than
     the aspect-ratio's natural height (mobile-stacked layout
     where the body is short), align-self: stretch on the photo
     cell could otherwise distort the box. min-height: 0 lets the
     box collapse to its aspect-ratio-derived height. */
  min-height: 0;
}
.ps-card-photo-img {
  /* Absolute-fill so the image fully covers the photo container
     regardless of how the container's height is computed (grid
     row, aspect-ratio, flex). Naked `width: 100%; height: 100%;
     object-fit: cover;` is unreliable when an ancestor's height
     resolves to `auto`. */
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
}
/* Card photo empty state — always rendered inside .ps-card-photo;
   the <img> overlays this when present. When the img fails (onerror
   hides it), this layer shows through. */
.ps-card-photo-empty {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  color: #5c4a2c;
}
.ps-card-photo-empty svg { opacity: 0.55; }
.ps-card-photo-empty-label {
  color: #7a6244;
  letter-spacing: 0.04em;
}

/* Photo-count overlay — shown when the listing has >1 photo. Sits
   bottom-right opposite the Save heart at top-right. The icon is a
   simple camera glyph; the count uses + prefix so it reads as
   "additional photos beyond the cover". */
.ps-card-photo-count {
  position: absolute;
  bottom: 8px; right: 8px;
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 8px;
  background: rgba(0,0,0,0.65);
  color: var(--paper);
  border-radius: 3px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  pointer-events: none;
}
.ps-card-photo-count svg { opacity: 0.85; }

/* The Save control needs a stable hit-target whether it's an <a>
   (guest) or a <button> in a <form> (auth). The wrap is the form
   element when present. */
.ps-card-save-wrap {
  position: absolute;
  top: 8px; right: 8px;
  margin: 0; padding: 0;
}
.ps-card-save-wrap .ps-card-save {
  position: static;
  margin: 0;
}
.ps-card-save {
  position: absolute; top: 8px; right: 8px;
  width: 32px; height: 32px;
  background: rgba(255,255,255,0.95);
  border: 0; border-radius: 50%;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  color: var(--ink-2);
}
.ps-card-save:hover, .ps-card-save.is-saved { color: var(--saffron-deep, #d8a35e); }
.ps-card-save.is-saved svg { fill: var(--saffron); }

.ps-card-body {
  padding: 14px 16px;
  display: flex; flex-direction: column;
  gap: 8px;
  min-width: 0;  /* allow flex/grid items to shrink below content width */
}

/* Smart label (Phase 2) — single Anthropic-picked controlled-vocab
   token, surfaced as a scannable pill above the title. Sits in its
   own row so it doesn't fight the price baseline. Tone variants
   tint the background by category. */
.ps-card-smart-label-row { display: flex; }
.ps-card-smart-label {
  display: inline-flex;
  align-items: center;
  padding: 2px 9px 3px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  line-height: 1.25;
  background: var(--paper-2, rgba(0, 0, 0, 0.05));
  color: var(--ink);
  border: 1px solid rgba(0, 0, 0, 0.08);
}
/* Tone tints — Mumbai-paper background + ink-tinted text. Kept low
   saturation so it sits behind the price/title hierarchy. */
.ps-card-smart-label--ready {
  background: #e8f4ec;
  color: #1c5a37;
  border-color: rgba(28, 90, 55, 0.18);
}
.ps-card-smart-label--asset {
  background: #ecedf8;
  color: #1f2a6b;
  border-color: rgba(31, 42, 107, 0.18);
}
.ps-card-smart-label--spec {
  background: #eeeef0;
  color: #2a2a2a;
  border-color: rgba(0, 0, 0, 0.12);
}
.ps-card-smart-label--compl {
  background: #fbf2dd;
  color: #6b4a0f;
  border-color: rgba(107, 74, 15, 0.20);
}
.ps-card-smart-label--access {
  background: #e6eef9;
  color: #1c3a6b;
  border-color: rgba(28, 58, 107, 0.18);
}

.ps-card-price-row { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.ps-card-price {
  font-size: 20px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.01em;
  line-height: 1.1;
}
.ps-card-per-sqft { color: var(--ink-3); }
.ps-card-possession {
  margin-left: auto;
  padding: 2px 8px;
  background: var(--ivory-2, rgba(216,163,94,0.12));
  border-radius: 3px;
  color: var(--ink);
  font-weight: 600;
  letter-spacing: 0.02em;
}
.ps-card-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
  line-height: 1.35;
  /* 2-line clamp so wildly long titles don't blow up the card.
     Pair the webkit prefix with the standard line-clamp property
     for forward-compat; both are needed today (webkit covers
     Safari/Chrome, the standard property is starting to ship in
     Firefox 127+). */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Description preview — sits below the title. Subtle, ink-3, smaller
   font so it reads as supporting context not a competing headline.
   Two-line clamp matches the title's clamp; the full text is on the
   PDP. */
.ps-card-desc {
  font-size: 12px;
  color: var(--ink-3);
  line-height: 1.45;
  margin: 0;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Stat tiles — mirrors PDP's pl-hero-stat. Auto-fit so the row
   contains 1, 2, or 3 tiles cleanly. Each tile self-sizes to its
   content; the gap stays consistent. */
.ps-card-stats {
  display: flex; flex-wrap: wrap;
  gap: 6px;
  margin-top: 2px;
}
.ps-card-stat {
  display: flex; flex-direction: column;
  padding: 6px 10px;
  background: var(--ivory-2, rgba(216,163,94,0.10));
  border-radius: 6px;
  min-width: 60px;
}
.ps-card-stat-value {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
  line-height: 1.1;
}
.ps-card-stat-label {
  font-size: 10px;
  color: var(--ink-3);
  margin-top: 2px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* Locality line — small mono with a pin icon. */
.ps-card-locality {
  display: flex; align-items: center; gap: 5px;
  color: var(--ink-2);
  font-size: 11px;
}
.ps-card-locality svg { color: var(--ink-3); flex: 0 0 auto; }

/* Trust cluster — coherent badge row. Each kind gets a tier color
   so the cluster reads as a group rather than a salad of disparate
   pill styles. Compact: 11px, 4-row max wrap. */
.ps-card-trust {
  display: flex; flex-wrap: wrap; gap: 4px;
}
.ps-trust-pill {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  border: 1px solid transparent;
  white-space: nowrap;
}
/* "Just listed" — recency signal. Saffron-bright so a fresh
   listing's pill catches the eye when scanning a page of cards. */
.ps-trust-pill--fresh {
  background: var(--saffron, #ffc14d);
  border-color: var(--saffron-deep, #d8a35e);
  color: #4a3315;
}
.ps-trust-pill--roi {
  background: rgba(207, 19, 34, 0.08);
  border-color: rgba(207, 19, 34, 0.25);
  color: #c01323;
}
.ps-trust-pill--rera {
  background: rgba(34, 113, 60, 0.08);
  border-color: rgba(34, 113, 60, 0.30);
  color: var(--green);
}
.ps-trust-pill--oc {
  background: rgba(34, 113, 60, 0.08);
  border-color: rgba(34, 113, 60, 0.30);
  color: var(--green);
}
/* Freshness pill — renamed from --verified to --refreshed so the
 * "Verified" label is reserved exclusively for ROI Verified brokers. */
.ps-trust-pill--refreshed {
  background: rgba(216,163,94,0.10);
  border-color: rgba(216,163,94,0.40);
  color: #8a5e1f;
}
.ps-trust-pill--gated {
  background: var(--ivory-2, rgba(216,163,94,0.08));
  border-color: var(--line);
  color: var(--ink-2);
}
.ps-trust-pill--negotiable {
  background: var(--ivory-2, rgba(216,163,94,0.08));
  border-color: var(--line);
  color: var(--ink-2);
}

/* Footer — posted timestamp + (cache-only) DB.com mirror tag.
   .ps-card-foot is dead on the property card after the 2026-05-26
   refactor (Posted/Indexed retired); kept here for the buyer-card
   variant below (.ps-card--buyer) which still uses it. */
.ps-card-foot {
  display: flex; align-items: center; gap: 10px;
  color: var(--ink-3);
  margin-top: auto;       /* push to card bottom */
  padding-top: 4px;
}
/* Contact CTA row — single-button row that replaces the old footer
   for property cards. No margin-top: auto so it sits naturally
   under the trust cluster instead of being yanked to the bottom of
   the card and leaving the trust pills floating mid-card. */
.ps-card-cta-row {
  display: flex;
  justify-content: flex-end;
  margin-top: 10px;
}
.ps-card-mirror-tag {
  margin-left: auto;
  padding: 2px 7px;
  background: rgba(0,0,0,0.04);
  border-radius: 3px;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.04em;
  color: var(--ink-3);
  cursor: help;
}
/* When the mirror tag is absent, the contact button takes the
   margin-left:auto slot to push to the right. Using `~` selectors
   would be cleaner but flexbox order works in either order: the
   button comes after the timestamp, the tag (if present) sits
   between. */
.ps-card-contact {
  margin-left: auto;
  display: inline-flex; align-items: center; gap: 5px;
  padding: 5px 12px;
  background: var(--paper);
  border: 1px solid var(--ink-2);
  border-radius: 6px;
  font-size: 11px;
  font-weight: 600;
  font-family: inherit;
  color: var(--ink);
  cursor: pointer;
  letter-spacing: 0.02em;
  transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.ps-card-contact:hover {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}
.ps-card-contact svg { flex: 0 0 auto; }
/* When both the mirror tag and the contact button are present, the
   tag's margin-left:auto wins (it's first in the DOM) and the button
   sits flush to its right. */
.ps-card-mirror-tag + .ps-card-contact { margin-left: 8px; }

/* Page-level H1 above the result list. Larger than the title-tag,
   visually owns the top of the result column. Mirrors the <title>
   tag verbatim so Google sees title↔H1 alignment for the page's
   primary intent token. */
.ps-results-h1 {
  font-size: 20px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.01em;
  line-height: 1.25;
  margin: 10px 0 10px;
}
@media (max-width: 700px) {
  .ps-results-h1 { font-size: 17px; }
}

/* Provenance pills (shared by property + buyer cards) */
.ps-buyer-broker-row {
  display: flex; flex-wrap: wrap; gap: 5px;
  margin-top: 8px;
}
.ps-prov-pill {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 500;
}
.ps-prov-pill .mono { font-size: 9px; opacity: 0.85; }
.ps-prov-pill--roi { background: #1a3d8c; color: #fff; }
.ps-prov-pill--market { background: var(--ivory-2); color: var(--ink-2); border: 1px solid var(--line); }

/* Buyer card foot — distinct from the property-card foot (L6755).
   Scoped to .ps-card--buyer so the property-card layout (flex with
   `margin-top: auto` to push to bottom) isn't overridden. */
.ps-card--buyer .ps-card-foot { color: var(--ink-3); margin-top: 8px; padding-top: 6px; border-top: 1px dotted var(--line); }

/* Buyer card — visually distinct silhouette. The buyer card is NOT a
   link wrapper (unlike property cards) — actions live in the right
   column buttons. Override .ps-card hover so we don't suggest the
   whole card is clickable. */
.ps-card--buyer {
  display: grid;
  grid-template-columns: 100px 1fr 180px;
  background: var(--paper);
  border-left: 3px solid var(--saffron);
  padding: 0;
}
.ps-card--buyer:hover { transform: none; border-color: var(--line); }
@media (max-width: 800px) {
  .ps-card--buyer {
    grid-template-columns: 80px 1fr;
  }
  .ps-buyer-actions { grid-column: 1 / -1; padding: 0 16px 14px; flex-direction: row !important; }
}

.ps-buyer-id {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  background: var(--ivory-2);
  padding: 16px 8px;
  border-right: 1px solid var(--line);
}
.ps-buyer-avatar {
  width: 48px; height: 48px; border-radius: 50%;
  background: linear-gradient(135deg, var(--ink), var(--ink-2));
  color: var(--paper);
  display: flex; align-items: center; justify-content: center;
  font-weight: 600;
  margin-bottom: 8px;
}
.ps-buyer-avatar-initials { font-size: 14px; letter-spacing: 0.04em; }
.ps-buyer-vertical {
  text-align: center;
  color: var(--ink-3);
  letter-spacing: 0.04em;
  line-height: 1.3;
  font-size: 10px;
  text-transform: uppercase;
}

.ps-buyer-body { padding: 14px 16px; display: flex; flex-direction: column; gap: 4px; }
.ps-buyer-headline {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 16px;
  font-weight: 600;
  color: var(--ink);
  flex-wrap: wrap;
}
.ps-buyer-bhk { color: var(--ink); }
/* "→" was the previous connector; now "in" — muted so the BHK + locality
   read as the load-bearing terms and the connector recedes. */
.ps-buyer-arrow { color: var(--ink-3); font-weight: 400; font-size: 14px; }
.ps-buyer-locality { color: var(--ink); }
.ps-buyer-budget {
  font-size: 18px;
  font-weight: 600;
  color: var(--ink);
  margin-top: 2px;
  letter-spacing: -0.01em;
}
.ps-buyer-meta-row { color: var(--ink-3); display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
.ps-buyer-meta-row .dot { color: var(--ink-3); }
.ps-buyer-urgency { color: var(--ink-2); }
.ps-buyer-posted { color: var(--ink-3); }

.ps-buyer-actions {
  display: flex; flex-direction: column; gap: 6px;
  padding: 14px;
  background: var(--ivory-2);
  border-left: 1px solid var(--line);
  justify-content: center;
}
.ps-buyer-cta-primary { width: 100%; }
.ps-buyer-cta-secondary { width: 100%; }

/* Buyer-specific page chrome */
.ps-buyers-banner {
  display: flex; align-items: center; gap: 14px;
  padding: 14px 18px;
  background: linear-gradient(90deg, rgba(255,193,77,0.10), transparent);
  border: 1px solid var(--line);
  border-left: 3px solid var(--saffron);
  border-radius: 8px;
  margin-bottom: 18px;
}
.ps-buyers-banner-icon { color: var(--saffron-deep, #d8a35e); }
.ps-buyers-banner-title { font-weight: 600; color: var(--ink); margin-bottom: 4px; }
.ps-buyers-banner-sub { color: var(--ink-2); font-size: 12px; line-height: 1.5; }
.ps-buyers-footnote { color: var(--ink-3); margin-top: 18px; padding: 12px 16px; border: 1px dashed var(--line); border-radius: 6px; line-height: 1.5; }

/* Map placeholders (split-pane right rail) */
.ps-split-map {
  position: sticky; top: 80px;
  display: flex; flex-direction: column; gap: 6px;
}
.ps-map-placeholder {
  position: relative;
  background:
    radial-gradient(circle at 30% 30%, rgba(255,255,255,0.4) 0%, transparent 30%),
    linear-gradient(135deg, #c8d4d8 0%, #b8c4c8 100%);
  border: 1px solid var(--line);
  border-radius: 10px;
  overflow: hidden;
}
.ps-map-placeholder--split { aspect-ratio: 1 / 1.1; min-height: 400px; }
.ps-map-cluster {
  position: absolute;
  width: 36px; height: 36px;
  border-radius: 50%;
  background: var(--ink);
  color: var(--paper);
  display: flex; align-items: center; justify-content: center;
  font-weight: 600;
  font-size: 13px;
  box-shadow: 0 2px 6px rgba(0,0,0,0.18);
  border: 2px solid var(--paper);
}
.ps-map-cluster--north  { top: 30%; left: 35%; }
.ps-map-cluster--center { top: 52%; left: 52%; }
.ps-map-cluster--south  { top: 68%; left: 38%; }
.ps-map-stub-overlay {
  position: absolute; bottom: 8px; left: 50%; transform: translateX(-50%);
  background: rgba(0,0,0,0.7); color: var(--paper);
  padding: 4px 10px; border-radius: 4px;
  white-space: nowrap;
  max-width: 90%;
  text-align: center;
}
.ps-map-meta {
  display: flex; justify-content: space-between; align-items: center;
  padding: 4px 6px;
  color: var(--ink-3);
}
.ps-map-redo {
  background: transparent; border: 0;
  color: var(--ink-2); font-family: inherit; font-size: 11px;
  cursor: pointer; text-decoration: underline;
}
.ps-mobile-map-close {
  display: none;
  position: absolute; top: 8px; right: 8px;
  width: 32px; height: 32px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 50%;
  cursor: pointer;
  font-size: 18px;
  color: var(--ink);
}
@media (max-width: 1000px) {
  .ps-split-map.is-mobile-open .ps-mobile-map-close { display: block; }
  .ps-split-map.is-mobile-open .ps-map-placeholder { flex: 1; min-height: 0; }
}

/* Heat-map (buyer-side map) */
.ps-map-placeholder--heatmap {
  background:
    radial-gradient(circle at 30% 30%, rgba(255,255,255,0.3) 0%, transparent 30%),
    linear-gradient(135deg, #d8e3d8 0%, #c8d4c8 100%);
}
.ps-heat-blob {
  position: absolute;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(216, 163, 94, 0.7) 0%, rgba(216, 163, 94, 0) 70%);
  display: flex; align-items: center; justify-content: center;
}
.ps-heat-blob--kharadi { width: 200px; height: 200px; top: 30%; left: 30%; }
.ps-heat-blob--wagholi { width: 110px; height: 110px; top: 25%; left: 60%; }
.ps-heat-blob--mundhwa { width: 80px;  height: 80px;  top: 65%; left: 50%; }
.ps-heat-blob-label {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 2px 8px;
  font-size: 11px;
  font-weight: 500;
  color: var(--ink);
  white-space: nowrap;
}

/* Empty state (Housing pattern) */
.ps-empty-state {
  padding: 32px 24px;
  background: var(--ivory-2);
  border: 1px dashed var(--line);
  border-radius: 10px;
  text-align: center;
}
.ps-empty-title { font-size: 18px; font-weight: 600; margin: 0 0 6px; color: var(--ink); }
.ps-empty-sub { color: var(--ink-2); line-height: 1.5; margin: 0; }
.ps-empty-sub a { color: var(--saffron-deep, #d8a35e); text-decoration: underline; }

/* "Post the first listing in {city}" CTA — surfaces below the empty
   state when the whole city has no inventory. Lands brokers from the
   homepage's "coming soon" autocomplete entry onto a useful action. */
.ps-empty-cta {
  margin-top: 16px;
  padding: 24px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 10px;
  text-align: center;
}
.ps-empty-cta-title { font-size: 16px; font-weight: 600; margin: 0 0 6px; color: var(--ink); }
.ps-empty-cta-sub { color: var(--ink-2); line-height: 1.5; margin: 0 0 14px; }
.ps-empty-cta-btn { display: inline-block; }

/* ── Coming-soon empty state (Buyers stub) ── */
.ps-empty-state--coming-soon {
  padding: 64px 24px;
  border-style: solid;
  background: var(--paper);
}
.ps-empty-eyebrow {
  display: inline-block;
  padding: 4px 10px;
  border-radius: 999px;
  background: var(--ivory-2);
  color: var(--ink-3);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  margin-bottom: 18px;
}
.ps-empty-state--coming-soon .ps-empty-title { font-size: 28px; line-height: 1.2; margin-bottom: 12px; }
.ps-empty-state--coming-soon .ps-empty-sub { max-width: 580px; margin: 0 auto 14px; }
.ps-empty-actions {
  display: flex;
  gap: 10px;
  justify-content: center;
  margin-top: 24px;
}

/* ── Section title ── */
.ps-section-title { font-size: 18px; font-weight: 600; color: var(--ink); margin: 0 0 14px; }

/* ── Locality intro paragraph (above results) ── */
.ps-locality-intro {
  margin: 18px 0 22px;
  padding: 18px 20px;
  background: var(--ivory-2);
  border-left: 3px solid var(--saffron, #d8a35e);
  border-radius: 6px;
}

/* ── Sibling-link footer (BHK siblings + intent flip) ── */
.ps-sibling-links {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 18px;
  margin: 28px 0;
  padding: 20px;
  background: var(--ivory-2);
  border-radius: 10px;
}
.ps-sibling-block {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.ps-sibling-block-title {
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.ps-sibling-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.ps-sibling-list li { display: inline; }
.ps-sibling-list a {
  display: inline-block;
  padding: 6px 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink-2);
  text-decoration: none;
  font-size: 13px;
  transition: border-color 0.15s, color 0.15s;
}
.ps-sibling-list a:hover {
  border-color: var(--ink-3);
  color: var(--ink);
}

/* ── FAQ block (visible counterpart to FAQPage JSON-LD).
     Mirrors .ph-faq* pattern from the homepage so the two surfaces feel
     visually consistent. ── */
.ps-faq-section {
  margin: 28px 0 0;
  padding: 24px;
  background: var(--ivory-2);
  border-radius: 12px;
}
.ps-faq-list { display: flex; flex-direction: column; gap: 8px; }
.ps-faq {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 8px;
  overflow: hidden;
}
.ps-faq[open] { border-color: var(--ink-3); }
.ps-faq-q {
  padding: 14px 16px;
  font-weight: 500;
  color: var(--ink);
  cursor: pointer;
  list-style: none;
  user-select: none;
}
.ps-faq-q::-webkit-details-marker { display: none; }
.ps-faq-q::before { content: "+ "; color: var(--ink-3); font-family: var(--mono); }
.ps-faq[open] .ps-faq-q::before { content: "− "; color: var(--ink); }
.ps-faq-a {
  padding: 0 16px 14px;
  color: var(--ink-2);
  line-height: 1.6;
  margin: 0;
  font-size: 13px;
}

/* ── Public Homepage B5.0 (.ph-*) ──────────────────────────────────────
   Front door. SpareRoom-shaped dual-tab hero + demand carousel + trust
   band + AEO footer link farm. Forward-compat: when this locks, port
   verbatim into the production HomeController + home.blade.php. */

.ph-page { display: flex; flex-direction: column; gap: 0; }

/* ── HERO ── */
.ph-hero {
  background:
    radial-gradient(circle at 75% 30%, rgba(255,193,77,0.12) 0%, transparent 45%),
    radial-gradient(circle at 20% 80%, rgba(216,163,94,0.08) 0%, transparent 40%),
    var(--paper);
  border-radius: 16px;
  padding: 32px 24px 28px;
  margin: 0 0 28px;
  border: 1px solid var(--line);
}
@media (max-width: 700px) { .ph-hero { padding: 22px 16px; } }

.ph-hero-inner { max-width: 920px; margin: 0 auto; }

.ph-hero-eyebrow {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
  background: var(--ivory-2);
  padding: 4px 12px;
  border-radius: 999px;
  border: 1px solid var(--line);
}
.ph-hero-eyebrow-dot {
  width: 6px; height: 6px;
  background: var(--saffron-deep, #d8a35e);
  border-radius: 50%;
  display: inline-block;
}
.ph-hero-headline {
  font-family: 'Instrument Serif', Georgia, serif;
  font-size: 44px;
  font-weight: 400;
  line-height: 1.05;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin: 16px 0 8px;
}
/* (the old @max-width:700px {font-size:30px} jump is superseded by the
   clamp() in the HOME LEAN block below) */

/* ════════════════════════════════════════════════════════════════════
   HOME LEAN — Phase 5 mobile hero + hygiene (shipped)

   Fixes the Phase-2 audit's confirmed mobile failures on the homepage's
   conversion surface: hero tabs / search submit / intent chips below the
   48px tap floor, the headline's discrete 30/44px jump (→ clamp), and FAQ
   rows with no min tap height. Content + section order unchanged. Mobile
   rules gated @max-width:700px (the homepage's primary phone breakpoint),
   so desktop is untouched. */

/* Fluid headline — replaces the 30px↔44px jump with a continuous clamp
   so it scales smoothly across phone→desktop (no resize "pop"). Replaces
   the old @max-width:700px {font-size:30px} rule above. */
.ph-hero-headline { font-size: clamp(30px, 7.5vw, 44px); }

@media (max-width: 700px) {
  /* Hero peer tabs — the primary above-fold nav. 36px → 48px tap floor. */
  .ph-hero-tab {
    min-height: 48px;
    padding: 0 14px;
  }

  /* Hero search submit — the above-fold conversion button. ~38 → 48px. */
  .ph-hero-search-submit {
    min-height: 48px;
    padding: 0 22px;
    display: inline-flex; align-items: center; justify-content: center;
  }

  /* Browse-by-intent chips — filter row. ~32 → 44px (dense secondary row,
     44 not 48 to keep the chip rhythm; still clears the floor). */
  .ph-intent-chip {
    min-height: 44px;
    padding: 0 14px;
  }

  /* FAQ question rows — give the <summary> an explicit 48px tap floor
     (was padding-only ~44px, no guaranteed min). */
  .ph-faq-q {
    min-height: 48px;
    display: flex; align-items: center;
  }
}

/* ════════════════════════════════════════════════════════════════════
   HOME LEAN — AI Search + search-engine lean (mobile, shipped)

   Adds the flagship AI Search entry to the mobile home hero (it was hidden
   everywhere on mobile) and leans the hero search the way the SRP was
   leaned: collapse the two category tab rows into the .ps-lean-cat
   bottom-sheet, swap the inline budget slider for the .ps-lean-budget
   band-preset sheet, hide the inline 9-chip filter row, trim popular chips.

   Mobile-only (@max-width:700px). The hero shares the search-engine
   component with the SRP, so the .ps-lean-cat / .ps-lean-budget the hero
   now renders are HIDDEN in hero context by default (the .search-engine
   --hero default-hide rules below) and re-shown only at ≤700px. Desktop
   hero keeps its tab rows + in-row AI pill + inline budget. The SRP uses
   the --srp-bar wrapper, so none of the hero-scoped rules touch it.
   ════════════════════════════════════════════════════════════════════ */

/* AI bar: hidden by default (desktop hero keeps its in-row pill; SRP never
   renders this). Shown full-width on mobile hero only (≤700px below). */
.ph-hero-ai-bar { display: none; }

/* The hero renders .ps-lean-cat + .ps-lean-budget (shared component); they
   must stay hidden on DESKTOP hero (which keeps its tab rows + inline
   budget). Hide them in hero context by default (2-class selector beats
   the global 1-class show rules at ≤999px); the ≤700px block re-shows. */
.search-engine--hero .ps-lean-cat { display: none; }
.search-engine--hero .ps-lean-budget { display: none; }

@media (max-width: 700px) {
  /* ── AI Search — full-width "Describe what you want" bar, the primary
        mobile search affordance. ≥48px. Saffron→violet gradient mirrors
        the desktop .search-engine-ai-pill so it reads as the same feature. */
  .ph-hero-ai-bar {
    display: flex; align-items: center; gap: 8px;
    width: 100%;
    min-height: 48px;
    margin: 10px 0;
    padding: 0 16px;
    background: linear-gradient(135deg,
        color-mix(in oklab, var(--saffron-soft, #fde7c4) 80%, var(--paper)) 0%,
        color-mix(in oklab, #d8c4f5 30%, var(--paper)) 100%);
    border: 1px solid var(--saffron-deep, #b07d3c);
    border-radius: 12px;
    font: inherit; font-size: 14px; font-weight: 600;
    color: var(--ink);
    text-align: left;
    cursor: pointer;
  }
  .ph-hero-ai-bar-spark { flex-shrink: 0; font-size: 16px; }
  .ph-hero-ai-bar-text {
    flex: 1; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    font-weight: 500; color: var(--ink-2);
  }
  .ph-hero-ai-bar-arrow { flex-shrink: 0; color: var(--saffron-deep, #b07d3c); }

  /* ── Category dropdown replaces the two tab rows on mobile hero.
        Scoped to --hero so the SRP (its own --srp-bar rules) is untouched. */
  .search-engine--hero .ps-lean-cat { display: inline-flex; }
  .search-engine--hero .search-engine-tabs-row { display: none; }

  /* ── Budget: the lean .ps-lean-budget band-sheet owns budget on mobile,
        and is the FIRST item in the strip (mounted as the first child of
        .ph-filter-chip-row). Render it as an inline strip item; hide the
        inline Budget chip + its slider panel (iOS-fragile dual-range) to
        avoid a duplicate control. */
  .search-engine--hero .ps-lean-budget { display: inline-flex; flex: 0 0 auto; }
  .search-engine--hero .ph-filter-chip--budget,
  .search-engine--hero .ph-filter-expand:has(.ph-budget-slider) { display: none; }

  /* ── Construction Status folds out of the mobile strip per the requested
        sequence (Budget · Sub Type · Posted By · ROI · More). Hidden here;
        making it selectable in the More-filters drawer is a follow-up. */
  .search-engine--hero .ph-filter-chip--construction { display: none !important; }

  /* ── Category sub-filters STAY on mobile (Bedrooms / Office-type / PG
        gender+sharing / Plot use / Farm type / Coliving brand — swapping
        per category via their x-show — plus ROI Verified + More Filters).
        The chip row becomes a horizontal scroll strip; its inline
        expandable panels (non-budget) drop below the strip as the
        bottom-sheet equivalent. The --hero qualifier (2-class) beats the
        later base `.ph-filter-chip-row{display:flex}` (source order). */
  .search-engine--hero .ph-filter-chip-row {
    display: flex;
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    gap: 8px;
    margin: 0 -16px;            /* bleed to the page gutter */
    padding: 12px 16px;
    border-top: 0;              /* drop the dashed divider on mobile */
  }
  .search-engine--hero .ph-filter-chip-row::-webkit-scrollbar { display: none; }
  /* Each chip ≥44px tap floor + don't squeeze in the scroller. */
  .search-engine--hero .ph-filter-chip-row .ph-filter-chip {
    flex: 0 0 auto;
    min-height: 44px;
  }
  /* The "More Filters" spacer is meaningless in a nowrap scroller. */
  .search-engine--hero .ph-filter-chip-spacer { display: none; }

  /* ── Trim popular chips to ~3 (+ the "Popular:" eyebrow) to save space.
        --hero-qualified for specificity (beats any later base rule). */
  .search-engine--hero .search-engine-popular-chip:nth-of-type(n+4) { display: none; }
}
.ph-hero-headline-em {
  font-style: italic;
  /* Saffron-deep → ink gradient that sweeps L→R every 6s. The text
     fill stays in `color: var(--ink-2)` for fallback (e.g. Edge old)
     but is overridden by the gradient-clipped fill below. Hover
     pauses the sweep so screenshots / screen recordings look clean.
     Reduced-motion: the global guard in the file header zeroes the
     animation duration. */
  background: linear-gradient(
    90deg,
    var(--ink-2) 0%,
    var(--ink-2) 38%,
    var(--saffron-deep, #d8a35e) 50%,
    var(--ink-2) 62%,
    var(--ink-2) 100%
  );
  background-size: 220% auto;
  background-clip: text;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  animation: roi-headline-sweep 6s linear infinite;
}
.ph-hero-headline-em:hover {
  animation-play-state: paused;
}
@keyframes roi-headline-sweep {
  0%   { background-position: 220% center; }
  100% { background-position: -220% center; }
}

/* Fade-up cascade on first paint — the eyebrow, headline, sub-line,
   and tabs reveal in sequence over ~600ms. Each child sets a
   `--delay` custom property to stagger its start. The animation
   itself is short (380ms) so the cascade finishes before the user
   reaches for the search box. */
.ph-hero-fade-up {
  opacity: 0;
  transform: translateY(8px);
  animation: roi-hero-fade-up 380ms ease-out forwards;
  animation-delay: var(--delay, 0ms);
}
@keyframes roi-hero-fade-up {
  to { opacity: 1; transform: translateY(0); }
}

.ph-hero-sub {
  font-size: 15px;
  color: var(--ink-2);
  line-height: 1.5;
  margin: 0 0 24px;
  max-width: 620px;
}
.ph-hero-sub b { color: var(--ink); font-weight: 600; }

/* Hero peer-tabs — "I'm looking for property" vs "I'm looking for
   buyers". Pill-shaped tabs inside an ivory rounded container.
   Active tab fills with ink (charcoal) + white text/icon; inactive
   sits on the container ground (no border, no shadow) so the active
   pill is the unambiguous visual anchor. */
.ph-hero-tabs {
  display: inline-flex;
  gap: 4px;
  background: var(--ivory-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 5px;
  margin: 0 0 5px;
  position: relative;
}
@media (max-width: 700px) { .ph-hero-tabs { width: 100%; } }
.ph-hero-tab {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 20px;
  border: 0;
  background: transparent;
  border-radius: 999px;
  font-family: inherit;
  font-size: 14px;
  color: var(--ink-2);
  cursor: pointer;
  font-weight: 600;
  text-decoration: none;
  transition: background 0.15s, color 0.15s, transform 0.15s;
  position: relative;
}
.ph-hero-tab-icon { flex-shrink: 0; }
.ph-hero-tab:hover { color: var(--ink); }
.ph-hero-tab.is-active {
  background: var(--ink);
  color: var(--paper);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.18);
}
.ph-hero-tab.is-active .ph-hero-tab-icon { color: var(--paper); }
@media (max-width: 700px) {
  .ph-hero-tab { flex: 1; justify-content: center; padding: 9px 14px; }
}

.ph-hero-tab-count {
  font-size: 10px;
  background: var(--ink);
  color: var(--paper);
  padding: 1px 6px;
  border-radius: 999px;
  font-weight: 500;
}
.ph-hero-tab.is-active .ph-hero-tab-count {
  background: var(--saffron);
  color: var(--ink);
}
/* NEW badge — pulls the eye to the buyers tab. Terracotta-deep ground
   with paper-white text, slightly bolder than the surrounding tab
   weight so it reads as a callout, not a count. */
.ph-hero-tab-new {
  font-size: 10px;
  letter-spacing: 0.08em;
  background: var(--terracotta-deep, #c04e2e);
  color: var(--paper);
  padding: 3px 7px;
  border-radius: 4px;
  font-weight: 700;
  line-height: 1;
}
.ph-hero-tab.is-active .ph-hero-tab-new {
  /* Active state — keep terracotta visible against the dark pill */
  background: var(--terracotta, #d8623e);
}


/* Hero search bar */
.ph-hero-search { margin-top: 4px; }
.ph-hero-search-row {
  display: grid;
  grid-template-columns: 180px minmax(0, 1fr) 160px auto;
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: 12px;
  /* `overflow: visible` is critical — the city + locality autocomplete
     dropdowns are absolutely positioned with `top: 100%`, breaking out
     of the row downward. `overflow: hidden` here would clip them despite
     correct DOM/x-show/z-index. The rounded outer-corner look is
     preserved by giving the first cell + the submit button matching
     border-radius (below). */
  overflow: visible;
  align-items: stretch;
}
/* Restore rounded outer corners on the edge cells now that the row no
   longer clips. Inner-cell square corners are intentionally invisible
   under the row's 1px border. */
.ph-hero-search-row > :first-child {
  border-top-left-radius: 12px;
  border-bottom-left-radius: 12px;
}
.ph-hero-search-row > .ph-hero-search-submit {
  border-top-right-radius: 12px;
  border-bottom-right-radius: 12px;
}
@media (max-width: 800px) {
  .ph-hero-search-row {
    grid-template-columns: 1fr;
    gap: 8px;
    background: transparent;
    border: 0;
  }
}
.ph-hero-search-cell {
  display: flex; flex-direction: column;
  background: var(--paper);
  padding: 10px 14px;
  min-width: 0;
}
@media (max-width: 800px) {
  .ph-hero-search-cell {
    border: 1px solid var(--line);
    border-radius: 8px;
  }
}
.ph-hero-search-cell-label {
  font-size: 9px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 4px;
}
.ph-hero-search-cell-input {
  border: 0;
  background: transparent;
  padding: 0;
  font-family: inherit;
  font-size: var(--fs-input);
  color: var(--ink);
  outline: none;
  width: 100%;
}
.ph-hero-search-cell-input::placeholder { color: var(--ink-3); }
.ph-hero-search-submit {
  border-radius: 0;
  font-size: 14px;
  padding: 12px 22px;
  white-space: nowrap;
}
@media (max-width: 800px) { .ph-hero-search-submit { border-radius: 8px; } }

/* Cross-city locality autocomplete — overlay below the locality cell.
   The wrapping cell is position:relative so the dropdown anchors to
   it; on small screens (<800px) the cell is a stacked card with its
   own border, and the dropdown widens to match. */
.ph-hero-locality-ac { position: relative; }
.ph-hero-suggest {
  position: absolute;
  top: 100%;
  left: 0; right: 0;
  z-index: 20;
  margin-top: 4px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: 0 6px 20px rgba(0,0,0,0.08);
  max-height: 320px;
  overflow-y: auto;
  padding: 4px 0;
}
.ph-hero-suggest-loading,
.ph-hero-suggest-empty {
  padding: 10px 14px;
  color: var(--ink-3);
}
.ph-hero-suggest-empty {
  /* Slightly muted from the loading variant; signals a terminal
     state (no results / rate-limited) rather than in-flight. */
  font-style: italic;
}
.ph-hero-suggest-row {
  display: flex; flex-direction: column;
  width: 100%;
  padding: 8px 14px;
  border: 0;
  background: transparent;
  text-align: left;
  font-family: inherit;
  cursor: pointer;
}
.ph-hero-suggest-row:hover,
.ph-hero-suggest-row.is-cursor {
  background: rgba(255,193,77,0.12);
}
.ph-hero-suggest-main {
  font-size: 14px;
  color: var(--ink);
  font-weight: 500;
}
.ph-hero-suggest-sub {
  color: var(--ink-3);
  margin-top: 2px;
}
/* "Coming soon" rows — curated city/locality without inventory yet.
   Muted main label, italicised sub-line so the user immediately sees
   it's a different state from a real result. Still clickable: lands
   on the empty SRP with a "post here" CTA. */
.ph-hero-suggest-row--no-inventory .ph-hero-suggest-main {
  color: var(--ink-2, var(--ink-3));
}
.ph-hero-suggest-row--no-inventory .ph-hero-suggest-sub {
  font-style: italic;
}
/* Google-Places-fallback rows — surfaced when local matchers return
   nothing. Visually distinct from local rows so the user understands
   they're picking a "find this for me" suggestion (server upserts on
   first form submit). Same clickable behaviour as a normal row. */
.ph-hero-suggest-row--places .ph-hero-suggest-sub {
  color: var(--saffron-deep, #d8a35e);
}

/* "No matches" header row — non-pickable, smaller, italic. Sits above
   the metro fallback when typing returned nothing, so the user knows
   the metros aren't a match for what they typed. */
.ph-hero-suggest-row--nomatch {
  cursor: default;
  pointer-events: none;
  padding-top: 6px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--line, rgba(0,0,0,0.06));
}
.ph-hero-suggest-row--nomatch .ph-hero-suggest-main {
  color: var(--ink-3);
  font-style: italic;
  font-weight: 400;
  font-size: 12px;
}

.ph-hero-search-hints {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px;
  margin-top: 10px;
}
.ph-hero-search-hint { color: var(--ink-3); }
.ph-hero-search-chip {
  padding: 4px 10px;
  border: 1px solid var(--line);
  background: var(--paper);
  border-radius: 999px;
  font-size: 11px;
  color: var(--ink-2);
  text-decoration: none;
}
.ph-hero-search-chip:hover { border-color: var(--ink-3); color: var(--ink); }

/* Hero "Or" cross-promo row — twin CTAs that funnel sellers + seekers
   directly into the conversational chatbots when they don't want to
   browse SRPs. Sits below the search form, above flywheel stats.
   Visual: matches .btn-primary (dark on paper), like the navbar's
   "Get started" so visitors recognise these as primary actions. */
.ph-hero-or-actions {
  display: flex; align-items: center; flex-wrap: wrap; gap: 10px;
  margin-top: 14px;
}
.ph-hero-or-actions-divider {
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-right: 2px;
}
.ph-hero-or-cta {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 16px;
  background: var(--ink);
  color: var(--paper);
  border: 0;
  border-radius: 8px;
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
  transition: filter .15s, transform .05s;
}
.ph-hero-or-cta:hover {
  filter: brightness(1.12);
  color: var(--paper);
}
.ph-hero-or-cta:active { transform: scale(0.98); }
.ph-hero-or-cta-icon { font-size: 14px; line-height: 1; opacity: 0.85; }
.ph-hero-or-cta-arrow { margin-left: 2px; font-weight: 700; opacity: 0.85; }

.ph-hero-stats {
  display: flex; flex-wrap: wrap; gap: 6px;
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px dashed var(--line);
  color: var(--ink-3);
}
.ph-hero-stats b { color: var(--ink); font-weight: 600; }
.ph-stat-dot { color: var(--ink-3); }
.ph-hero-stat-link { color: var(--saffron-deep, #d8a35e); text-decoration: none; margin-left: auto; }
.ph-hero-stat-link:hover { text-decoration: underline; }

/* ── Generic section + heading scaffolding ── */
.ph-section { margin: 32px 0; }
.ph-section--two-col {
  display: grid; grid-template-columns: 1fr 1fr; gap: 24px;
}
@media (max-width: 800px) { .ph-section--two-col { grid-template-columns: 1fr; } }

.ph-section-head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;
  margin-bottom: 16px;
}
.ph-section-head--inline { align-items: center; margin-bottom: 12px; }
.ph-section-eyebrow {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.ph-eyebrow-pulse {
  width: 8px; height: 8px;
  background: #355d1f;
  border-radius: 50%;
  box-shadow: 0 0 0 0 rgba(53, 93, 31, 0.7);
  animation: ph-pulse-dot 2s infinite;
}
@keyframes ph-pulse-dot {
  0% { box-shadow: 0 0 0 0 rgba(53, 93, 31, 0.5); }
  70% { box-shadow: 0 0 0 8px rgba(53, 93, 31, 0); }
  100% { box-shadow: 0 0 0 0 rgba(53, 93, 31, 0); }
}
.ph-section-title {
  font-size: 22px; font-weight: 600;
  color: var(--ink);
  margin: 4px 0 4px;
  letter-spacing: -0.01em;
}
.ph-section-title-sm { font-size: 16px; font-weight: 600; color: var(--ink); margin: 0; }
.ph-section-sub { color: var(--ink-3); margin: 0; max-width: 640px; line-height: 1.5; font-size: 13px; }

/* ── Discovery zone — homepage post-hero grids ──────────────────
   Borrows the figure-ground containment from .ph-why--dark (the Why
   ROI section): the destination grids sit inside an ivory-2 slab so
   paper-coloured cards stand out clearly against the contrasting
   background, instead of being a flat-on-flat smear.

   Two visual languages:
   1. Destination cards (.ph-card--metro / .ph-card--locality)
      Paper card on ivory-2 slab. Saffron-deep stat number is the
      load-bearing visual element — same role .ph-why-tile--load-
      bearing plays in the Why ROI grid.
   2. Filter chips (.ph-intent-chip)
      Lower-hierarchy pills with a leading SVG icon. No slab — sits
      directly on the page bg. */
.ph-discovery {
  margin: 24px 0 32px;
}
/* The slab modifier — applied to the metro + locality sections so
   the cards have a contrasting figure-ground. Browse-by-intent
   stays unwrapped (chip rows don't need the container). */
.ph-discovery--slab {
  background: var(--ivory-2);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 24px 22px;
  margin: 24px 0;
}
.ph-discovery--slab .ph-section-head {
  margin-bottom: 14px;
}
.ph-card-grid {
  display: grid;
  gap: 12px;
}
.ph-card-grid--metro {
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.ph-card-grid--locality {
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
}

.ph-card {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 18px 18px 16px;
  /* Card sits on paper (page bg) inside the ivory-2 slab → strong
     figure-ground. Border darker than the default --line so the
     edge is visible at rest. */
  border: 1px solid color-mix(in oklab, var(--ink-3) 35%, var(--line));
  border-radius: 12px;
  text-decoration: none;
  color: var(--ink);
  background: var(--paper);
  position: relative;
  overflow: hidden;
  transition: transform 0.18s ease-out, box-shadow 0.18s ease-out, border-color 0.18s;
}
/* City-card photo treatment — full-card warm-toned skyline behind
   an ivory gradient. Top half stays paper-clean so the city name +
   count read cleanly; lower half reveals the photo at full bleed.
   Per-city WebP at /img/cities/{slug}.webp is set via the
   `--city-photo` custom property below; when unset (locality cards,
   or any city we haven't added a photo for yet) the default
   Indian-skyline SVG renders as a graceful fallback. */
.ph-card--metro::before,
.ph-card--locality::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(180deg,
      var(--paper) 0%,
      color-mix(in oklab, var(--paper) 88%, transparent) 28%,
      color-mix(in oklab, var(--paper) 35%, transparent) 60%,
      transparent 100%),
    var(--city-photo, url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 92 40'><g fill='%23d8a35e'><rect x='2' y='22' width='5' height='18'/><rect x='9' y='14' width='4' height='26'/><rect x='15' y='18' width='8' height='22'/><path d='M15 18 Q19 13 23 18 Z'/><rect x='25' y='24' width='5' height='16'/><rect x='32' y='10' width='6' height='30'/><path d='M32 10 Q35 5 38 10 Z'/><rect x='40' y='18' width='4' height='22'/><rect x='46' y='22' width='10' height='18'/><rect x='58' y='16' width='4' height='24'/><rect x='64' y='12' width='5' height='28'/><path d='M64 12 Q66.5 7 69 12 Z'/><rect x='71' y='20' width='8' height='20'/><rect x='81' y='14' width='4' height='26'/><rect x='87' y='22' width='5' height='18'/></g></svg>"));
  background-repeat: no-repeat, no-repeat;
  background-position: center, center bottom;
  background-size: cover, cover;
  pointer-events: none;
  transition: filter 0.22s ease-out;
}
/* Locality cards stay on the silhouette accent only — photos are
   reserved for the metro grid where the city name carries the
   visual association. */
.ph-card--locality::before {
  background-image:
    linear-gradient(180deg,
      var(--paper) 0%,
      color-mix(in oklab, var(--paper) 90%, transparent) 65%,
      color-mix(in oklab, var(--paper) 60%, transparent) 100%),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 92 40' preserveAspectRatio='xMidYMax meet'><g fill='%23d8a35e' opacity='0.22'><rect x='2' y='22' width='5' height='18'/><rect x='9' y='14' width='4' height='26'/><rect x='15' y='18' width='8' height='22'/><path d='M15 18 Q19 13 23 18 Z'/><rect x='25' y='24' width='5' height='16'/><rect x='32' y='10' width='6' height='30'/><path d='M32 10 Q35 5 38 10 Z'/><rect x='40' y='18' width='4' height='22'/><rect x='46' y='22' width='10' height='18'/><rect x='58' y='16' width='4' height='24'/><rect x='64' y='12' width='5' height='28'/><path d='M64 12 Q66.5 7 69 12 Z'/><rect x='71' y='20' width='8' height='20'/><rect x='81' y='14' width='4' height='26'/><rect x='87' y='22' width='5' height='18'/></g></svg>");
  background-position: center, right -8px bottom -4px;
  background-size: cover, 92px 40px;
}

/* ── Per-city skyline photos ──────────────────────────────────
   One WebP per city, ~1200x675, warm-toned, ~80KB. The card
   slug class drives the variable; the ::before above renders it
   under the ivory gradient. Add a city by dropping a WebP at
   /img/cities/{slug}.webp and adding one line here. */
.ph-card--city-bangalore  { --city-photo: url('/img/cities/bangalore.webp'); }
.ph-card--city-bengaluru  { --city-photo: url('/img/cities/bangalore.webp'); }
.ph-card--city-hyderabad  { --city-photo: url('/img/cities/hyderabad.webp'); }
.ph-card--city-mohali     { --city-photo: url('/img/cities/mohali.webp'); }
.ph-card--city-ahmedabad  { --city-photo: url('/img/cities/ahmedabad.webp'); }
.ph-card--city-mumbai     { --city-photo: url('/img/cities/mumbai.webp'); }
.ph-card--city-noida      { --city-photo: url('/img/cities/noida.webp'); }
.ph-card--city-bhopal     { --city-photo: url('/img/cities/bhopal.webp'); }
.ph-card--city-jaipur     { --city-photo: url('/img/cities/jaipur.webp'); }
.ph-card--city-chennai    { --city-photo: url('/img/cities/chennai.webp'); }
.ph-card--city-pune       { --city-photo: url('/img/cities/pune.webp'); }
/* Delhi NCR alias — same photo, two slugs. */
.ph-card--city-delhi      { --city-photo: url('/img/cities/delhi-ncr.webp'); }
.ph-card--city-delhi-ncr  { --city-photo: url('/img/cities/delhi-ncr.webp'); }
.ph-card--city-new-delhi  { --city-photo: url('/img/cities/delhi-ncr.webp'); }
.ph-card--city-gurgaon    { --city-photo: url('/img/cities/gurgaon.webp'); }
.ph-card--city-gurugram   { --city-photo: url('/img/cities/gurgaon.webp'); }
.ph-card--city-kolkata    { --city-photo: url('/img/cities/kolkata.webp'); }
/* Saffron accent on hover — the bottom-edge line slides in, the
   skyline darkens, the card lifts. Calm in resting state, signal
   on intent. */
.ph-card::after {
  content: '';
  position: absolute;
  left: 16px; right: 16px; bottom: 0;
  height: 2px;
  background: var(--saffron-deep, #d8a35e);
  opacity: 0;
  transform: scaleX(0.4);
  transform-origin: left center;
  transition: opacity 0.18s, transform 0.22s ease-out;
}
.ph-card:hover {
  transform: translateY(-1px);
  border-color: var(--ink-3);
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
}
.ph-card:hover::after {
  opacity: 0.85;
  transform: scaleX(1);
}
.ph-card--metro:hover::before,
.ph-card--locality:hover::before {
  opacity: 0.32;
}
.ph-card-name {
  font-family: var(--serif);
  font-size: 22px;
  font-weight: 500;
  color: var(--ink);
  line-height: 1.18;
  letter-spacing: -0.005em;
  position: relative;
  z-index: 1;
}
/* Lift count above the full-card ::before photo backdrop. .ph-card-meta
   already carries its own z-index; .ph-card-name + count need the same. */
.ph-card-count {
  position: relative;
  z-index: 1;
}
/* Count is the load-bearing stat — Urban-Company-style, count number
   sits ABOVE the unit label and gets the saffron + serif treatment.
   On metro cards the number runs at 28px so it reads at-a-glance
   from across the screen; on locality cards it stays at 22px. The
   "properties" unit hangs below in muted mono, so the visual
   hierarchy reads number → unit → meta. */
.ph-card-count {
  display: flex;
  flex-direction: column;
  line-height: 1.05;
  margin-top: 6px;
  color: var(--ink-3);
}
.ph-card-count strong {
  color: var(--saffron-deep, #d8a35e);
  font-weight: 600;
  font-family: var(--serif);
  font-size: 28px;
  letter-spacing: -0.01em;
}
.ph-card-count-unit {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--ink-3);
  margin-top: 2px;
  text-transform: uppercase;
}
.ph-card--locality .ph-card-count strong {
  font-size: 22px;
}
.ph-card-meta {
  color: var(--ink-2);
  font-size: 12px;
  font-weight: 500;
  margin-top: auto;
  padding-top: 12px;
  position: relative;
  z-index: 1;
}
.ph-card-meta::before {
  content: '★';
  color: var(--saffron-deep, #d8a35e);
  margin-right: 5px;
  font-size: 11px;
}
.ph-card--metro    { min-height: 168px; }
.ph-card--locality { min-height: 128px; }

/* Browse-by-intent chips — flat row, wraps responsively. The
   glyph carries the meaning at-a-glance; the label spells it out. */
.ph-intent-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.ph-intent-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink);
  text-decoration: none;
  font-size: 13px;
  font-weight: 500;
  transition: border-color 0.12s, color 0.12s, background 0.12s;
}
.ph-intent-chip:hover {
  border-color: var(--saffron-deep, #d8a35e);
  background: var(--saffron-soft);
}
.ph-intent-icon {
  display: inline-flex;
  align-items: center; justify-content: center;
  width: 16px; height: 16px;
  color: var(--saffron-deep, #d8a35e);
  flex-shrink: 0;
}
.ph-intent-icon svg {
  width: 100%;
  height: 100%;
}
.ph-intent-chip:hover .ph-intent-icon {
  color: var(--ink);
}
.ph-intent-label {
  color: var(--ink);
}
.ph-section-cta {
  white-space: nowrap;
  color: var(--ink-2);
  text-decoration: none;
  font-size: 13px;
  font-weight: 500;
  padding: 6px 14px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--paper);
}
.ph-section-cta:hover { border-color: var(--ink-3); color: var(--ink); }
.ph-section-cta-sm { color: var(--ink-3); text-decoration: none; font-size: 12px; }
.ph-section-cta-sm:hover { color: var(--ink); }

/* ── Demand band — the differentiator ── */
.ph-demand-band {
  background: linear-gradient(135deg, rgba(255,193,77,0.06) 0%, rgba(216,163,94,0.04) 100%);
  border: 1px solid var(--line);
  border-left: 3px solid var(--saffron);
  border-radius: 12px;
  padding: 20px 22px;
}
.ph-demand-scroll {
  display: flex;
  gap: 10px;
  overflow-x: auto;
  padding: 4px 2px 12px;
  scroll-snap-type: x mandatory;
  margin: 0 -22px;
  padding-left: 22px;
  padding-right: 22px;
}
.ph-demand-card {
  flex: 0 0 240px;
  scroll-snap-align: start;
  display: flex; flex-direction: column;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 14px;
  text-decoration: none;
  color: inherit;
  transition: border-color 0.12s, transform 0.12s;
}
.ph-demand-card:hover {
  border-color: var(--ink-3);
  transform: translateY(-1px);
}
.ph-demand-card-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.ph-demand-card-avatar {
  /* Saffron gradient + serif initials — warmer than the old ink-on-paper
     treatment, which read as a database row. Bigger size lifts the card
     personality so each buyer feels like a person. */
  width: 44px; height: 44px;
  background: linear-gradient(135deg,
    color-mix(in oklab, var(--saffron-deep, #d8a35e) 100%, transparent),
    color-mix(in oklab, var(--saffron-deep, #d8a35e) 65%, var(--paper) 35%));
  color: var(--paper);
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-weight: 600;
  flex-shrink: 0;
  box-shadow: 0 1px 3px rgba(216, 163, 94, 0.22);
}
.ph-demand-card-initials {
  font-family: 'Instrument Serif', Georgia, serif;
  font-size: 16px;
  letter-spacing: 0.01em;
  color: var(--paper);
  font-weight: 500;
}
.ph-demand-card-vertical {
  font-size: 9px;
  color: var(--ink-3);
  letter-spacing: 0.04em;
  line-height: 1.3;
  text-transform: uppercase;
}
.ph-demand-card-bhk { font-size: 14px; font-weight: 600; color: var(--ink); }
.ph-demand-card-locality { font-size: 12px; color: var(--ink-2); margin-top: 4px; line-height: 1.4; }
.ph-demand-card-budget {
  font-size: 16px;
  font-weight: 600;
  color: var(--ink);
  margin-top: 8px;
  letter-spacing: -0.01em;
}
.ph-demand-card-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 6px;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px dotted var(--line);
}
.ph-demand-card-urgency { color: var(--ink-3); font-size: 10px; }

/* CTA card at end of carousel */
.ph-demand-card--cta {
  background: var(--ivory-2);
  border-style: dashed;
  align-items: center; justify-content: center; text-align: center;
  min-height: 180px;
}
.ph-demand-cta-icon {
  width: 40px; height: 40px;
  background: var(--ink);
  color: var(--paper);
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 22px;
  font-weight: 400;
  margin-bottom: 10px;
}
.ph-demand-cta-label { font-size: 13px; font-weight: 600; color: var(--ink); margin-bottom: 4px; }
.ph-demand-cta-sub { color: var(--ink-3); }

/* Provenance pills (homepage variants — slightly smaller) */
.ph-prov-pill {
  display: inline-flex; align-items: center;
  padding: 1px 7px;
  border-radius: 999px;
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.04em;
}
.ph-prov-pill--roi { background: #1a3d8c; color: #fff; }
.ph-prov-pill--market { background: var(--ivory-2); color: var(--ink-2); border: 1px solid var(--line); }
.ph-prov-pill--rera { background: #1a3d1f; color: #d8e8db; }

/* ── Featured projects ── */
.ph-featured-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 12px;
}
.ph-featured-card {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 10px;
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  display: flex; flex-direction: column;
  transition: border-color 0.12s, transform 0.12s;
}
.ph-featured-card:hover { border-color: var(--ink-3); transform: translateY(-1px); }
.ph-featured-photo {
  position: relative;
  aspect-ratio: 16/10;
  background: linear-gradient(135deg, #d8c7a3, #e4d4b3);
}
.ph-photo-placeholder--featured {
  display: flex; align-items: center; justify-content: center;
  height: 100%;
  color: #5c4a2c;
  font-size: 12px;
  font-family: var(--mono);
  letter-spacing: 0.04em;
  padding: 12px;
  text-align: center;
}
.ph-featured-badge { position: absolute; top: 8px; left: 8px; }
.ph-featured-body { padding: 12px 14px; display: flex; flex-direction: column; gap: 4px; }
.ph-featured-name { font-size: 14px; font-weight: 600; color: var(--ink); }
.ph-featured-meta { color: var(--ink-3); }
.ph-featured-price-row {
  display: flex; align-items: center; gap: 8px;
  margin-top: 4px;
  flex-wrap: wrap;
}
.ph-featured-price { font-size: 13px; font-weight: 600; color: var(--ink); }

/* ── Locality + builder lists ── */
.ph-locality-block {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 16px 18px;
}
.ph-locality-list { list-style: none; padding: 0; margin: 0; }
.ph-locality-row {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 0;
  border-bottom: 1px dotted var(--line);
}
.ph-locality-row:last-child { border-bottom: 0; }
.ph-locality-name {
  color: var(--ink); text-decoration: none; font-weight: 500; font-size: 14px;
}
.ph-locality-name:hover { color: var(--saffron-deep, #d8a35e); }
.ph-locality-meta { color: var(--ink-3); margin-top: 2px; }
.ph-locality-arrow { color: var(--ink-3); font-size: 16px; }

/* ── Trust band ── */
.ph-trust-band {
  background: var(--ink);
  color: var(--paper);
  border-radius: 16px;
  padding: 32px 28px;
  margin: 36px 0;
}
.ph-trust-eyebrow {
  display: inline-flex; align-items: center; gap: 8px;
  background: rgba(255,255,255,0.08);
  color: var(--paper);
  padding: 4px 12px;
  border-radius: 999px;
  border: 1px solid rgba(255,255,255,0.18);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.ph-trust-eyebrow-icon { color: var(--saffron); }
.ph-trust-headline {
  font-family: 'Instrument Serif', Georgia, serif;
  font-size: 28px;
  font-weight: 400;
  line-height: 1.1;
  margin: 14px 0 24px;
  color: var(--paper);
}
@media (max-width: 700px) { .ph-trust-headline { font-size: 22px; } }
.ph-trust-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px;
  margin-bottom: 24px;
}
@media (max-width: 800px) { .ph-trust-grid { grid-template-columns: repeat(2, 1fr); } }
.ph-trust-tile {
  background: rgba(255,255,255,0.05);
  border: 1px solid rgba(255,255,255,0.1);
  border-radius: 10px;
  padding: 16px 18px;
}
.ph-trust-tile--differentiator {
  background: rgba(255,193,77,0.15);
  border-color: var(--saffron);
}
.ph-trust-tile-value { font-size: 28px; font-weight: 600; line-height: 1.05; letter-spacing: -0.02em; }
.ph-trust-tile-label { font-size: 12px; color: rgba(255,255,255,0.85); margin-top: 4px; }
.ph-trust-tile-meta { color: rgba(255,255,255,0.5); margin-top: 6px; line-height: 1.5; font-size: 10px; }
.ph-trust-pillars {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px;
}
@media (max-width: 800px) { .ph-trust-pillars { grid-template-columns: 1fr; gap: 12px; } }
.ph-trust-pillar {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 12px;
  background: rgba(255,255,255,0.03);
  border-radius: 8px;
}
.ph-trust-pillar-icon { font-size: 22px; flex-shrink: 0; }
.ph-trust-pillar-title { font-weight: 600; color: var(--paper); margin-bottom: 4px; font-size: 13px; }
.ph-trust-pillar-sub { color: rgba(255,255,255,0.7); font-size: 12px; line-height: 1.5; }

/* ── Tools ── */
.ph-tools-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 10px;
}
.ph-tool-card {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 14px;
  text-decoration: none;
  color: inherit;
  transition: border-color 0.12s;
}
.ph-tool-card:hover { border-color: var(--ink-3); }
.ph-tool-icon { font-size: 22px; margin-bottom: 8px; }
.ph-tool-name { font-size: 13px; font-weight: 600; color: var(--ink); }
.ph-tool-desc { color: var(--ink-3); margin-top: 2px; }
.ph-tools-note {
  margin-top: 10px;
  color: var(--ink-3);
  padding: 8px 12px;
  background: var(--ivory-2);
  border-radius: 6px;
  border: 1px dashed var(--line);
}

/* ── FAQ ── */
.ph-faq-section {
  background: var(--ivory-2);
  border-radius: 12px;
  padding: 24px;
}
/* Speakable region — the top 2 Q/A pairs voice assistants quote
   directly. Saffron-tinted card visually signals "load-bearing
   first answers" + breaks the wall-of-text FAQ stack. */
.ph-faq-speakable {
  background: color-mix(in oklab, var(--saffron-deep, #d8a35e) 5%, var(--paper));
  border: 1px solid color-mix(in oklab, var(--saffron-deep, #d8a35e) 38%, var(--line));
  border-radius: 12px;
  padding: 18px 20px;
  margin-bottom: 14px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.ph-faq-speakable .ph-faq--static {
  border: 0;
  background: transparent;
  padding: 0;
  border-radius: 0;
  overflow: visible;
}
.ph-faq-speakable .ph-faq-q {
  font-size: 16px;
  margin: 0 0 4px;
  padding: 0;
  cursor: default;
}
.ph-faq-speakable .ph-faq-q::before { content: ""; }
.ph-faq-speakable .ph-faq-a {
  padding: 0;
  font-size: 14px;
}
.ph-faq-list { display: flex; flex-direction: column; gap: 8px; }
.ph-faq {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 8px;
  overflow: hidden;
}
.ph-faq[open] { border-color: var(--ink-3); }
.ph-faq-q {
  padding: 14px 16px;
  font-weight: 500;
  color: var(--ink);
  cursor: pointer;
  list-style: none;
  user-select: none;
}
.ph-faq-q::-webkit-details-marker { display: none; }
.ph-faq-q::before { content: "+ "; color: var(--ink-3); font-family: var(--mono); }
.ph-faq[open] .ph-faq-q::before { content: "− "; color: var(--ink); }
.ph-faq-a {
  padding: 0 16px 14px;
  color: var(--ink-2);
  line-height: 1.6;
  margin: 0;
  font-size: 13px;
}

/* ── Footer SEO link farm ── */
.ph-footer-seo {
  background: var(--paper);
  border-top: 1px solid var(--line);
  margin: 36px -20px 0;
  padding: 28px 24px;
}
.ph-footer-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 24px;
}
@media (max-width: 900px) { .ph-footer-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 600px) { .ph-footer-grid { grid-template-columns: 1fr; } }
.ph-footer-col {}
.ph-footer-col--differentiator {
  background: linear-gradient(180deg, rgba(255,193,77,0.06) 0%, transparent 60%);
  border-left: 2px solid var(--saffron);
  padding-left: 12px;
  margin-left: -14px;
}
.ph-footer-col-flag {
  display: inline-block;
  background: var(--saffron);
  color: var(--ink);
  padding: 1px 6px;
  border-radius: 3px;
  font-size: 9px;
  letter-spacing: 0.04em;
  margin-right: 6px;
  font-weight: 700;
}
.ph-footer-col-title {
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 10px;
  display: block;
}
.ph-footer-col-list {
  list-style: none; padding: 0; margin: 0;
  display: flex; flex-direction: column; gap: 6px;
}
.ph-footer-col-list a {
  color: var(--ink-2); text-decoration: none; font-size: 13px;
}
.ph-footer-col-list a:hover { color: var(--saffron-deep, #d8a35e); text-decoration: underline; }
.ph-footer-col-meta { color: var(--ink-3); margin-top: 10px; line-height: 1.5; font-size: 11px; }
.ph-footer-meta {
  margin-top: 22px;
  padding-top: 16px;
  border-top: 1px dotted var(--line);
  color: var(--ink-3);
  text-align: center;
  font-size: 11px;
}

/* ── Homepage v2 (seeker-first restructure, brand brief 2026-04-30) ─────
   Adds: hero foot row (no tabs), Problem, How it works, Why ROI (4 pillars),
   slim demand band, For Brokers, For Owners, Trust strip, Final CTA,
   Footer tagline. Older .ph-hero-tabs* / .ph-hero-stats / .ph-trust-band
   classes above are unused but left in place for diffability. */

/* Hero — restyled foot row replacing the popular-search chips strip */
.ph-hero-search-foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
  margin-top: 12px;
}
.ph-hero-secondary {
  color: var(--ink-3);
}
.ph-hero-secondary a {
  color: var(--ink-2);
  font-weight: 500;
  text-decoration: none;
  margin-right: 4px;
}
.ph-hero-secondary a:hover { color: var(--ink); text-decoration: underline; }
.ph-hero-secondary-meta { color: var(--ink-3); }
.ph-hero-search-private {
  color: var(--ink-2);
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px;
  background: rgba(53, 93, 31, 0.08);
  border-radius: 999px;
  border: 1px solid rgba(53, 93, 31, 0.2);
}
.ph-hero-search-private b { color: #355d1f; font-weight: 600; }

.ph-hero-search-cell--intent { /* same shape as city cell */ }

/* §2 Problem — "WHY ROI EXISTS" comparison section.
   Two-column phone-journey contrast (other portals vs ROI). Each
   column carries a numbered timeline with a dashed vertical
   connector between steps; selected steps surface a small badge
   pill ("87% MATCH", "STILL ANONYMOUS", "YOU STAY IN CONTROL").
   Replaced the older quote-glyph aesthetic per 2026-05-22 user
   direction. The .ph-problem-h2 / .ph-problem-h2-em / .ph-problem-body
   class names from the prior section are kept where reused, but the
   ::before quote-glyph and the .ph-problem-pivot pull-quote are gone. */
.ph-problem {
  padding: 96px 24px;
  text-align: center;
  background: var(--ivory);
  position: relative;
  /* Rounded outer corners so the slab reads as a "card" against the
     dark page in dark mode (mirrors the .ph-persist treatment a few
     sections below). In light mode the rounded corners + border still
     read cleanly against the page's own ivory ground. */
  border-radius: 18px;
  overflow: hidden;
}
@media (max-width: 880px) {
  .ph-problem { border-radius: 14px; }
}
.ph-problem-inner {
  max-width: 1080px;
  margin: 0 auto;
}
.ph-problem-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  font-size: 12px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--terracotta-deep, var(--saffron-deep, #c04e2e));
  font-weight: 600;
  margin: 0 0 28px;
}
.ph-problem-eyebrow::before {
  content: "";
  display: inline-block;
  width: 28px;
  height: 1px;
  background: var(--terracotta-deep, var(--saffron-deep, #c04e2e));
}
.ph-problem-h2 {
  font-family: 'Instrument Serif', Georgia, serif;
  font-size: 44px;
  font-weight: 400;
  line-height: 1.12;
  letter-spacing: -0.02em;
  color: var(--ink);
  margin: 0 auto 22px;
  max-width: 800px;
}
.ph-problem-h2-em {
  font-style: italic;
  color: var(--ink);
}
.ph-problem-sub {
  font-size: 17px;
  line-height: 1.55;
  color: var(--ink-2);
  margin: 0 auto 56px;
  max-width: 600px;
}

/* Two-column contrast container */
.ph-problem-vs {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;
  max-width: 1000px;
  margin: 0 auto;
  background: var(--ivory-2);
  border-radius: 18px;
  padding: 44px 32px;
  text-align: left;
}
.ph-problem-vs-col {
  padding: 0 28px;
  position: relative;
}
.ph-problem-vs-col + .ph-problem-vs-col {
  border-left: 1px solid color-mix(in oklab, var(--ink-3) 18%, transparent);
}
.ph-problem-vs-eyebrow {
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin: 0 0 8px;
  font-weight: 600;
}
.ph-problem-vs-col--signal .ph-problem-vs-eyebrow {
  color: var(--terracotta-deep, var(--saffron-deep, #c04e2e));
}
.ph-problem-vs-title {
  font-family: 'Instrument Serif', Georgia, serif;
  font-style: italic;
  font-size: 22px;
  font-weight: 400;
  color: var(--ink);
  line-height: 1.3;
  margin: 0 0 32px;
}

/* Numbered timeline steps */
.ph-problem-steps {
  list-style: none;
  margin: 0;
  padding: 0;
  position: relative;
}
.ph-problem-step {
  display: grid;
  grid-template-columns: 32px 1fr;
  gap: 16px;
  margin-bottom: 28px;
  position: relative;
}
.ph-problem-step:last-child {
  margin-bottom: 0;
}
.ph-problem-step::before {
  /* Dashed vertical connector between numbered circles */
  content: "";
  position: absolute;
  left: 15px;
  top: 32px;
  bottom: -28px;
  border-left: 1px dashed color-mix(in oklab, var(--ink-3) 30%, transparent);
}
.ph-problem-step:last-child::before {
  display: none;
}
.ph-problem-step-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 999px;
  background: var(--paper);
  border: 1px solid color-mix(in oklab, var(--ink-3) 22%, transparent);
  color: var(--ink-3);
  font-size: 12px;
  font-weight: 500;
  position: relative;
  z-index: 1;
  flex-shrink: 0;
}
.ph-problem-vs-col--signal .ph-problem-step-num {
  background: var(--terracotta-deep, var(--saffron-deep, #c04e2e));
  color: var(--paper);
  border-color: transparent;
}
.ph-problem-step-title {
  font-size: 16px;
  font-weight: 600;
  color: var(--ink);
  line-height: 1.3;
  margin: 4px 0 6px;
}
.ph-problem-step-body {
  font-size: 14px;
  line-height: 1.55;
  color: var(--ink-2);
  margin: 0;
}
.ph-problem-step-badge {
  display: inline-block;
  margin-top: 10px;
  padding: 4px 9px;
  border-radius: 4px;
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 600;
  line-height: 1;
}
.ph-problem-vs-col--noise .ph-problem-step-badge {
  background: var(--ivory);
  color: var(--ink-3);
  border: 1px solid color-mix(in oklab, var(--ink-3) 18%, transparent);
}
.ph-problem-vs-col--signal .ph-problem-step-badge {
  background: color-mix(in oklab, var(--terracotta-deep, var(--saffron-deep, #c04e2e)) 14%, var(--paper));
  color: var(--terracotta-deep, var(--saffron-deep, #c04e2e));
}
.ph-problem-step-badge--solid {
  background: var(--ink) !important;
  color: var(--paper) !important;
  border-color: var(--ink) !important;
}

/* Footer tagline — bilingual signature */
.ph-problem-footer {
  margin: 64px auto 0;
  max-width: 800px;
}
.ph-problem-footer-title {
  font-family: 'Instrument Serif', Georgia, serif;
  font-style: italic;
  font-size: 28px;
  font-weight: 400;
  line-height: 1.3;
  color: var(--ink);
  margin: 0 0 12px;
}
.ph-problem-footer-title em {
  color: var(--terracotta-deep, var(--saffron-deep, #c04e2e));
  font-style: italic;
  font-weight: 500;
}
.ph-problem-footer-sub {
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-3);
  font-weight: 600;
  margin: 0;
}

@media (max-width: 880px) {
  .ph-problem { padding: 64px 18px; }
  .ph-problem-h2 { font-size: 30px; }
  .ph-problem-sub { font-size: 15px; margin-bottom: 36px; }
  .ph-problem-vs {
    grid-template-columns: 1fr;
    padding: 28px 8px;
  }
  .ph-problem-vs-col {
    padding: 0 16px;
  }
  .ph-problem-vs-col + .ph-problem-vs-col {
    border-left: none;
    border-top: 1px solid color-mix(in oklab, var(--ink-3) 18%, transparent);
    margin-top: 32px;
    padding-top: 32px;
  }
  .ph-problem-footer-title { font-size: 22px; }
}

/* Visual contrast — 14,000 (faded) vs 3 (saffron-deep, bold). Breaks
   the prose wall between the spam-calls paragraph and the pivot
   pull-quote. Anchors the "noise → signal" thesis as an image, not
   just a sentence. */
.ph-problem-contrast {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  margin: 8px auto 0;
  max-width: 460px;
}
.ph-problem-contrast-cell {
  flex: 1;
  padding: 16px 14px;
  border-radius: 10px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-items: center;
  text-align: center;
  border: 1px solid var(--line);
  background: var(--paper);
}
.ph-problem-contrast-cell--noise {
  color: var(--ink-3);
  opacity: 0.72;
}
.ph-problem-contrast-cell--signal {
  color: var(--saffron-deep, #d8a35e);
  border-color: color-mix(in oklab, var(--saffron-deep, #d8a35e) 55%, var(--line));
  background: color-mix(in oklab, var(--saffron-deep, #d8a35e) 5%, var(--paper));
}
.ph-problem-contrast-num {
  font-family: 'Instrument Serif', Georgia, serif;
  font-size: 38px;
  line-height: 1;
  font-weight: 500;
  letter-spacing: -0.01em;
}
.ph-problem-contrast-cell--signal .ph-problem-contrast-num {
  font-weight: 600;
}
.ph-problem-contrast-label {
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.ph-problem-contrast-vs {
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  flex-shrink: 0;
}
@media (max-width: 560px) {
  .ph-problem-contrast { gap: 8px; }
  .ph-problem-contrast-num { font-size: 30px; }
  .ph-problem-contrast-cell { padding: 12px 10px; }
}

/* §3 How it works */
.ph-how-head { margin-bottom: 32px; max-width: 720px; }
.ph-how-eyebrow {
  display: inline-flex; align-items: center; gap: 12px;
  letter-spacing: 0.18em; text-transform: uppercase;
  font-weight: 700; color: var(--ink);
  margin-bottom: 16px;
}
.ph-how-eyebrow::before {
  content: ""; width: 28px; height: 2px; background: var(--terracotta, var(--saffron-deep));
}
.ph-how-sub {
  font-size: 16px; line-height: 1.55;
  color: var(--ink-2);
  max-width: 36rem;
  margin: 12px 0 0;
}
.ph-how-grid {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px;
}
@media (max-width: 800px) { .ph-how-grid { grid-template-columns: 1fr; } }
.ph-how-step {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 22px 20px;
  position: relative;
}
.ph-how-step--engine {
  background: linear-gradient(180deg, rgba(255,193,77,0.08) 0%, var(--paper) 60%);
  border-color: rgba(216,163,94,0.4);
}
.ph-how-step-icon {
  width: 44px; height: 44px;
  background: var(--ivory-2);
  border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  color: var(--ink);
  margin-bottom: 12px;
}
.ph-how-step--engine .ph-how-step-icon {
  background: var(--saffron);
  color: var(--ink);
}
.ph-how-step-num {
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 4px;
}
.ph-how-step-title {
  font-size: 16px;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 8px;
}
.ph-how-step-body {
  margin: 0;
  color: var(--ink-2);
  font-size: 14px;
  line-height: 1.55;
}
.ph-how-step-body b { color: var(--ink); font-weight: 600; }

/* §4 Why ROI */
.ph-why-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 14px;
}
@media (max-width: 700px) { .ph-why-grid { grid-template-columns: 1fr; } }
.ph-why-tile {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 22px 22px;
}
.ph-why-tile--load-bearing {
  background: linear-gradient(135deg, rgba(255,193,77,0.06) 0%, rgba(216,163,94,0.04) 100%);
  border-color: rgba(216,163,94,0.4);
}
.ph-why-icon {
  font-size: 26px;
  margin-bottom: 10px;
  width: 44px; height: 44px;
  background: var(--ivory-2);
  border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
}
.ph-why-tile--load-bearing .ph-why-icon { background: var(--saffron); }
.ph-why-title {
  font-size: 16px;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 8px;
  line-height: 1.3;
}
.ph-why-body {
  margin: 0;
  color: var(--ink-2);
  font-size: 14px;
  line-height: 1.55;
}
.ph-why-body b { color: var(--ink); font-weight: 600; }

/* §5 Slim demand band — overrides earlier full-carousel styles */
.ph-demand-band--slim { padding: 18px 22px; }
.ph-demand-slim-row {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) auto;
  align-items: center;
  gap: 18px;
}
@media (max-width: 1000px) {
  .ph-demand-slim-row { grid-template-columns: 1fr; gap: 14px; }
}
.ph-demand-slim-text { min-width: 0; }
.ph-demand-slim-headline {
  margin: 6px 0 0;
  color: var(--ink);
  font-size: 14px;
  line-height: 1.55;
  max-width: 460px;
}
.ph-demand-slim-headline b { color: var(--ink); font-weight: 700; }
.ph-demand-slim-chips {
  display: flex; gap: 8px;
  overflow-x: auto;
  padding: 2px 0;
}
.ph-demand-chip {
  flex: 0 0 auto;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 10px 12px;
  min-width: 130px;
}
.ph-demand-chip-bhk {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink);
}
.ph-demand-chip-locality {
  color: var(--ink-3);
  margin-top: 2px;
}
.ph-demand-chip-budget {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
  margin-top: 6px;
  letter-spacing: -0.01em;
}
.ph-demand-chip-urgency {
  color: var(--ink-3);
  margin-top: 4px;
  font-size: 10px;
}
.ph-demand-slim-link {
  white-space: nowrap;
  color: var(--ink-2);
  text-decoration: none;
  font-size: 13px;
  font-weight: 500;
  padding: 8px 14px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--paper);
}
.ph-demand-slim-link:hover { border-color: var(--ink-3); color: var(--ink); }

/* §6 For Brokers */
.ph-broker-block {
  background: var(--ivory-2);
  border-radius: 16px;
  padding: 32px 28px;
  margin: 36px 0;
}
.ph-broker-block-inner { max-width: 880px; margin: 0 auto; }
.ph-broker-block-eyebrow {
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 6px;
}
.ph-broker-block-h2 {
  font-family: 'Instrument Serif', Georgia, serif;
  font-size: 28px;
  font-weight: 400;
  color: var(--ink);
  margin: 0 0 20px;
  letter-spacing: -0.01em;
}
@media (max-width: 700px) { .ph-broker-block-h2 { font-size: 22px; } }
.ph-broker-block-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 14px;
}
@media (max-width: 700px) { .ph-broker-block-grid { grid-template-columns: 1fr; } }
.ph-broker-tier {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 20px 22px;
  display: flex; flex-direction: column;
}
.ph-broker-tier--verified {
  background: linear-gradient(180deg, rgba(255,193,77,0.10) 0%, var(--paper) 60%);
  border-color: rgba(216,163,94,0.5);
  position: relative;
}
.ph-broker-tier-head {
  display: flex; align-items: baseline; justify-content: space-between;
  margin-bottom: 14px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--line);
}
.ph-broker-tier-name {
  font-size: 15px;
  font-weight: 600;
  color: var(--ink);
}
.ph-broker-tier-price {
  font-size: 18px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.01em;
}
.ph-broker-tier-price-unit {
  font-size: 12px;
  font-weight: 400;
  color: var(--ink-3);
  letter-spacing: 0;
}
.ph-broker-tier-list {
  list-style: none; padding: 0; margin: 0 0 18px;
  display: flex; flex-direction: column; gap: 8px;
  color: var(--ink-2);
  font-size: 14px;
  line-height: 1.5;
  flex: 1;
}
.ph-broker-tier-list li {
  padding-left: 22px;
  position: relative;
}
.ph-broker-tier-list li::before {
  content: "✓";
  position: absolute;
  left: 0; top: 0;
  color: #355d1f;
  font-weight: 700;
}
.ph-broker-tier-list--plus li:first-child {
  padding-left: 0;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 4px;
}
.ph-broker-tier-list--plus li:first-child::before { content: ""; }
.ph-broker-tier-cta { width: 100%; }

/* Accordion for less-prominent features. Keeps the visible card to
   a digestible 2-3 line list while preserving access to everything
   for buyers who want depth. Reads as a mono "+ N more" cue. */
.ph-broker-tier-more {
  margin: 4px 0 12px;
  border-top: 1px dashed var(--line);
  padding-top: 8px;
}
.ph-broker-tier-more > summary {
  list-style: none;
  cursor: pointer;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--ink-3);
  padding: 4px 0;
  user-select: none;
}
.ph-broker-tier-more > summary::-webkit-details-marker { display: none; }
.ph-broker-tier-more > summary::after {
  content: " ↓";
  color: var(--ink-3);
  font-family: inherit;
}
.ph-broker-tier-more[open] > summary { color: var(--ink-2); }
.ph-broker-tier-more[open] > summary::after { content: " ↑"; color: var(--ink-2); }
.ph-broker-tier-more .ph-broker-tier-list {
  margin: 6px 0 0;
}
.ph-broker-block-foot {
  text-align: center;
  color: var(--ink-3);
  margin: 18px 0 0;
}
.ph-broker-block-quick {
  text-align: center;
  color: var(--ink-3);
  margin: 8px 0 0;
}
.ph-broker-block-quick a {
  color: var(--accent, #c0392b);
  text-decoration: none;
  font-weight: 600;
}
.ph-broker-block-quick a:hover { text-decoration: underline; }

/* §7 For Owners */
.ph-owner-row {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 22px 26px;
  margin: 36px 0;
}
.ph-owner-row-inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 24px;
}
@media (max-width: 700px) {
  .ph-owner-row-inner { grid-template-columns: 1fr; }
  .ph-owner-cta { width: 100%; }
}
.ph-owner-eyebrow {
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 4px;
}
.ph-owner-h2 {
  font-size: 18px;
  font-weight: 600;
  color: var(--ink);
  margin: 0 0 6px;
}
.ph-owner-body {
  margin: 0;
  color: var(--ink-2);
  font-size: 14px;
  line-height: 1.55;
  max-width: 540px;
}

/* §8 Trust signals strip — slim horizontal */
.ph-trust-strip {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
  padding: 22px 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
@media (max-width: 800px) { .ph-trust-strip { grid-template-columns: repeat(2, 1fr); } }
.ph-trust-strip-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 6px 8px;
}
.ph-trust-strip-icon { font-size: 22px; flex-shrink: 0; }
.ph-trust-strip-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
}
.ph-trust-strip-meta {
  color: var(--ink-3);
  margin-top: 1px;
  font-size: 11px;
  line-height: 1.4;
}

/* §9 Final CTA */
.ph-final-cta {
  background: var(--ink);
  color: var(--paper);
  border-radius: 16px;
  padding: 44px 28px;
  margin: 36px 0;
  text-align: center;
}
.ph-final-cta-h2 {
  font-family: 'Instrument Serif', Georgia, serif;
  font-size: 32px;
  font-weight: 400;
  margin: 0 0 8px;
  letter-spacing: -0.01em;
  color: var(--paper);
}
.ph-final-cta-body {
  margin: 0 0 22px;
  color: rgba(255,255,255,0.8);
  font-size: 14px;
  font-family: var(--mono);
  letter-spacing: 0.04em;
}
.ph-final-cta-actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
}
.ph-final-cta-primary { padding: 14px 28px; font-size: 15px; }
.ph-final-cta-secondary { color: rgba(255,255,255,0.6); }
.ph-final-cta-secondary a {
  color: var(--paper);
  text-decoration: underline;
  margin: 0 4px;
}

/* ── Homepage v3 (peer tabs restored + filter chips + always-on USP) ──── */

/* v3 banner */
.ph-v3-banner {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 0 0 18px;
  padding: 8px 14px;
  background: #e8f0fa;
  border: 1px solid #b0c4dc;
  border-radius: 8px;
  color: #1a3d5c;
}
.ph-v3-banner-flag {
  display: inline-block;
  background: #1a3d5c;
  color: #e8f0fa;
  padding: 2px 8px;
  border-radius: 3px;
  font-weight: 700;
  font-size: 9px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.ph-v3-banner a { color: #1a3d5c; text-decoration: underline; font-weight: 600; }

/* v3 hero — 4-cell search row: city + locality + Search + ✨ AI Search
   pill (renders in every mode; see form.blade.php). The pill is the
   row's rightmost cell: the Search button squares its right corner and
   the pill takes the rounded right end, forming one seamless bar. The
   idle CTA glow that previously made this look boxy is gone (the pulsing
   box-shadow animation was deleted), so squaring the submit is now
   clean. Variant 2. */
.ph-hero--v3 .ph-hero-search-row--v3 {
  grid-template-columns: 200px minmax(0, 1fr) auto auto;
}
@media (min-width: 801px) {
  /* Submit no longer the rightmost cell — square its right so the pill
     butts flush and forms the row's rounded right end. */
  .ph-hero--v3 .ph-hero-search-row--v3 > .ph-hero-search-submit {
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
  }
  /* Pill flush like the city/locality cells (no own border); takes the
     row's right corner. */
  .ph-hero--v3 .ph-hero-search-row--v3 > .search-engine-ai-pill {
    border: 0;
    border-radius: 0 12px 12px 0;
  }
  /* Border-based hover is dead (border:0) — deepen the gradient instead. */
  .ph-hero--v3 .ph-hero-search-row--v3 > .search-engine-ai-pill:hover {
    background: linear-gradient(135deg,
        color-mix(in oklab, var(--saffron-soft, #fde7c4) 92%, var(--paper)) 0%,
        color-mix(in oklab, #d8c4f5 44%, var(--paper)) 100%);
  }
}
@media (max-width: 800px) {
  /* Single-column stack — pill drops below Search with its natural radius. */
  .ph-hero--v3 .ph-hero-search-row--v3 { grid-template-columns: 1fr; }
  .ph-hero--v3 .ph-hero-search-row--v3 > .search-engine-ai-pill {
    border-radius: 10px;
  }
}

/* MagicBricks-style filter chip row + inline expansion (v3) */
.ph-filter-chip-row {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px dashed var(--line);
}
.ph-filter-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 14px;
  border: 1px solid var(--line);
  background: var(--paper);
  border-radius: 999px;
  font-size: 12px;
  color: var(--ink-2);
  cursor: pointer;
  font-family: inherit;
  font-weight: 500;
  white-space: nowrap;
  transition: border-color 0.12s, background 0.12s;
}
.ph-filter-chip:hover { border-color: var(--ink-3); }
.ph-filter-chip--active {
  background: rgba(255,193,77,0.12);
  border-color: var(--saffron-deep, #d8a35e);
  color: var(--ink);
}
.ph-filter-chip.is-expanded {
  background: rgba(255,193,77,0.22);
  border-color: var(--saffron-deep, #d8a35e);
  font-weight: 600;
}
.ph-filter-chip-caret { font-size: 9px; opacity: 0.7; }
.ph-filter-chip-spacer { flex: 1; }
.ph-filter-chip--more {
  border-style: dashed;
  color: var(--ink);
  font-weight: 600;
}
/* ROI Verified — primary toggle chip (platform USP). Saffron-edged even
   when inactive so it reads as the featured filter; the shared --active
   treatment + a filled green tick mark the on-state. */
.ph-filter-chip--roi {
  border-color: var(--saffron-deep, #d8a35e);
  color: var(--ink);
}
.ph-filter-chip-roi-tick { color: var(--saffron-deep, #d8a35e); font-size: 11px; line-height: 1; }
.ph-filter-chip--roi.ph-filter-chip--active .ph-filter-chip-roi-tick { color: var(--green, #4a7c2f); }
/* Active-filter count badge on the More Filters chip. */
.ph-filter-chip-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 16px; height: 16px; padding: 0 4px;
  background: var(--saffron-deep, #d8a35e); color: #fff;
  border-radius: 999px; font-size: 10px; font-weight: 700;
}
@media (max-width: 700px) {
  .ph-filter-chip-spacer { display: none; }
  .ph-filter-chip--more { width: 100%; justify-content: center; }
}

.ph-filter-expand {
  margin-top: 10px;
  padding: 14px 16px;
  background: var(--paper);
  border: 1px solid var(--saffron-deep, #d8a35e);
  border-radius: 10px;
  box-shadow: 0 2px 8px rgba(216,163,94,0.08);
}
.ph-filter-expand-head {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-bottom: 16px;
}
.ph-filter-expand-title { font-size: 13px; font-weight: 600; color: var(--ink); }
.ph-filter-expand-meta { color: var(--ink-3); }

/* Budget preset bands — one-tap range chips above the hero slider
   (SRP-parity). Shares the .ph-filter-chip look; .is-active reuses the
   saffron-tint highlight. */
.ph-budget-bands {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 0 12px;
  margin-bottom: 14px;
}
.ph-budget-band {
  padding: 7px 13px;
  border: 1px solid var(--line);
  background: var(--paper);
  border-radius: 999px;
  font-size: 12px;
  color: var(--ink-2);
  cursor: pointer;
  font-family: inherit;
  font-weight: 500;
  white-space: nowrap;
  transition: border-color 0.12s, background 0.12s, color 0.12s;
}
.ph-budget-band:hover { border-color: var(--ink-3); }
.ph-budget-band.is-active {
  background: rgba(255,193,77,0.12);
  border-color: var(--saffron-deep, #d8a35e);
  color: var(--ink);
  font-weight: 600;
}

.ph-budget-slider { padding: 0 12px; }
.ph-budget-slider-handles {
  display: flex; gap: 12px; margin-bottom: 12px;
}
.ph-budget-slider-pill {
  display: inline-block;
  padding: 4px 10px;
  background: var(--ink);
  color: var(--paper);
  border-radius: 4px;
  font-size: 11px;
  font-weight: 600;
  font-family: var(--mono);
  letter-spacing: 0.04em;
}
.ph-budget-slider-track {
  position: relative;
  height: 4px;
  background: var(--line);
  border-radius: 2px;
  margin: 6px 0 22px;
}
.ph-budget-slider-track-fill {
  position: absolute;
  top: 0; bottom: 0;
  background: var(--saffron-deep, #d8a35e);
  border-radius: 2px;
}

/* Two-thumb dual-range slider. The frame stacks an inert visual
   track at the centerline plus two transparent <input type="range">
   controls overlaid; only the thumbs receive pointer events so the
   user can grab either handle independently. The track-fill div
   inside the track shows the selected band. */
.ph-budget-slider-frame {
  position: relative;
  height: 18px;             /* thumb diameter (16px) + breathing room */
  margin: 6px 0 22px;
}
.ph-budget-slider-frame .ph-budget-slider-track {
  position: absolute;
  top: 50%;
  left: 0; right: 0;
  margin: 0;
  transform: translateY(-50%);
}
.ph-budget-slider-input {
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 100%;
  margin: 0;
  background: transparent;
  pointer-events: none;     /* track is inert; thumbs override below */
  -webkit-appearance: none;
  appearance: none;
}
.ph-budget-slider-input:focus { outline: none; }

/* Hide the native track — we render our own underneath. */
.ph-budget-slider-input::-webkit-slider-runnable-track {
  background: transparent; border: none; height: 100%;
}
.ph-budget-slider-input::-moz-range-track {
  background: transparent; border: none; height: 100%;
}

/* Thumb styling — pointer-events:auto so the user can grab. */
.ph-budget-slider-input::-webkit-slider-thumb {
  -webkit-appearance: none;
  pointer-events: auto;
  width: 16px; height: 16px;
  background: var(--paper);
  border: 2px solid var(--saffron-deep, #d8a35e);
  border-radius: 50%;
  cursor: grab;
  box-shadow: 0 1px 3px rgba(0,0,0,0.15);
  margin-top: 0;
}
.ph-budget-slider-input::-moz-range-thumb {
  pointer-events: auto;
  width: 16px; height: 16px;
  background: var(--paper);
  border: 2px solid var(--saffron-deep, #d8a35e);
  border-radius: 50%;
  cursor: grab;
  box-shadow: 0 1px 3px rgba(0,0,0,0.15);
}
.ph-budget-slider-input:active::-webkit-slider-thumb { cursor: grabbing; }
.ph-budget-slider-input:active::-moz-range-thumb { cursor: grabbing; }
.ph-budget-slider-input:focus-visible::-webkit-slider-thumb {
  box-shadow: 0 0 0 4px rgba(216,163,94,0.25);
}
.ph-budget-slider-input:focus-visible::-moz-range-thumb {
  box-shadow: 0 0 0 4px rgba(216,163,94,0.25);
}

/* Stack: lower-bound input on top so its thumb wins clicks at the
   left edge; upper-bound on top at the right edge. With both at the
   same z-index the upper input would always win on the left half. */
.ph-budget-slider-input--upper { z-index: 3; }
.ph-budget-slider-input--lower { z-index: 4; }

.ph-budget-slider-axis {
  display: flex; justify-content: space-between;
  color: var(--ink-3);
  font-size: 10px;
}

/* Single-select option pills used by the Bedroom, Construction
   Status, and Posted By chip panels. Same flow as the budget
   panel — rendered inside .ph-filter-expand. The "Clear" pill is
   dashed and only visible once a value is picked. */
.ph-filter-options {
  display: flex; flex-wrap: wrap; gap: 8px;
  padding: 4px 0 6px;
}
.ph-filter-option {
  padding: 8px 14px;
  border: 1px solid var(--line);
  background: var(--paper);
  border-radius: 999px;
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-2);
  cursor: pointer;
  font-family: inherit;
  transition: border-color 0.12s, background 0.12s, color 0.12s;
}
.ph-filter-option:hover { border-color: var(--ink-3); }
.ph-filter-option.is-selected {
  background: rgba(255,193,77,0.22);
  border-color: var(--saffron-deep, #d8a35e);
  color: var(--ink);
  font-weight: 600;
}
.ph-filter-option--clear {
  border-style: dashed;
  color: var(--ink-3);
}

/* Why ROI — dark theme (v3 per user) */
.ph-why--dark {
  background: var(--ink);
  color: var(--paper);
  border-radius: 16px;
  padding: 32px 28px;
  margin: 36px 0;
}
.ph-section-title--on-dark { color: var(--paper); }
.ph-why-tile--dark {
  background: rgba(255,255,255,0.05);
  border-color: rgba(255,255,255,0.12);
}
.ph-why-tile--dark .ph-why-icon {
  background: rgba(255,255,255,0.08);
}
.ph-why-tile--dark.ph-why-tile--load-bearing {
  background: rgba(255,193,77,0.18);
  border-color: var(--saffron);
}
.ph-why-tile--dark.ph-why-tile--load-bearing .ph-why-icon {
  background: var(--saffron);
}
.ph-why-tile--dark .ph-why-title { color: var(--paper); }
.ph-why-tile--dark .ph-why-body { color: rgba(255,255,255,0.78); }
.ph-why-tile--dark .ph-why-body b { color: var(--paper); }

/* For Owners + For Buyers (v3 expanded panel) */
.ph-owner-buyer {
  margin: 36px 0;
}
.ph-owner-buyer-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}
@media (max-width: 800px) { .ph-owner-buyer-grid { grid-template-columns: 1fr; } }

.ph-owner-buyer-panel {
  display: flex; flex-direction: column;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 24px 26px;
  position: relative;
}
.ph-owner-buyer-panel--owner {
  background: var(--ivory-2);
}
.ph-owner-buyer-panel--buyer {
  background: linear-gradient(180deg, rgba(255,193,77,0.10) 0%, rgba(216,163,94,0.04) 100%);
  border-color: rgba(216,163,94,0.5);
}
.ph-owner-buyer-eyebrow {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 8px;
}
.ph-owner-buyer-flag {
  background: var(--saffron);
  color: var(--ink);
  padding: 2px 6px;
  border-radius: 3px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.06em;
}
.ph-owner-buyer-title {
  font-family: 'Instrument Serif', Georgia, serif;
  font-size: 22px;
  font-weight: 400;
  color: var(--ink);
  margin: 0 0 10px;
  letter-spacing: -0.01em;
  line-height: 1.2;
}
.ph-owner-buyer-body {
  margin: 0 0 14px;
  color: var(--ink-2);
  font-size: 14px;
  line-height: 1.6;
}
.ph-owner-buyer-body b { color: var(--ink); font-weight: 600; }
.ph-owner-buyer-bullets {
  list-style: none; padding: 0; margin: 0 0 18px;
  display: flex; flex-direction: column; gap: 8px;
  flex: 1;
}
.ph-owner-buyer-bullets li {
  position: relative;
  padding-left: 22px;
  color: var(--ink-2);
  font-size: 13px;
  line-height: 1.5;
}
.ph-owner-buyer-bullets li::before {
  content: "✓";
  position: absolute;
  left: 0; top: 0;
  color: #355d1f;
  font-weight: 700;
}
.ph-owner-buyer-cta { width: 100%; }

/* Always-on strip — single flowing line. Layout-bug fix 2026-04-30:
   the previous flex container shredded `<b>` tags into separate flex
   items with gap; now it's two atoms — pulse dot + one text span. */
.ph-owner-buyer-foot {
  display: flex; align-items: center; gap: 10px;
  margin-top: 14px;
  padding: 12px 18px;
  background: var(--ink);
  color: rgba(255,255,255,0.85);
  border-radius: 8px;
  line-height: 1.5;
}
.ph-owner-buyer-foot-text {
  flex: 1;
  min-width: 0;
}
.ph-owner-buyer-foot b { color: var(--paper); font-weight: 600; }
.ph-owner-buyer-foot-pulse {
  display: inline-block;
  width: 8px; height: 8px;
  background: #5cd175;
  border-radius: 50%;
  flex-shrink: 0;
  box-shadow: 0 0 0 0 rgba(92, 209, 117, 0.7);
  animation: ph-pulse-dot 2s infinite;
}

/* Demand-band + Featured-band head controls (city selector + CTA stacked) */
.ph-demand-head-controls {
  display: flex; align-items: center; gap: 8px;
  flex-shrink: 0;
}
@media (max-width: 700px) {
  .ph-demand-head-controls { width: 100%; flex-direction: column; align-items: stretch; }
}
.ph-demand-city-select {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 6px 12px;
  color: var(--ink-2);
  font-family: var(--mono);
  font-size: 11px; /* fs-input-allow — homepage demand strip, follow-up: --fs-input-sm */
  cursor: pointer;
  max-width: 240px;
}
.ph-demand-city-select:hover { border-color: var(--ink-3); color: var(--ink); }

/* Buyer-card posted-time replaces the (removed) broker tier badge.
   Lives in the foot row; right-aligned via natural flex flow. */
.ph-demand-card-posted { color: var(--ink-3); margin-left: auto; }

/* v1 archived-page banner — surfaces clearly that this page is not the locked direction */
.ph-v1-banner {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 0 0 18px;
  padding: 8px 14px;
  background: var(--cream);
  border: 1px solid #d8c7a3;
  border-radius: 8px;
  color: #5c4a2c;
}
.ph-v1-banner-flag {
  display: inline-block;
  background: #5c4a2c;
  color: var(--cream);
  padding: 2px 8px;
  border-radius: 3px;
  font-weight: 700;
  font-size: 9px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.ph-v1-banner a { color: #5c4a2c; text-decoration: underline; font-weight: 600; }

/* Footer tagline (replaces .ph-footer-meta in v2) */
.ph-footer-tagline {
  text-align: center;
  margin-top: 22px;
  padding-top: 16px;
  border-top: 1px dotted var(--line);
  color: var(--ink-2);
  font-style: italic;
  font-family: 'Instrument Serif', Georgia, serif;
  font-size: 14px;
  letter-spacing: 0.01em;
}




/* ──────────────────────────────────────────────────────────────────
   B4.5.2 — WhatsApp button (lead-capture entry point on every surface
   where a phone is otherwise rendered). Pill shape, WhatsApp green.
   Sits inline next to a masked phone span — see broker-card.
   ────────────────────────────────────────────────────────────────── */
.whatsapp-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  margin-left: 8px;
  background: #25D366;
  color: #ffffff;
  border: none;
  border-radius: 999px;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  transition: filter 120ms ease, transform 120ms ease;
}
.whatsapp-btn:hover { filter: brightness(1.06); }
.whatsapp-btn:active { transform: translateY(1px); }
.whatsapp-btn:focus-visible {
  outline: 2px solid var(--ink, #1a1a1a);
  outline-offset: 2px;
}
.whatsapp-btn svg { display: block; flex-shrink: 0; }

/* ──────────────────────────────────────────────────────────────────
   AI Search modal (<x-ai-search-sheet>, public/js/ai-search.js).
   Mounted page-globally in layouts/app.blade.php; opens on the
   `open-ai-search` window event. Bottom-sheet on phones, centred
   dialog ≥640px. ([x-cloak] is defined globally above.)
   ────────────────────────────────────────────────────────────────── */

.ai-search-overlay {
  position: fixed;
  inset: 0;
  z-index: 9000;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}
.ai-search-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(20, 18, 16, 0.55);
  backdrop-filter: blur(2px);
}
.ai-search-sheet {
  position: relative;
  width: 100%;
  max-width: 560px;
  max-height: 88vh;
  overflow-y: auto;
  background: var(--paper, #fff);
  border-radius: 16px 16px 0 0;
  padding: 24px 20px calc(24px + var(--inset-bottom));
  box-shadow: 0 -8px 40px -8px rgba(20, 18, 16, 0.3);
}
.ai-search-close {
  position: absolute;
  top: 12px;
  right: 14px;
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 0;
  font-size: 24px;
  line-height: 1;
  color: var(--ink-3, #8a8079);
  cursor: pointer;
  border-radius: 50%;
}
.ai-search-close:hover { background: var(--ivory-2, #efe8db); color: var(--ink, #141210); }

.ai-search-title {
  font-size: 19px;
  font-weight: 700;
  margin: 0 0 6px;
  color: var(--ink, #141210);
  letter-spacing: -0.01em;
}
.ai-search-title-sub {
  font-family: var(--mono, monospace);
  font-size: 11px;
  font-weight: 400;
  color: var(--saffron-deep, #b07d3c);
  letter-spacing: 0.02em;
}
.ai-search-lede {
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink-2, #4a443e);
  margin: 0 0 14px;
}

.ai-search-input {
  width: 100%;
  box-sizing: border-box;
  min-height: 64px;
  resize: vertical;
  padding: 12px 14px;
  border: 1px solid var(--line, #e2dccf);
  border-radius: 10px;
  background: var(--ivory-2, #efe8db);
  font: inherit;
  font-size: var(--fs-input);
  color: var(--ink, #141210);
  line-height: 1.45;
}
.ai-search-input:focus {
  outline: 0;
  border-color: var(--ink, #141210);
  background: var(--paper, #fff);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--ink, #141210) 8%, transparent);
}

.ai-search-examples {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 12px 0 16px;
}
.ai-search-example {
  display: inline-flex;
  align-items: center;
  min-height: 32px;
  padding: 5px 11px;
  background: var(--paper, #fff);
  border: 1px solid var(--line, #e2dccf);
  border-radius: 999px;
  font: inherit;
  font-size: 12px;
  color: var(--ink-2, #4a443e);
  cursor: pointer;
  text-align: left;
}
.ai-search-example:hover {
  border-color: var(--saffron-deep, #b07d3c);
  color: var(--ink, #141210);
}

.ai-search-submit {
  width: 100%;
  min-height: 48px;
  background: var(--ink, #141210);
  color: var(--paper, #fff);
  border: 0;
  border-radius: 10px;
  font: inherit;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
}
.ai-search-submit:disabled { opacity: 0.45; cursor: not-allowed; }

.ai-search-actions { display: flex; flex-direction: column; gap: 8px; margin-top: 16px; }
.ai-search-ghost {
  width: 100%;
  min-height: 44px;
  background: transparent;
  color: var(--ink-2, #4a443e);
  border: 1px solid var(--line, #e2dccf);
  border-radius: 10px;
  font: inherit;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
}
.ai-search-ghost:hover { border-color: var(--ink-3, #8a8079); color: var(--ink, #141210); }

.ai-search-chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 4px 0 4px; }
.ai-search-chip {
  display: inline-flex;
  align-items: center;
  padding: 5px 11px;
  background: var(--saffron-soft, #fde7c4);
  color: var(--saffron-deep, #b07d3c);
  border-radius: 999px;
  font-size: 13px;
  font-weight: 600;
}
.ai-search-chip--empty {
  background: var(--ivory-2, #efe8db);
  color: var(--ink-3, #8a8079);
  font-weight: 500;
}

.ai-search-loading {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 28px 0;
  color: var(--ink-2, #4a443e);
  font-size: 14px;
}
.ai-search-spinner {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 3px solid var(--line, #e2dccf);
  border-top-color: var(--saffron-deep, #b07d3c);
  animation: ai-search-spin 0.7s linear infinite;
}
@keyframes ai-search-spin { to { transform: rotate(360deg); } }

.ai-search-errorbox { padding: 8px 0; }
.ai-search-error {
  font-size: 14px;
  line-height: 1.5;
  color: #b04040;
  margin: 0 0 14px;
}

/* AI Search entry-point pill in the production search-engine (srp-bar). */
.search-engine-ai-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  padding: 0 14px;
  background: linear-gradient(135deg, color-mix(in oklab, var(--saffron-soft, #fde7c4) 80%, var(--paper)) 0%, color-mix(in oklab, #d8c4f5 30%, var(--paper)) 100%);
  border: 1px solid var(--line, #e2dccf);
  border-radius: 10px;
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  color: var(--ink, #141210);
  cursor: pointer;
  white-space: nowrap;
}
.search-engine-ai-pill:hover { border-color: var(--saffron-deep, #b07d3c); }

@media (min-width: 640px) {
  .ai-search-overlay { align-items: center; }
  .ai-search-sheet { border-radius: 16px; }
}

/* ──────────────────────────────────────────────────────────────────
   B4.5.1 — Lead-form modal. Mounted page-globally in layouts/app.blade.php;
   opens in response to `lead-form:open` Alpine event from whatsapp-btn.
   ────────────────────────────────────────────────────────────────── */

.lead-form-overlay {
  position: fixed;
  inset: 0;
  z-index: 9000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}
.lead-form-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(20, 20, 20, 0.55);
  backdrop-filter: blur(2px);
}
.lead-form-modal {
  position: relative;
  z-index: 1;
  max-width: 460px;
  width: 100%;
  max-height: 90vh;
  overflow-y: auto;
  background: var(--paper, #ffffff);
  border: 1px solid var(--line-2, #e5e5e5);
  border-radius: 14px;
  box-shadow: 0 20px 60px -10px rgba(0, 0, 0, 0.35);
  padding: 28px 26px 24px;
}
.lead-form-modal h2 {
  font: inherit;
  font-size: 22px;
  font-weight: 700;
  margin: 0 0 6px;
  color: var(--ink, #1a1a1a);
}
.lead-form-sub {
  margin: 0 0 18px;
  color: var(--ink-2, #555);
  font-size: 14px;
}
.lead-form-close {
  position: absolute;
  top: 8px;
  right: 12px;
  background: transparent;
  border: 0;
  font-size: 28px;
  line-height: 1;
  color: var(--ink-2, #555);
  cursor: pointer;
  padding: 4px 8px;
  border-radius: 6px;
}
.lead-form-close:hover { background: var(--ivory-2, #f5f5f5); }

.lead-form-modal label {
  display: block;
  margin-bottom: 12px;
  font-size: 13px;
  color: var(--ink-2, #555);
}
.lead-form-modal label > span {
  display: block;
  margin-bottom: 4px;
  font-weight: 500;
}
.lead-form-modal input[type="text"],
.lead-form-modal input[type="tel"],
.lead-form-modal input[type="number"],
.lead-form-modal select {
  width: 100%;
  padding: 9px 12px;
  font: inherit;
  font-size: var(--fs-input);
  background: var(--paper, #fff);
  color: var(--ink, #1a1a1a);
  border: 1px solid var(--line-2, #e5e5e5);
  border-radius: 8px;
}
.lead-form-modal input:focus,
.lead-form-modal select:focus {
  outline: none;
  border-color: var(--ink, #1a1a1a);
}

.lead-form-intent {
  border: 0;
  padding: 0;
  margin: 0 0 14px;
}
.lead-form-intent legend {
  padding: 0;
  margin-bottom: 8px;
  font-size: 13px;
  color: var(--ink-2, #555);
  font-weight: 500;
}
.lead-form-intent label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 0 12px 6px 0;
  font-size: 14px;
  color: var(--ink, #1a1a1a);
}
.lead-form-intent label > span { display: inline; margin: 0; }

.lead-form-match { margin-bottom: 12px; }
.lead-form-budget {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

.lead-form-consent {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin: 16px 0;
  padding: 10px;
  background: var(--ivory-2, #faf7f2);
  border-radius: 8px;
  font-size: 13px;
  color: var(--ink-2, #444);
}
.lead-form-consent input[type="checkbox"] { margin-top: 2px; }
.lead-form-consent > span { flex: 1; }

.lead-form-otp {
  font-size: 22px !important;
  letter-spacing: 0.4em;
  text-align: center;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
}

.lead-form-error {
  margin: 0 0 12px;
  padding: 10px 12px;
  background: var(--red-soft);
  color: #a13030;
  border: 1px solid #f4cccc;
  border-radius: 8px;
  font-size: 13px;
}

.lead-form-success { text-align: center; padding: 12px 0 4px; }
.lead-form-success h2 { margin-bottom: 10px; }
.lead-form-success p {
  margin: 0 0 18px;
  color: var(--ink-2, #555);
  font-size: 14px;
  line-height: 1.5;
}

.lead-form-modal .btn {
  width: 100%;
  margin-top: 6px;
}

/* Reveal-on-click affordance for the masked phone span. Same shape as
   the surrounding listing-broker-link, just with a hover/focus hint to
   communicate it's interactive. */
.listing-broker-link--reveal {
  background: transparent;
  border: 0;
  padding: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
  border-bottom: 1px dashed currentColor;
  transition: opacity 120ms ease;
}
.listing-broker-link--reveal:hover { opacity: 0.75; }
.listing-broker-link--reveal:focus-visible {
  outline: 2px solid var(--ink, #1a1a1a);
  outline-offset: 3px;
  border-radius: 2px;
}

/* Success-step reveal block — the promised reward post-capture. */
.lead-form-reveal {
  margin: 12px 0 18px;
  padding: 16px;
  background: var(--ivory-2, #faf7f2);
  border: 1px solid var(--line-2, #e5e5e5);
  border-radius: 10px;
  text-align: center;
}
.lead-form-reveal-label {
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-2, #555);
  margin-bottom: 4px;
}
.lead-form-reveal-number {
  font-size: 22px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--ink, #1a1a1a);
  margin-bottom: 12px;
}
.lead-form-reveal-actions {
  display: flex;
  gap: 8px;
  justify-content: center;
}
.lead-form-reveal-actions .btn {
  width: auto;
  flex: 1;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 9px 14px;
}
.lead-form-success-meta {
  font-size: 12px;
  color: var(--ink-3, #888);
  margin-top: 12px;
}

/* ────────────────────────────────────────────────────────────
 * Public PDP — Body intro + 2-col body grid + sticky right rail.
 *
 * Composition rationale:
 *  - The hero stays 2-col (gallery + compact rail) but both cols
 *    end at the same height via `align-items: stretch`. The gallery
 *    grows vertically to match the rail; or the rail caps height
 *    at the gallery's natural height. No "rail extends past the
 *    gallery" gap.
 *  - Below the hero, a full-width `pl-body-intro` carries the USP +
 *    key-highlights bullets that used to crowd the hero rail.
 *  - Below the intro, a 2-col `pl-body-grid` holds all body
 *    sections (left, fluid) + a sticky compact contact card (right,
 *    fixed-width). The contact card follows the buyer through the
 *    entire page — Zillow / 99acres / Housing.com pattern.
 *  - Mobile (<900px): grid collapses to single column, sticky rail
 *    drops out (the existing `_sticky-cta` mobile bar covers conversion).
 * ──────────────────────────────────────────────────────────── */
.pl-hero-gallery { display: flex; flex-direction: column; }

.pl-body-intro {
  margin: 0 0 28px;
  padding: 20px 24px;
  background: var(--ivory-2, #f7f1e8);
  border: 1px solid var(--line, #e6dfd1);
  border-radius: 12px;
}
.pl-body-intro-usp {
  font-size: 17px;
  line-height: 1.55;
  color: var(--ink, #1a1a1a);
  margin: 0;
  font-weight: 500;
}
.pl-body-intro-highlights {
  margin: 14px 0 0;
  padding: 0 0 0 18px;
  list-style: disc;
  color: var(--ink-2, #333);
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: 24px;
  row-gap: 6px;
  font-size: 14px;
  line-height: 1.5;
}
@media (max-width: 700px) {
  .pl-body-intro-highlights { grid-template-columns: 1fr; }
}

.pl-body-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: 32px;
  align-items: start;
}
@media (max-width: 900px) {
  .pl-body-grid { grid-template-columns: 1fr; gap: 0; }
}
.pl-body-main { min-width: 0; }
.pl-body-rail { position: relative; }
.pl-body-rail-inner {
  position: sticky;
  /* 80px = anchor-nav height (~50px) + breathing room. Without this
   * offset the rail's top edge would slide under the sticky nav. */
  top: 80px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
@media (max-width: 900px) {
  /* On mobile, the sticky rail flow-positions BELOW the body main
   * column — but the global `_sticky-cta` bottom bar already serves
   * the persistent-CTA role on small screens, so we hide this rail
   * to avoid redundant CTAs. */
  .pl-body-rail { display: none; }
}

.pl-body-rail-card {
  border: 1px solid var(--line, #e6dfd1);
  border-radius: 12px;
  background: var(--paper, #fff);
  padding: 18px 18px 16px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.pl-body-rail-head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--line-soft, #f0e9d8);
}
.pl-body-rail-avatar {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.pl-body-rail-avatar-initials {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink, #1a1a1a);
  letter-spacing: 0.04em;
}
.pl-body-rail-head-text { display: flex; flex-direction: column; min-width: 0; }
.pl-body-rail-head-eyebrow {
  color: var(--ink-3, #888);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.pl-body-rail-head-name {
  font-size: 16px;
  font-weight: 600;
  color: var(--ink, #1a1a1a);
  display: flex;
  align-items: center;
  gap: 8px;
}
.pl-body-rail-cta {
  width: 100%;
  justify-content: center;
  font-size: 15px;
  font-weight: 600;
  padding: 11px 14px;
}
.pl-body-rail-secondary {
  width: 100%;
  justify-content: center;
}
.pl-body-rail-foot {
  color: var(--ink-3, #888);
  text-align: center;
  margin-top: 4px;
}

/* ────────────────────────────────────────────────────────────
 * Public PDP — Cut 2: Anchor nav + EMI calc + Share button.
 * ──────────────────────────────────────────────────────────── */

/* Anchor-nav: sticky horizontal tab strip below the body intro.
 * Sticks to the top of the viewport while the buyer is in the body
 * region; falls out of sticky once they scroll past the FAQs.
 * Mobile: horizontal scroll (overflow-x: auto), no scroll-bar visible. */
.pl-anchor-nav {
  position: sticky;
  /* Slot beneath the site navbar (sticky, ~60px tall) instead of
   * covering it. z-index below navbar's 20 is belt-and-braces so
   * any future navbar-height change doesn't re-trigger the overlap. */
  top: 60px;
  z-index: 15;
  margin: 0 0 28px;
  background: var(--paper, #fff);
  border-top: 1px solid var(--line, #e6dfd1);
  /* Heavier bottom border so the nav reads as a structural divider,
   * not a ghost strip. The active-tab pill below now has enough
   * contrast that the section the buyer is reading is unmistakable. */
  border-bottom: 2px solid var(--ink-2, #555);
}
.pl-anchor-nav-inner {
  display: flex;
  gap: 4px;
  overflow-x: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
  padding: 10px 0 10px;
}
.pl-anchor-nav-inner::-webkit-scrollbar { display: none; }
.pl-anchor-nav a {
  flex-shrink: 0;
  padding: 9px 16px;
  font-size: 14px;
  /* Bump default weight from 500 → 600 + darken default text so the
   * nav reads as a real surface, not a ghost. */
  font-weight: 600;
  color: var(--ink-2, #555);
  text-decoration: none;
  border-radius: 8px;
  transition: color 120ms ease, background 120ms ease;
}
.pl-anchor-nav a:hover {
  color: var(--ink, #1a1a1a);
  background: var(--ivory-2, #f7f1e8);
}
.pl-anchor-nav a.is-active {
  /* Dark pill + light text. Unmistakable signal for the section the
   * buyer is currently reading; works against both light and dark
   * page backgrounds. */
  color: var(--paper, #fff);
  background: var(--ink, #1a1a1a);
  font-weight: 700;
}
.pl-anchor-nav a.is-active:hover {
  /* Keep the active pill dark on hover instead of falling back to
   * the hover style — would create a flicker otherwise. */
  color: var(--paper, #fff);
  background: var(--ink, #1a1a1a);
}
@media (max-width: 700px) {
  .pl-anchor-nav { margin: 0 -16px 20px; padding: 0 16px; }
  .pl-anchor-nav a { padding: 8px 12px; font-size: 13px; }
}

/* Scroll-margin-top so anchor-link clicks land each section BELOW
 * the sticky nav rather than under it. ~80px = nav height + breathing
 * room. Applied to the wrapper divs (and the directly-IDd sections
 * #listing-video / #listing-faqs). */
.pl-anchor-target,
#listing-video,
#listing-faqs {
  scroll-margin-top: 80px;
}

/* EMI widget — sits in the sticky body rail. Compact card layout.
 * Live-updating output value at the top, three sliders below.
 * The browser's default <input type="range"> is good enough; we
 * just style the surrounding rows. */
.pl-emi-widget {
  border: 1px solid var(--line, #e6dfd1);
  border-radius: 12px;
  background: var(--paper, #fff);
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.pl-emi-widget-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink, #1a1a1a);
  margin: 0;
  letter-spacing: 0.02em;
}
.pl-emi-widget-output {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 12px 14px;
  background: var(--ivory-2, #f7f1e8);
  border-radius: 8px;
  align-items: flex-start;
}
.pl-emi-widget-output-value {
  font-size: 22px;
  font-weight: 600;
  color: var(--ink, #1a1a1a);
  letter-spacing: -0.01em;
}
.pl-emi-widget-output-label {
  color: var(--ink-3, #888);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.pl-emi-widget-slider { display: flex; flex-direction: column; gap: 6px; }
.pl-emi-widget-slider-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  color: var(--ink-3, #888);
}
.pl-emi-widget-slider-value {
  color: var(--ink, #1a1a1a);
  font-weight: 600;
}
.pl-emi-widget-slider input[type="range"] {
  width: 100%;
  appearance: none;
  -webkit-appearance: none;
  height: 4px;
  background: var(--line, #e6dfd1);
  border-radius: 2px;
  outline: none;
  cursor: pointer;
}
.pl-emi-widget-slider input[type="range"]::-webkit-slider-thumb {
  appearance: none;
  -webkit-appearance: none;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--saffron, #f97316);
  cursor: grab;
  border: 2px solid var(--paper, #fff);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
}
.pl-emi-widget-slider input[type="range"]::-moz-range-thumb {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--saffron, #f97316);
  cursor: grab;
  border: 2px solid var(--paper, #fff);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
}
.pl-emi-widget-foot {
  color: var(--ink-3, #888);
  text-align: center;
  font-style: italic;
}

/* Share button — sits at the bottom of the sticky rail. The Alpine
 * binding swaps the label briefly when the URL is copied; visual
 * treatment kept low-key (ghost) so the WhatsApp CTA stays primary. */
.pl-body-rail-share {
  width: 100%;
  justify-content: center;
}

/* ────────────────────────────────────────────────────────────
 * Public PDP — Cut 3: Per-kind "Move-in readiness" section.
 * Renders different content for ready_to_move vs under_construction
 * vs new_launch. Visual treatment is intentionally calm — this is a
 * trust / due-diligence panel, not a marketing pitch.
 * ──────────────────────────────────────────────────────────── */
.pl-readiness {
  /* Sub-rows have their own gap; section already has the standard
   * pl-section vertical rhythm. */
}

/* Under-construction progress bar */
.pl-readiness-progress {
  margin-bottom: 16px;
}
.pl-readiness-progress-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  color: var(--ink-3, #888);
  margin-bottom: 6px;
}
.pl-readiness-progress-value {
  color: var(--ink, #1a1a1a);
  font-weight: 600;
}
.pl-readiness-progress-bar {
  height: 8px;
  background: var(--line, #e6dfd1);
  border-radius: 4px;
  overflow: hidden;
}
.pl-readiness-progress-fill {
  height: 100%;
  background: var(--saffron, #f97316);
  border-radius: 4px;
  transition: width 240ms ease;
}

/* New-launch countdown line */
.pl-readiness-launch {
  padding: 10px 14px;
  background: var(--ivory-2, #f7f1e8);
  border-radius: 8px;
  color: var(--ink-2, #333);
  margin-bottom: 16px;
  letter-spacing: 0.02em;
}

/* Document checklist (OC / CC certs) */
.pl-readiness-checks {
  list-style: none;
  margin: 0 0 16px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.pl-readiness-check {
  display: flex;
  align-items: baseline;
  gap: 8px;
  color: var(--ink, #1a1a1a);
}
.pl-readiness-check-mark {
  color: var(--green, #2e7d32);
  font-weight: 700;
  font-size: 14px;
}
.pl-readiness-check-label {
  font-weight: 500;
}
.pl-readiness-check-detail {
  color: var(--ink-3, #888);
}

/* Last-sold history row (resale signal) */
.pl-readiness-history {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 10px 0;
  border-top: 1px solid var(--line-soft, #f0e9d8);
  border-bottom: 1px solid var(--line-soft, #f0e9d8);
  margin-bottom: 16px;
}
.pl-readiness-history-label {
  color: var(--ink-3, #888);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.pl-readiness-history-value {
  font-size: 15px;
  font-weight: 600;
  color: var(--ink, #1a1a1a);
}

/* Payment plan block */
.pl-readiness-payment {
  margin-bottom: 16px;
}
.pl-readiness-payment-label {
  color: var(--ink-3, #888);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: 6px;
}
.pl-readiness-payment-text {
  color: var(--ink-2, #333);
  white-space: pre-line;
  line-height: 1.55;
}

/* Escrow trust note — borrowed visual from the existing
 * .pl-escrow-note used inside the Builder block. */
.pl-readiness-escrow {
  padding: 12px 14px;
  background: var(--ivory-2, #f7f1e8);
  border-left: 3px solid var(--saffron, #f97316);
  border-radius: 4px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink-2, #333);
}
.pl-readiness-escrow strong {
  color: var(--ink, #1a1a1a);
}

/* ────────────────────────────────────────────────────────────
 * Public PDP — Cut 4: Trust & Verification strip + Docs section.
 *
 * Trust strip sits at the top of pl-body-main as a horizontal badge
 * row. Earned-only signals — every badge is independently @if-guarded.
 * Strong AEO citation surface (LLMs heavily weight verification chains).
 *
 * Docs grid is a 2-column document checklist (universal + state-
 * specific groups). Indian-state-specific section gated on the
 * resolved state_slug — Karnataka khata/mutation; Maharashtra
 * 7/12 + mutation; Delhi/Haryana/UP conversion certificate.
 * ──────────────────────────────────────────────────────────── */

/* Trust strip — horizontal pill row above Property details. */
.pl-trust-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 24px;
  padding: 0;
}
.pl-trust-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  background: var(--ivory-2, #f7f1e8);
  border: 1px solid var(--line, #e6dfd1);
  border-radius: 999px;
  font-size: 13px;
  color: var(--ink, #1a1a1a);
  white-space: nowrap;
}
.pl-trust-badge-mark {
  color: var(--green, #2e7d32);
  font-weight: 700;
  font-size: 12px;
}
.pl-trust-badge-label {
  font-weight: 500;
}
.pl-trust-badge-detail {
  color: var(--ink-3, #888);
}

/* Differentiated treatments per badge type — kept visually quiet
 * so the strip reads as a coherent row, not a circus of colors. */
.pl-trust-badge--rera {
  background: rgba(46, 125, 50, 0.06); /* faint green tint */
  border-color: rgba(46, 125, 50, 0.18);
}
.pl-trust-badge--roi {
  /* Low-saturation red. The full ROI Verified badge lives in the
   * broker card; this is the secondary trust pill. */
  background: rgba(220, 38, 38, 0.05);
  border-color: rgba(220, 38, 38, 0.18);
}
.pl-trust-badge--exclusive {
  background: rgba(249, 115, 22, 0.06);
  border-color: rgba(249, 115, 22, 0.18);
}

@media (max-width: 700px) {
  .pl-trust-strip {
    /* Horizontal scroll on mobile so badges don't wrap into 4 rows */
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    -ms-overflow-style: none;
    margin: 0 -16px 20px;
    padding: 0 16px;
  }
  .pl-trust-strip::-webkit-scrollbar { display: none; }
  .pl-trust-badge { flex-shrink: 0; }
}

/* Docs grid — two-column document checklist with checkmarks. */
.pl-docs {
  /* Inherits pl-section's vertical rhythm. */
}
.pl-docs-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px 24px;
}
@media (max-width: 700px) {
  .pl-docs-grid { grid-template-columns: 1fr; }
}
.pl-docs-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
}
.pl-doc-check {
  flex-shrink: 0;
  width: 18px;
  text-align: center;
  font-weight: 700;
  font-size: 13px;
  line-height: 1;
}
.pl-doc-check--ok { color: var(--green, #2e7d32); }
.pl-doc-check--info {
  color: var(--ink-3, #888);
  font-size: 9px;
  vertical-align: middle;
}
.pl-docs-row-label {
  color: var(--ink, #1a1a1a);
  font-weight: 500;
}
.pl-docs-row-value {
  color: var(--ink-3, #888);
}

/* State-specific doc block — visually separated from the universal
 * grid by a subtle top border + small uppercase eyebrow heading. */
.pl-docs-state-block {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px dashed var(--line, #e6dfd1);
}
.pl-docs-state-title {
  color: var(--ink-3, #888);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 11px;
  margin: 0 0 10px;
  font-weight: 600;
}

/* ────────────────────────────────────────────────────────────
 * Public PDP — Cut 5: Pricing intelligence + Rental terms.
 *
 * Both sections share a 2-col definition-list grid for their primary
 * rows (one row per attribute). Pricing additionally renders an
 * optional sparkline when price_history has 2+ points. Rental
 * additionally renders a "What's included" chip-list from the
 * furnishing_inventory JSON.
 *
 * AEO note: dt/dd structure is semantically rich — search engines
 * extract these as labeled facts. Stamp-duty, GST, negotiability
 * become Q&A-ready passages.
 * ──────────────────────────────────────────────────────────── */

/* Shared 2-col grid + row treatment (used by both Pricing + Rental). */
.pl-pricing-grid,
.pl-rental-terms-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px 28px;
  margin: 0;
}
@media (max-width: 700px) {
  .pl-pricing-grid,
  .pl-rental-terms-grid {
    grid-template-columns: 1fr;
    gap: 12px;
  }
}
.pl-pricing-row,
.pl-rental-terms-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.pl-pricing-row dt,
.pl-rental-terms-row dt {
  color: var(--ink-3, #888);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.pl-pricing-row dd,
.pl-rental-terms-row dd {
  margin: 0;
  font-size: 15px;
  font-weight: 500;
  color: var(--ink, #1a1a1a);
}

/* Price-history sparkline (Pricing intelligence section). Inline
 * mini-chart that visually corroborates the "+/- X% since {month}"
 * caption. Values shown on hover via the title attribute. */
.pl-pricing-history {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px dashed var(--line, #e6dfd1);
}
.pl-pricing-history-title {
  color: var(--ink-3, #888);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 11px;
  margin: 0 0 10px;
  font-weight: 600;
}
.pl-pricing-history-spark {
  display: flex;
  align-items: flex-end;
  gap: 4px;
  height: 60px;
  margin-bottom: 8px;
}
.pl-pricing-history-bar {
  flex: 1;
  background: var(--saffron, #f97316);
  border-radius: 2px 2px 0 0;
  min-height: 4px;
  transition: opacity 120ms ease;
}
.pl-pricing-history-bar:hover { opacity: 0.7; }
.pl-pricing-history-caption {
  color: var(--ink-3, #888);
  text-align: right;
}

/* Rental terms — "What's included" furnishing chip list. Each chip
 * is a count + label (e.g. "3× AC"); compact, scannable. */
.pl-rental-terms-furnishing {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px dashed var(--line, #e6dfd1);
}
.pl-rental-terms-furnishing-title {
  color: var(--ink-3, #888);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 11px;
  margin: 0 0 10px;
  font-weight: 600;
}
.pl-rental-terms-furnishing-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.pl-rental-terms-furnishing-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px;
  background: var(--ivory-2, #f7f1e8);
  border: 1px solid var(--line, #e6dfd1);
  border-radius: 999px;
  font-size: 13px;
  color: var(--ink, #1a1a1a);
}
.pl-rental-terms-furnishing-count {
  font-weight: 600;
  color: var(--ink, #1a1a1a);
}

/* ────────────────────────────────────────────────────────────
 * Public PDP — Cut 6: Connectivity + Society stats + Costs.
 *
 * Connectivity has two visual layers:
 *   1) Top row of pills (nearest metro / railway / airport / walkability)
 *   2) Typed POI panels grid (schools / hospitals / tech parks)
 * Society & building stats: a 2-col dt/dd grid + an urgency callout
 * for new-launch / UC listings + a sample-flat CTA strip.
 * Costs & utilities: a simple 2-col dt/dd grid sharing the pricing-grid
 * visual treatment.
 * ──────────────────────────────────────────────────────────── */

/* Connectivity pills — horizontal row above the POI panels. */
.pl-connectivity-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 18px;
}
.pl-connectivity-pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  background: var(--ivory-2, #f7f1e8);
  border: 1px solid var(--line, #e6dfd1);
  border-radius: 999px;
  font-size: 13px;
  color: var(--ink, #1a1a1a);
}
.pl-connectivity-pill-icon {
  font-size: 14px;
}
.pl-connectivity-pill-text {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  flex-wrap: wrap;
}
.pl-connectivity-pill-detail {
  color: var(--ink-3, #888);
}
.pl-connectivity-pill--walkability {
  background: rgba(46, 125, 50, 0.06);
  border-color: rgba(46, 125, 50, 0.18);
}

/* Typed POI panels — schools / hospitals / tech parks. 3-col on
 * desktop, 1-col on mobile. */
.pl-connectivity-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}
@media (max-width: 900px) {
  .pl-connectivity-grid { grid-template-columns: 1fr; }
}
.pl-connectivity-panel {
  border: 1px solid var(--line, #e6dfd1);
  border-radius: 8px;
  padding: 14px;
}
.pl-connectivity-panel-head {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink, #1a1a1a);
  margin-bottom: 10px;
  display: flex;
  align-items: center;
  gap: 6px;
}
.pl-connectivity-panel-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.pl-connectivity-panel-list li {
  padding-bottom: 8px;
  border-bottom: 1px solid var(--line-soft, #f0e9d8);
}
.pl-connectivity-panel-list li:last-child {
  border-bottom: none;
  padding-bottom: 0;
}
.pl-connectivity-poi-name {
  font-size: 14px;
  font-weight: 500;
  color: var(--ink, #1a1a1a);
}
.pl-connectivity-poi-meta {
  color: var(--ink-3, #888);
  margin-top: 2px;
}

/* Society & building stats — 2-col dt/dd grid + optional urgency
 * callout + sample-flat CTA strip. */
.pl-society-stats-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px 28px;
  margin: 0 0 14px;
}
@media (max-width: 700px) {
  .pl-society-stats-grid { grid-template-columns: 1fr; gap: 12px; }
}
.pl-society-stats-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.pl-society-stats-row dt {
  color: var(--ink-3, #888);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.pl-society-stats-row dd {
  margin: 0;
  font-size: 15px;
  font-weight: 500;
  color: var(--ink, #1a1a1a);
}

/* Urgency callout — saffron-tinted pill above the stats grid. Renders
 * on new-launch / UC listings when available_unit_count is known and
 * low. Genuine scarcity → buyer trust. */
.pl-society-urgency {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  background: rgba(249, 115, 22, 0.08);
  border: 1px solid rgba(249, 115, 22, 0.25);
  border-radius: 999px;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink, #1a1a1a);
  margin-bottom: 14px;
}
.pl-society-urgency-mark {
  color: var(--saffron, #f97316);
  font-size: 10px;
  animation: pulse 2s ease-in-out infinite;
}
@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}

/* Sample-flat CTA — sits at the bottom of the Society section.
 * "🏠 Sample flat available" + "Book a site visit" button. */
.pl-society-sample-flat {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 14px;
  padding: 12px 14px;
  background: var(--ivory-2, #f7f1e8);
  border-radius: 8px;
}
.pl-society-sample-flat-label {
  font-size: 14px;
  font-weight: 500;
  color: var(--ink, #1a1a1a);
}
@media (max-width: 500px) {
  .pl-society-sample-flat {
    flex-direction: column;
    align-items: stretch;
  }
}

/* Costs & utilities — same dt/dd treatment as pricing-grid. */
.pl-costs-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px 28px;
  margin: 0;
}
@media (max-width: 700px) {
  .pl-costs-grid { grid-template-columns: 1fr; gap: 12px; }
}
.pl-costs-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.pl-costs-row dt {
  color: var(--ink-3, #888);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.pl-costs-row dd {
  margin: 0;
  font-size: 15px;
  font-weight: 500;
  color: var(--ink, #1a1a1a);
}

/* ========== Cut 7 — Commercial specs + Plot & land details =====
   Two category-gated spec sections. Layout deliberately mirrors the
   society-stats / costs grids so the visual language stays consistent
   across PDP categories.
   ──────────────────────────────────────────────────────────────── */

/* Commercial specs grid — cabin / workstation / washroom / power. */
.pl-commercial-specs-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px 24px;
  margin: 0 0 18px;
}
@media (max-width: 900px) { .pl-commercial-specs-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 520px) { .pl-commercial-specs-grid { grid-template-columns: 1fr; gap: 12px; } }
.pl-commercial-specs-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 12px 14px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 10px;
}
.pl-commercial-specs-row dt {
  color: var(--ink-3, #888);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.pl-commercial-specs-row dd {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
  color: var(--ink, #1a1a1a);
}

/* Fit-out tier panel — tier label + explainer prose. */
.pl-commercial-fitout {
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px 16px;
  background: var(--surface);
  margin: 0 0 14px;
}
.pl-commercial-fitout-tier {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 6px;
}
.pl-commercial-fitout-tier-mark {
  font-size: 18px;
  line-height: 1;
}
.pl-commercial-fitout-tier-label {
  font-size: 15px;
  font-weight: 600;
  color: var(--ink, #1a1a1a);
}
.pl-commercial-fitout-detail {
  margin: 0;
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink-2, #555);
}

/* Lease tenure — single-line strip. */
.pl-commercial-lease-tenure {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 14px;
  background: var(--surface-2);
  border-radius: 8px;
}
.pl-commercial-lease-tenure strong {
  font-size: 15px;
  font-weight: 600;
}

/* Plot & land specs grid — area / dimensions / road / zoning. */
.pl-plot-specs-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px 28px;
  margin: 0 0 16px;
}
@media (max-width: 700px) { .pl-plot-specs-grid { grid-template-columns: 1fr; gap: 12px; } }
.pl-plot-specs-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.pl-plot-specs-row dt {
  color: var(--ink-3, #888);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.pl-plot-specs-row dd {
  margin: 0;
  font-size: 15px;
  font-weight: 500;
  color: var(--ink, #1a1a1a);
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.pl-plot-specs-detail {
  color: var(--ink-3, #888);
  font-weight: 400;
}

/* Plot flags — corner plot · boundary wall — pill row. */
.pl-plot-specs-flags {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.pl-plot-specs-flag {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 14px;
  font-weight: 500;
  color: var(--ink, #1a1a1a);
}
.pl-plot-specs-flag-detail {
  color: var(--ink-3, #888);
  font-weight: 400;
}

/* ========== Cut 8 — Media depth + Save button ===================
   Virtual tour + drone iframes use a 16:9 aspect-ratio container so
   embedded Matterport / YouTube content responds without layout
   shift. Save button mirrors share button visual weight (ghost) so
   the WhatsApp CTA stays primary in the rail.
   ──────────────────────────────────────────────────────────────── */

.pl-virtual-tour-caption,
.pl-drone-caption {
  margin: 4px 0 14px;
  color: var(--ink-3, #888);
  line-height: 1.5;
}

.pl-virtual-tour-frame,
.pl-drone-frame {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: 12px;
  overflow: hidden;
  background: #0a0a0a;
  border: 1px solid var(--border);
}
.pl-virtual-tour-frame iframe,
.pl-drone-frame iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* Save (favourite) button — same width treatment as share, with a
 * tinted active state when the listing is saved. The fill swap on
 * the heart icon is handled by Alpine via :fill binding; the
 * button-level .is-saved class drives the tint. */
.pl-body-rail-save {
  width: 100%;
  justify-content: center;
  margin-bottom: 8px;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.pl-body-rail-save.is-saved {
  background: var(--accent-soft, #fff1f3);
  color: var(--accent);
  border-color: var(--accent);
}
.pl-body-rail-save:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ──────────────────────────────────────────────────────────────────
 * /dashboard — post-login landing
 * Sections under the hero KPI strip. The strip itself reuses
 * .dash / .dash-kpis / .dash-kpi rules already defined above.
 * ────────────────────────────────────────────────────────────────── */

.dash-greeting {
  margin: 24px 0 8px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.dash-greeting-sub {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--ink-3);
  font-size: 12px;
  letter-spacing: 0.04em;
}

.dash-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 24px;
  margin-top: 8px;
  align-items: start;
}
@media (min-width: 1100px) {
  .dash-grid { grid-template-columns: 1fr 300px; }
}
.dash-grid-main {
  display: flex;
  flex-direction: column;
  gap: 28px;
  min-width: 0;
}
.dash-grid-side {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.ps-empty-cta-row { margin-top: 14px; }

/* Seeker /my/matches filter bar */
.my-matches-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin: 14px 0 18px;
}
.my-matches-filters .form-input { padding: 6px 10px; font-size: var(--fs-input); }

/* Seeker conversations inbox */
.my-conv-list { display: flex; flex-direction: column; gap: 6px; margin-top: 16px; }
.my-conv-row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 12px 14px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 10px;
  text-decoration: none;
  color: inherit;
}
.my-conv-row:hover { background: var(--ivory-2); }
.my-conv-row--unread { border-color: var(--saffron, #f59e0b); background: rgba(245, 158, 11, 0.04); }
.my-conv-body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.my-conv-head { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.my-conv-broker { font-weight: 600; color: var(--ink); }
.my-conv-firm, .my-conv-when { color: var(--ink-3); }
.my-conv-listing { color: var(--ink-2); }
.my-conv-preview { color: var(--ink-2); font-size: 13px; }
.my-conv-unread {
  background: var(--saffron, #f59e0b);
  color: #fff;
  border-radius: 999px;
  padding: 2px 9px;
  font-size: 11px;
  align-self: center;
  flex: 0 0 auto;
}

/* Seeker dashboard intro action row — Accept/Decline buttons,
 * "Open conversation" deep-link. Sits inside .dash-intro-row. */
.dash-intro-actions {
  display: flex;
  gap: 6px;
  align-items: center;
  margin-left: auto;
  flex: 0 0 auto;
}
.dash-intro-form { margin: 0; }
.dash-intro-row--accepted { background: rgba(34, 197, 94, 0.04); }
.dash-intro-row--declined { opacity: 0.55; }

.dash-section {
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--paper);
  padding: 18px 20px;
}
.dash-section--side { padding: 16px 18px; }
.dash-section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
}
.dash-section-title {
  font-family: var(--serif);
  font-size: 20px;
  line-height: 1.1;
  color: var(--ink);
  margin: 0;
}
.dash-section-sub {
  font-size: 11px;
  color: var(--ink-4);
  letter-spacing: 0.06em;
}

/* "See all X →" affordance, sits flush right of the section header
 * or just below the list when used as a footer link. */
.dash-section-link {
  color: var(--ink-3);
  text-decoration: none;
  white-space: nowrap;
}
.dash-section-link:hover { color: var(--ink); }

/* Seeker dashboard intro section ("Brokers reaching out" / "Brokers
 * you contacted"). Each row renders as a flat card; the broker name
 * is the primary, listing context is secondary, actions stack right. */
.dash-intro-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.dash-intro-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 8px;
  flex-wrap: wrap;
}
.dash-intro-row:hover { background: var(--ivory-2); }
.dash-intro-broker {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--ink);
  text-decoration: none;
  font-weight: 600;
  min-width: 0;
}
.dash-intro-broker:hover { text-decoration: underline; }
.dash-intro-broker-name { color: var(--ink); }
.dash-intro-badge {
  background: rgba(34, 197, 94, 0.10);
  color: #15803d;
  border-radius: 999px;
  padding: 1px 8px;
  font-size: 10px;
  letter-spacing: 0.04em;
  white-space: nowrap;
}
.dash-intro-listing {
  color: var(--ink-2);
  text-decoration: none;
  flex: 1 1 200px;
  min-width: 0;
}
.dash-intro-listing:hover { color: var(--ink); text-decoration: underline; }
.dash-intro-status {
  color: var(--ink-3);
  background: var(--ivory-2);
  border-radius: 999px;
  padding: 2px 10px;
}
.dash-intro-actions {
  display: flex;
  gap: 6px;
  margin-left: auto;
}
.dash-intro-form { margin: 0; }
.dash-intro-row--accepted { background: rgba(34, 197, 94, 0.04); }
.dash-intro-row--declined { opacity: 0.55; }

/* Saved listings list — used by seeker + DO + fallback dashboards. */
.dash-saved-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.dash-saved-list li {
  padding: 8px 12px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--paper);
}
.dash-saved-list li:hover { background: var(--ivory-2); }
.dash-saved-list a {
  color: var(--ink);
  text-decoration: none;
  display: inline-flex;
  gap: 6px;
  align-items: baseline;
}
.dash-saved-list a:hover { text-decoration: underline; }

/* ── Direct Owner dashboard ───────────────────────────────────── */
.do-property-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 14px;
}
.do-property-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 14px 16px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 10px;
}
.do-property-card--draft { border-style: dashed; opacity: 0.85; }
.do-property-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.do-property-card-bhk {
  background: var(--ivory-2);
  border-radius: 4px;
  padding: 2px 8px;
  color: var(--ink-2);
  font-size: 11px;
}
.do-property-card-status {
  font-size: 10px;
  letter-spacing: 0.08em;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--ivory-2);
  color: var(--ink-3);
  text-transform: uppercase;
}
.do-property-card-status--live {
  background: rgba(34, 197, 94, 0.10);
  color: #15803d;
}
.do-property-card-title {
  color: var(--ink);
  font-weight: 600;
  text-decoration: none;
  line-height: 1.3;
}
.do-property-card-title:hover { text-decoration: underline; }
.do-property-card-meta { color: var(--ink-3); }
.do-property-card-actions {
  display: flex;
  gap: 6px;
  margin-top: 4px;
}

.do-lead-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.do-lead-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 14px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 8px;
}
.do-lead-row-main {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
  flex: 1 1 auto;
}
.do-lead-row-head { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.do-lead-name { font-weight: 600; color: var(--ink); }
.do-lead-channel {
  background: var(--ivory-2);
  border-radius: 999px;
  padding: 1px 8px;
  color: var(--ink-3);
}
.do-lead-when { color: var(--ink-3); }
.do-lead-listing { color: var(--ink-2); }
.do-lead-message {
  color: var(--ink-2);
  font-size: 13px;
  padding: 4px 0;
  border-top: 1px dashed var(--line);
}
.do-lead-contact { color: var(--ink-3); display: flex; gap: 6px; align-items: baseline; flex-wrap: wrap; }
.do-lead-sep { opacity: 0.6; }
.do-lead-row-actions {
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex: 0 0 auto;
}

/* Empty-state used by today-actions + activity-feed. */
.dash-empty {
  padding: 18px 16px;
  text-align: center;
  border: 1px dashed var(--line);
  border-radius: 8px;
  background: var(--ivory-2);
}
.dash-empty-title {
  font-family: var(--serif);
  font-size: 16px;
  color: var(--ink-2);
  margin-bottom: 4px;
}
.dash-empty-sub {
  font-size: 12px;
  color: var(--ink-4);
}
.dash-empty a { color: var(--saffron-deep); text-decoration: none; font-weight: 600; }
.dash-empty a:hover { text-decoration: underline; }

/* Today's actions — prioritized list with colored dots. */
.dash-actions {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.dash-action {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--ivory-2);
}
.dash-action-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--ink-4);
}
.dash-action--attention .dash-action-dot { background: var(--saffron); }
.dash-action--opportunity .dash-action-dot { background: var(--accent); }
.dash-action--cleanup .dash-action-dot { background: var(--ink-4); }
.dash-action-text {
  font-size: 14px;
  color: var(--ink);
  text-decoration: none;
  flex: 1;
}
.dash-action-text:hover { text-decoration: underline; }

/* Performance — three tiles with delta arrows. */
.dash-perf {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
}
@media (max-width: 800px) {
  .dash-perf { grid-template-columns: 1fr; }
}
.dash-perf-tile {
  display: block;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--ivory-2);
  text-decoration: none;
  color: inherit;
}
.dash-perf-tile:hover {
  border-color: var(--ink-4);
}
.dash-perf-label {
  font-size: 10px;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.dash-perf-value {
  font-family: var(--serif);
  font-size: 28px;
  line-height: 1;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  margin: 6px 0 4px;
}
.dash-perf-delta {
  font-size: 11px;
  letter-spacing: 0.04em;
  display: flex;
  align-items: baseline;
  gap: 6px;
}
.dash-perf-delta--up { color: var(--green); }
.dash-perf-delta--down { color: var(--accent); }
.dash-perf-delta--flat { color: var(--ink-4); }
.dash-perf-delta-prev {
  color: var(--ink-4);
  font-size: 10px;
}

/* Activity feed — vertical list with a left-aligned timestamp. */
.dash-activity {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}
.dash-activity-row {
  display: grid;
  grid-template-columns: 80px 1fr;
  gap: 12px;
  padding: 10px 0;
  border-bottom: 1px solid var(--line);
}
.dash-activity-row:last-child { border-bottom: none; }
.dash-activity-meta {
  font-size: 11px;
  color: var(--ink-4);
  letter-spacing: 0.04em;
}
.dash-activity-link {
  color: var(--ink);
  text-decoration: none;
  font-size: 14px;
}
.dash-activity-link:hover .dash-activity-verb { text-decoration: underline; }
.dash-activity-verb { font-weight: 600; }
.dash-activity-subject { color: var(--ink-3); }

/* Quick actions — right-rail link grid. */
.dash-quick {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.dash-quick-item {
  display: block;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--ivory-2);
  text-decoration: none;
  color: inherit;
}
.dash-quick-item:hover {
  border-color: var(--saffron);
  background: var(--paper);
}
.dash-quick-label {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
}
.dash-quick-sub {
  font-size: 11px;
  color: var(--ink-4);
  letter-spacing: 0.04em;
  margin-top: 2px;
}

/* Sign-out button in the navbar — icon-only, sits next to the avatar.
 * Same visual weight as the theme toggle so the navbar stays balanced. */
.nav-logout-form {
  display: inline-flex;
  margin: 0;
  padding: 0;
}
.nav-logout-btn {
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--line);
  background: var(--paper);
  border-radius: 50%;
  color: var(--ink-3);
  cursor: pointer;
  transition: border-color 120ms ease, color 120ms ease;
}
.nav-logout-btn:hover {
  color: var(--accent);
  border-color: var(--accent);
}
.nav-logout-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ========== Pending FAQ drafts (broker show page) ===============
   Auto-generated FAQ drafts surface here for broker review. Visual
   weight is intentionally calmer than CTAs — this is moderation,
   not marketing. Approve/Edit/Reject row uses the standard btn-sm
   token set.
   ──────────────────────────────────────────────────────────────── */

.listing-faq-drafts {
  margin-top: 16px;
}
.listing-faq-drafts .listing-section-sub {
  margin-top: 4px;
  color: var(--ink-3, #888);
}
.listing-faq-drafts-list {
  list-style: none;
  padding: 0;
  margin: 12px 0 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.listing-faq-draft {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px 16px;
  background: var(--surface);
}
.listing-faq-draft.is-editing {
  border-color: var(--accent);
}
.listing-faq-draft-q {
  font-size: 15px;
  font-weight: 600;
  color: var(--ink, #1a1a1a);
  margin-bottom: 6px;
}
.listing-faq-draft-a {
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink-2, #555);
  margin-bottom: 12px;
}
.listing-faq-draft-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.listing-faq-draft-reject {
  color: var(--accent);
}
.listing-faq-draft-edit {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.listing-faq-draft-edit .form-input {
  width: 100%;
}

/* ──────────────────────────────────────────────────────────────────
 * /leads — mini-CRM inbox + detail (Phase 2)
 * ────────────────────────────────────────────────────────────────── */

.leads-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  margin: 12px 0 12px;
  flex-wrap: wrap;
}
.leads-head-sub {
  font-size: 12px;
  color: var(--ink-3);
  letter-spacing: 0.04em;
  margin-top: 4px;
}
.leads-head-actions { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
.leads-add-lead { white-space: nowrap; }
.leads-search { display: flex; gap: 8px; }
.leads-search-input {
  width: 280px;
  max-width: 100%;
  padding: 8px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--paper);
  color: var(--ink);
  font-size: var(--fs-input);
  font-family: var(--mono);
}
.leads-search-input:focus { outline: 2px solid var(--ink-4); outline-offset: -1px; }
/* Title row (h1 + Add-lead). Desktop: the title block sizes to content; the
   Add-lead sits at the row's right via the parent's space-between. */
.leads-head-titlerow { display: flex; align-items: flex-end; justify-content: space-between; gap: 12px; flex: 1 1 auto; }
.leads-head-titles { min-width: 0; }
/* Right-side CTA group (Bulk upload + Add lead). Keeps the titlerow a clean
   two-child space-between so the Add-lead button stays flush-right as before. */
.leads-head-cta { display: inline-flex; align-items: center; gap: 10px; flex: 0 0 auto; }
/* .leads-add-lead-long (the " lead" suffix) shows by default; hidden ≤800px. */

/* Filter pills row */
.leads-filters { display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px; }
.leads-filter-row { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }

/* ════════════════════════════════════════════════════════════════════
   SHARED CRM MOBILE FILTER PATTERN (.crm-filter-*)
   The one implementation behind the mobile filter declutter on every CRM
   surface (Leads · Buyers · Listings · Matches). A sticky "quick" strip
   keeps the daily controls visible; a "⚙ Filters" trigger opens a bottom
   SHEET holding everything secondary.

   DESKTOP (>=801px): wrappers are display:contents (they vanish, children
   flow inline exactly as the legacy filter block did) and the mobile-only
   chrome (trigger/backdrop/head/foot) is display:none — so promoting a
   surface to this pattern is byte-for-byte unchanged on desktop. All
   mobile behaviour lives in the @media block.

   Per-surface specifics (which controls sit in the strip vs the sheet, the
   horizontal scroll-strip, etc.) live in each surface's own small block
   AFTER this one (e.g. .leads-filter-row--primary). This block owns only
   the shared shell.
   ════════════════════════════════════════════════════════════════════ */
/* ── SHARED desktop default (Buyers/Listings/Matches keep this) ──────────
   Wrappers vanish; children flow inline; mobile chrome hidden. UNCHANGED. */
.crm-filter-quick { display: contents; }
.crm-filter-more-btn,
.crm-filter-sheet-backdrop,
.crm-filter-sheet-head,
.crm-filter-sheet-foot { display: none; }
.crm-filter-sheet { display: contents; }

/* ── "★ Saved ▾" front-strip dropdown (saved views) ─────────────────────
   The trigger reuses .crm-filter-more-btn styling (shown via the media
   queries below, same as ⚙ Filters). The menu is anchored to the wrapper. */
.crm-saved-dd { position: relative; display: inline-flex; flex: 0 0 auto; }
.crm-saved-dd-caret { font-size: 9px; opacity: 0.7; margin-left: 1px; }
.crm-saved-dd-menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 40;
  min-width: 220px;
  max-width: 280px;
  max-height: 60vh;
  overflow-y: auto;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: 0 8px 28px -10px rgba(20, 18, 16, 0.28);
  padding: 6px;
}
.crm-saved-dd-item { display: flex; align-items: center; gap: 4px; }
.crm-saved-dd-link {
  flex: 1 1 auto;
  display: block;
  padding: 7px 10px;
  border-radius: 7px;
  color: var(--ink);
  text-decoration: none;
  font-size: 13px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.crm-saved-dd-link:hover { background: var(--ivory-2); }
.crm-saved-dd-remove { margin: 0; }
.crm-saved-dd-remove button {
  border: 0; background: none; cursor: pointer;
  color: var(--ink-3); font-size: 16px; line-height: 1;
  padding: 4px 8px; border-radius: 6px;
}
.crm-saved-dd-remove button:hover { color: #b91c1c; background: color-mix(in oklab, #b91c1c 8%, var(--paper)); }
.crm-saved-dd-empty { padding: 8px 10px; color: var(--ink-3); }
.crm-saved-dd-save {
  width: 100%;
  margin-top: 4px;
  padding: 8px 10px;
  border: 0;
  border-top: 1px solid var(--line);
  background: none;
  cursor: pointer;
  text-align: left;
  color: var(--accent, #1a73e8);
  font-size: 13px;
  font-weight: 600;
  border-radius: 0 0 7px 7px;
}
.crm-saved-dd-save:hover { background: var(--ivory-2); }

/* ── LEADS ONLY — DESKTOP lean filter bar (progressive disclosure) ──────
   Scoped under .leads-filters so the shared pattern on the other CRM
   surfaces is untouched, AND wrapped in @media (min-width: 801px) so these
   higher-specificity rules DON'T leak into mobile. (They previously lived in
   the base block and, being more specific than the shared mobile bottom-
   sheet rules, overrode them — so on a phone the filter rendered as a cropped
   desktop popover instead of a bottom sheet, and the backdrop/chrome were
   hidden. Confining them to ≥801px lets the mobile sheet win cleanly.)
   Tier 1 (state pills + view toggle + a "Filters" trigger) stays inline;
   Tier 2 collapses into a POPOVER anchored to .leads-filters (the positioned
   common parent of the strip AND the popover — siblings, so the anchor must
   be the parent, not the strip). */
@media (min-width: 801px) {
  .leads-filters { position: relative; }      /* popover anchor */
  .leads-filters .crm-filter-quick {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
  }
  .leads-filters .crm-filter-quick .leads-filter-row--primary { display: flex; flex-wrap: wrap; gap: 6px; }
  .leads-filters .crm-filter-more-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-left: auto;             /* push the trigger to the right edge */
    min-height: 34px;
    padding: 0 14px;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--paper);
    color: var(--ink-2);
    font-family: var(--mono);
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
  }
  .leads-filters .crm-filter-more-btn:hover { border-color: var(--ink-4); }
  .leads-filters .crm-filter-more-count {
    display: inline-grid; place-items: center;
    min-width: 17px; height: 17px; padding: 0 4px;
    border-radius: 999px; background: var(--saffron); color: var(--ink);
    font-size: 10px; font-weight: 700;
  }
  /* Group "★ Saved ▾" + "⚙ Filters" together at the right edge: the Saved
     wrapper takes the auto-margin (pushes the group right), and the Filters
     button sits immediately after it (no second auto-push / gap). The Saved
     button itself must NOT keep the base .crm-filter-more-btn auto-margin
     (it's inside the wrapper) — neutralize it. */
  .leads-filters .crm-saved-dd { margin-left: auto; }
  .leads-filters .crm-saved-dd .crm-filter-more-btn { margin-left: 0; }
  .leads-filters .crm-saved-dd + .crm-filter-more-btn { margin-left: 8px; }
  .leads-filters .crm-filter-sheet-head { display: none; }   /* desktop: no sheet header */
  /* Footer (Clear-all + Done) DOES show on desktop — Clear-all is a key action. */
  .leads-filters .crm-filter-sheet-foot {
    display: flex; gap: 8px; justify-content: flex-end; align-items: center;
    margin-top: 4px; padding-top: 12px; border-top: 1px solid var(--line);
  }
  /* Desktop: a TRANSPARENT full-viewport backdrop so a click anywhere
     outside the popover dismisses it (it sits below the popover z-index). */
  .leads-filters .crm-filter-sheet-backdrop {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 55;            /* below the popover (60), above the page */
    background: transparent;
  }
  .leads-filters .crm-filter-sheet {
    display: none;
    position: absolute;
    top: 100%;
    right: 0;
    z-index: 60;        /* above sticky cards / chrome so the popover isn't clipped */
    width: min(680px, 92vw);
    flex-direction: column;
    gap: 12px;
    margin-top: 6px;
    padding: 16px;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: 14px;
    box-shadow: 0 12px 32px -8px rgba(0,0,0,0.18);
  }
  .leads-filters .crm-filter-sheet.is-open { display: flex; }
  /* View toggle: desktop shows the Tier-1 inline copy, hides the sheet copy. */
  .leads-filters .leads-view-toggle--sheet { display: none; }
  .leads-filters .leads-view-toggle--inline { display: inline-flex; margin-left: 4px; }
  /* Score (tier) + Saved rows live INSIDE the sheet on mobile only — desktop
     uses the inline front-strip versions, so hide the sheet copies here. */
  .leads-filters .crm-sheet-mobile-only { display: none; }
}

/* ── Matches desktop (>=801px): restore the ORIGINAL filter layout. The
     mobile restructure splits the pills into a quick strip (state tabs +
     primary pills) and a sheet (secondary pills + sort). With the wrappers
     at display:contents those groups are siblings of .matches-filter-wrap;
     re-order them so desktop reads as before — Sort, then state tabs, then a
     continuous pill area (primary + secondary adjacent, the seam padding
     removed so they wrap like the original single row). ── */
@media (min-width: 801px) {
  .matches-filter-wrap { display: flex; flex-direction: column; }
  .matches-filter-wrap .matches-sort            { order: 1; }
  .matches-filter-wrap .matches-state-tabs      { order: 2; }
  .matches-filter-wrap .filter-pills--primary   { order: 3; padding-bottom: 4px; }
  .matches-filter-wrap .filter-pills--secondary { order: 4; padding-top: 0; }
}

@media (max-width: 800px) {
  /* Sticky quick strip — daily controls; pinned so it stays reachable
     while the broker scrolls results. */
  .crm-filter-quick {
    display: flex;
    align-items: center;
    gap: 8px;
    position: sticky;
    top: 0;
    z-index: 8;
    padding: 8px 16px;
    margin: 0 -16px;            /* bleed to viewport edges for the scroll */
    background: color-mix(in oklab, var(--paper) 94%, transparent);
    backdrop-filter: blur(8px);
    border-bottom: 1px solid var(--line);
  }

  /* On mobile the front strip is ONLY the pill scroll-lane + ⚙ Filters.
     The Hot/Warm/Cold tier pills and the ★ Saved dropdown are NON-shrinking
     (flex:0 0 auto) — left on the strip they crushed the pill lane to ~45px
     so it couldn't scroll. They move into the bottom sheet on mobile (shown
     there via .crm-filter-sheet copies). Desktop keeps them inline. */
  .leads-filters .crm-filter-quick > .leads-tier-filters,
  .leads-filters .crm-filter-quick > .crm-saved-dd { display: none; }

  /* ⚙ Filters trigger — pinned to the right of the quick strip. */
  .crm-filter-more-btn {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    flex: 0 0 auto;
    margin-left: auto;
    min-height: 36px;
    padding: 0 12px;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--paper);
    color: var(--ink-2);
    font-family: var(--mono);
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
  }
  .crm-filter-more-count {
    display: inline-grid;
    place-items: center;
    min-width: 17px;
    height: 17px;
    padding: 0 4px;
    border-radius: 999px;
    background: var(--saffron);
    color: var(--ink);
    font-size: 10px;
    font-weight: 700;
  }

  /* Mobile: the view toggle lives ONLY inside the Filters sheet — keep it off
     the front. The inline copy must be hidden with enough specificity to beat
     the base `.leads-view-toggle { display: inline-flex }` rule (same
     specificity but defined later in the file, so it'd otherwise win). The
     `.leads-filters` prefix bumps specificity so the hide sticks. */
  .leads-filters .leads-view-toggle--inline { display: none; }
  .leads-filters .leads-view-toggle--sheet { display: flex; }

  /* Secondary filters → bottom sheet. Hidden until .is-open. */
  .crm-filter-sheet-backdrop {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 60;
    background: rgba(0,0,0,0.4);
  }
  .crm-filter-sheet {
    display: flex;
    flex-direction: column;
    gap: 10px;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 61;
    max-height: 82vh;
    overflow-y: auto;
    padding: 8px 16px calc(16px + var(--inset-bottom));
    background: var(--paper);
    border-radius: 16px 16px 0 0;
    box-shadow: 0 -8px 28px rgba(0,0,0,0.18);
    transform: translateY(100%);
    transition: transform 0.24s cubic-bezier(0.2, 0.8, 0.4, 1);
  }
  .crm-filter-sheet.is-open { transform: translateY(0); }

  .crm-filter-sheet-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    position: sticky;
    top: 0;
    padding: 6px 0 8px;
    background: var(--paper);
    border-bottom: 1px solid var(--line);
  }
  .crm-filter-sheet-title { font-size: 13px; font-weight: 700; color: var(--ink); text-transform: uppercase; letter-spacing: 0.06em; }
  .crm-filter-sheet-close {
    width: 36px; height: 36px;
    display: grid; place-items: center;
    border: 0; background: transparent;
    font-size: 22px; line-height: 1;
    color: var(--ink-3); cursor: pointer;
  }
  /* Rows inside the sheet wrap + get a comfortable tap height. */
  .crm-filter-sheet .leads-filter-row,
  .crm-filter-sheet .leads-saved-row,
  .crm-filter-sheet .leads-view-toggle,
  .crm-filter-sheet .dir-sort,
  .crm-filter-sheet .dir-filters,
  .crm-filter-sheet .filter-pills,
  .crm-filter-sheet .matches-sort { flex-wrap: wrap; }
  .crm-filter-sheet .leads-pill,
  .crm-filter-sheet .leads-view-toggle-btn,
  .crm-filter-sheet .matches-sort-opt,
  .crm-filter-sheet .filter-pill { min-height: 36px; }

  .crm-filter-sheet-foot {
    display: flex;
    gap: 10px;
    position: sticky;
    bottom: 0;
    padding: 10px 0 2px;
    background: var(--paper);
    border-top: 1px solid var(--line);
  }
  .crm-filter-sheet-foot .crm-filter-sheet-done { flex: 1; }
  .crm-filter-sheet-foot .btn { min-height: 44px; }

  /* Lock the page behind the open sheet so only the sheet scrolls. */
  body.body--crm-sheet-open { overflow: hidden; }

  /* Add-lead / save-view modal must clear the fixed bottom nav on mobile —
     centered at 80vh it collided with the nav, cropping the last fields.
     Cap the height to leave room for the nav + safe-area and let the body
     scroll within it. */
  .save-view-modal {
    max-height: calc(100dvh - 64px - var(--inset-bottom, 0px) - 24px);
  }

  /* ── Leads header — lean mobile layout ──────────────────────────────
     Row 1: title (left) + a compact "＋ Add" (right), one line.
     Caption: tight sub-line under the title.
     Row 2: full-width search. (Pills + toggle handled by the filter rules.) */
  .leads-head { flex-direction: column; align-items: stretch; gap: 8px; margin: 8px 0 10px; }
  .leads-head-titlerow { align-items: center; gap: 10px; }
  .leads-head-titles { flex: 1 1 auto; }
  .leads-head .page-h1 { font-size: var(--fs-lg); margin: 0; line-height: 1.15; }
  /* Sub-line stays (all of it) but tightens into a caption, not a row. */
  .leads-head-sub { font-size: 11px; margin-top: 2px; }
  /* Add-lead: compact "＋ Add" beside the title (drop the " lead" suffix). */
  .leads-add-lead { flex: 0 0 auto; white-space: nowrap; }
  .leads-add-lead-long { display: none; }
  /* Bulk upload collapses to its ⇪ icon on mobile to save space. */
  .leads-head-cta { gap: 8px; }
  .leads-bulk-upload-long { display: none; }
  /* Search: its own full-width row under the title. */
  .leads-head-actions { width: 100%; }
  .leads-search, .leads-head-actions .leads-search { width: 100%; }
  .leads-search-input { width: 100%; }

  /* ── Leads surface specifics: the primary pills are a horizontal
       scroll strip inside the shared quick rail. ── */
  /* Specificity MUST match the desktop default rule above
     (.leads-filters .crm-filter-quick .leads-filter-row--primary, which sets
     flex-wrap: wrap) — otherwise a lower-specificity mobile rule loses the
     cascade even inside this @media, and the pills wrap into 3 rows instead
     of scrolling. This is the regression the recent filter-bar restructure
     introduced; the matched-specificity selector here re-asserts the strip. */
  .leads-filters .crm-filter-quick .leads-filter-row--primary {
    flex: 1 1 auto;
    /* min-width:0 lets a flex child shrink below its content width so the
       strip actually scrolls instead of forcing the row wider (which was
       squeezing the pills + clipping "Today" to "Tod…"). */
    min-width: 0;
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x proximity;
    /* Trailing pad so the last pill clears the ⚙ Filters button edge and
       isn't hidden behind it at the scroll end. */
    padding-right: 4px;
  }
  .leads-filter-row--primary::-webkit-scrollbar { display: none; }
  .leads-filter-row--primary .leads-pill {
    flex: 0 0 auto;
    scroll-snap-align: start;
    min-height: 36px;
    /* Never let a pill label wrap/truncate inside the scroll strip — the
       label ("Today (5)") must stay on one line; the strip scrolls instead. */
    white-space: nowrap;
  }

  /* ── Buyers/Listings surface: inside the sheet the .dir-filters form
       stacks to one comfortable column; its inputs/buttons go full-width. ── */
  .crm-filter-sheet .dir-filters {
    display: flex;
    flex-direction: column;
    gap: 10px;
  }
  .crm-filter-sheet .dir-filters .form-input,
  .crm-filter-sheet .dir-filters .btn,
  .crm-filter-sheet .dir-filters button { width: 100%; min-height: 44px; }
  .crm-filter-sheet .dir-filters .form-check { min-height: 44px; display: flex; align-items: center; gap: 8px; }
  .crm-filter-sheet .dir-sort { gap: 6px; }
  /* The scope row in the quick strip keeps its inline pill layout on mobile. */
  .crm-filter-quick .dir-sort { flex: 1 1 auto; margin: 0; flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
  .crm-filter-quick .dir-sort::-webkit-scrollbar { display: none; }

  /* ── Matches surface: state tabs + primary pills share the quick strip
       and scroll horizontally; secondary pills + sort live in the sheet. ── */
  .crm-filter-quick .matches-state-tabs { flex: 0 0 auto; margin: 0; border-bottom: 0; }
  .crm-filter-quick .filter-pills--primary {
    flex: 1 1 auto;
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    padding: 0;
    border-bottom: 0;
    margin: 0;
    gap: 6px;
  }
  .crm-filter-quick .filter-pills--primary::-webkit-scrollbar { display: none; }
  .crm-filter-quick .filter-pill { flex: 0 0 auto; min-height: 36px; }
  /* In the sheet, the secondary pills + sort stack with breathing room. */
  .crm-filter-sheet .filter-pills--secondary { padding: 0; border-bottom: 0; }
  .crm-filter-sheet .matches-sort { margin: 0; }
}
.leads-filter-row--secondary { font-size: 11px; color: var(--ink-4); }
.leads-filter-label {
  font-size: 10px;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--ink-4);
  margin-right: 4px;
}
.leads-pill {
  display: inline-flex;
  align-items: center;
  padding: 6px 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink-2);
  font-size: 12px;
  font-family: var(--mono);
  text-decoration: none;
  letter-spacing: 0.02em;
  transition: border-color 120ms ease, background 120ms ease;
}
.leads-pill:hover { border-color: var(--ink-4); }
.leads-pill--sm { padding: 4px 10px; font-size: 11px; }
.leads-pill--active {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}
/* CRM Phase 1 — "Needs response" pill carries a warn accent so the
   speed-to-lead worklist stands out among the neutral quick-filters.
   When active it inverts to a solid warn fill. */
.leads-pill--warn {
  border-color: #f59e0b;
  color: #92400e;
  background: #fffbeb;
}
.leads-pill--warn:hover { border-color: #d97706; }
/* Front-strip Clear-all pill — muted, dashed, reads as a reset action. */
.leads-pill--clear {
  border-style: dashed;
  color: var(--ink-3);
}
.leads-pill--clear:hover { color: #b91c1c; border-color: #b91c1c; }
.leads-pill--warn.leads-pill--active {
  background: #d97706;
  color: #fff;
  border-color: #d97706;
}

/* CRM Phase 1 — SLA pill on inbox cards + rows. Three states:
   overdue (red), due-soon (amber), responded (green, quiet). Shares
   the compact inline shape of the existing last-contact stamp. */
.lead-sla {
  display: inline-flex;
  align-items: center;
  padding: 1px 7px;
  border-radius: 999px;
  font-weight: 600;
  letter-spacing: 0.02em;
  border: 1px solid transparent;
  white-space: nowrap;
  /* Defensive: never let an unexpectedly long SLA label blow out the card
     width and shove the call/WhatsApp actions off-screen — cap + ellipsize. */
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.lead-sla--overdue {
  background: #fef2f2;
  color: #b91c1c;
  border-color: #fca5a5;
}
.lead-sla--due-soon {
  background: #fffbeb;
  color: #92400e;
  border-color: #fcd34d;
}
.lead-sla--responded {
  background: #ecfdf5;
  color: #065f46;
  border-color: #6ee7b7;
}

/* Inbox list — card-per-lead, scannable on mobile + desktop */
.lead-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--paper);
  text-decoration: none;
  color: inherit;
  transition: border-color 120ms ease, background 120ms ease;
}
.lead-row:hover { border-color: var(--ink-4); background: var(--ivory-2); }
.lead-row-main { flex: 1; min-width: 0; }
.lead-row-identity { margin-bottom: 6px; }
.lead-row-name {
  font-family: var(--serif);
  font-size: 17px;
  color: var(--ink);
  line-height: 1.2;
}
.lead-row-meta {
  display: flex;
  gap: 6px;
  font-size: 11px;
  color: var(--ink-3);
  margin-top: 2px;
  flex-wrap: wrap;
}
.lead-row-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}
.lead-row-tag {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--ivory-2);
  font-size: 11px;
  font-family: var(--mono);
  color: var(--ink-2);
}
/* Lost-reason tag — muted red so it reads as a "why it died" annotation. */
.lead-row-tag--lost {
  border-color: color-mix(in oklab, #b91c1c 30%, var(--line));
  background: color-mix(in oklab, #b91c1c 8%, var(--paper));
  color: #b91c1c;
}
/* CRM Phase 6 — behavioral score chip (Hot / Warm / Cold). */
.lead-score-chip {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px solid var(--line);
  font-size: 11px;
  font-family: var(--mono);
  font-weight: 600;
  white-space: nowrap;
}
.lead-score-chip--hot {
  border-color: color-mix(in oklab, #dc2626 35%, var(--line));
  background: color-mix(in oklab, #dc2626 10%, var(--paper));
  color: #b91c1c;
}
.lead-score-chip--warm {
  border-color: color-mix(in oklab, #d97706 35%, var(--line));
  background: color-mix(in oklab, #d97706 10%, var(--paper));
  color: #b45309;
}
.lead-score-chip--cold {
  border-color: var(--line);
  background: var(--ivory-2);
  color: var(--ink-3);
}

/* Front-strip TIER filters (Hot/Warm/Cold) — replaced the List/Table/Board
   toggle. Pill look, tinted per tier; the active one is filled. */
.leads-tier-filters { display: inline-flex; align-items: center; gap: 6px; flex: 0 0 auto; }
.leads-tier-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 5px 12px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--paper);
  color: var(--ink-2);
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}
.leads-tier-pill:hover { border-color: var(--ink-4); }
.leads-tier-pill--hot.leads-tier-pill--active {
  border-color: #dc2626; background: color-mix(in oklab, #dc2626 14%, var(--paper)); color: #b91c1c;
}
.leads-tier-pill--warm.leads-tier-pill--active {
  border-color: #d97706; background: color-mix(in oklab, #d97706 14%, var(--paper)); color: #b45309;
}
.leads-tier-pill--cold.leads-tier-pill--active {
  border-color: var(--ink-4); background: var(--ivory-2); color: var(--ink);
}
.lead-row-side {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
  min-width: 0;
  flex-shrink: 0;
}
.lead-row-owner {
  font-size: 10px;
  letter-spacing: 0.06em;
  color: var(--ink-4);
}
.lead-row-times {
  font-size: 11px;
  color: var(--ink-3);
  display: flex;
  gap: 4px;
  align-items: center;
  flex-wrap: wrap;
  justify-content: flex-end;
}
.lead-row-times-sep { color: var(--line); }
.lead-row-times-warn { color: var(--accent); font-weight: 600; }
.lead-row-reminder {
  font-size: 11px;
  font-family: var(--mono);
  letter-spacing: 0.04em;
}
.lead-row-reminder--overdue { color: var(--accent); font-weight: 600; }
.lead-row-reminder--today { color: var(--saffron-deep); font-weight: 600; }
.lead-row-reminder--future { color: var(--ink-4); }

@media (max-width: 640px) {
  .lead-row { flex-direction: column; align-items: stretch; }
  .lead-row-side { align-items: flex-start; }
  .lead-row-times { justify-content: flex-start; }
}

.leads-pagination { margin-top: 16px; display: flex; justify-content: center; }

/* Source badge */
.lead-source-badge {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: 4px;
  font-size: 10px;
  font-family: var(--mono);
  font-weight: 600;
  letter-spacing: 0.06em;
}
.lead-source-badge--roi {
  background: color-mix(in oklab, var(--saffron) 15%, var(--paper));
  color: var(--saffron-deep);
  border: 1px solid color-mix(in oklab, var(--saffron) 35%, var(--line));
}
.lead-source-badge--dbcom {
  background: var(--ivory-2);
  color: var(--ink-3);
  border: 1px solid var(--line);
}
/* Phase 4 — inbound third-party webhook leads (Pabbly / IndiaMart /
 * Zapier / 99Acres / etc.). The badge displays the provider's
 * source_label so brokers can visually tell at a glance which
 * platform sent the lead. Color leans cool to differentiate from
 * the warm saffron of homepage-form ROI leads. */
.lead-source-badge--inbound {
  background: color-mix(in oklab, #4a90e2 12%, var(--paper));
  color: #2a6bb3;
  border: 1px solid color-mix(in oklab, #4a90e2 30%, var(--line));
}

/* Stage chip */
.stage-chip {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: 4px;
  font-size: 11px;
  font-family: var(--mono);
  font-weight: 600;
  letter-spacing: 0.04em;
  border: 1px solid var(--line);
  background: var(--ivory-2);
  color: var(--ink-2);
}
.stage-chip--new          { background: var(--ivory-2); color: var(--ink-2); }
.stage-chip--contacted    { background: color-mix(in oklab, #4a90e2 15%, var(--paper)); color: #2a6bb3; border-color: color-mix(in oklab, #4a90e2 30%, var(--line)); }
.stage-chip--qualifying   { background: color-mix(in oklab, var(--saffron) 18%, var(--paper)); color: var(--saffron-deep); border-color: color-mix(in oklab, var(--saffron) 30%, var(--line)); }
.stage-chip--negotiating  { background: color-mix(in oklab, #b87333 15%, var(--paper)); color: #8a5121; border-color: color-mix(in oklab, #b87333 30%, var(--line)); }
.stage-chip--won          { background: color-mix(in oklab, var(--green) 15%, var(--paper)); color: var(--green); border-color: color-mix(in oklab, var(--green) 30%, var(--line)); }
.stage-chip--lost         { background: color-mix(in oklab, var(--accent) 12%, var(--paper)); color: var(--accent); border-color: color-mix(in oklab, var(--accent) 30%, var(--line)); }
.stage-chip--lost-competitor { background: color-mix(in oklab, var(--accent) 8%, var(--paper)); color: var(--accent); border-color: color-mix(in oklab, var(--accent) 25%, var(--line)); }

/* Channel icon — sized by SVG width attribute; this just colors them */
.channel-icon { color: var(--ink-3); flex-shrink: 0; }
.channel-icon--note { color: var(--ink-4); }
.channel-icon--call-out, .channel-icon--call-in { color: #2a6bb3; }
.channel-icon--whatsapp-out, .channel-icon--whatsapp-in { color: var(--green); }
.channel-icon--sms-out, .channel-icon--sms-in { color: var(--ink-3); }
.channel-icon--email-out, .channel-icon--email-in { color: var(--ink-3); }
.channel-icon--system { color: var(--ink-4); opacity: 0.7; }

/* ── Lead detail page ─────────────────────────────────────────── */

.lead-detail-back {
  display: inline-block;
  font-size: 12px;
  color: var(--ink-3);
  text-decoration: none;
  margin: 16px 0;
  letter-spacing: 0.04em;
}
.lead-detail-back:hover { color: var(--ink); text-decoration: underline; }

.lead-detail {
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--paper);
  padding: 20px 24px;
}
.lead-detail-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 20px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--line);
}
.lead-detail-name {
  font-family: var(--serif);
  font-size: 28px;
  line-height: 1.1;
  color: var(--ink);
  margin-bottom: 8px;
}
.lead-detail-tags {
  display: flex;
  gap: 6px;
  align-items: center;
  flex-wrap: wrap;
}
.lead-detail-times {
  font-size: 11px;
  color: var(--ink-4);
  letter-spacing: 0.04em;
}

.lead-detail-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
  margin-bottom: 24px;
}
@media (max-width: 800px) {
  .lead-detail-grid { grid-template-columns: 1fr; }
}

.lead-detail-facts {
  display: grid;
  grid-template-columns: 110px 1fr;
  gap: 8px 12px;
  font-size: 13px;
  margin: 0;
}
.lead-detail-facts dt {
  color: var(--ink-4);
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  align-self: center;
}
.lead-detail-facts dd { color: var(--ink); margin: 0; word-break: break-word; }

.lead-detail-actions {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 16px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--ivory-2);
}
.lead-detail-actions-title {
  font-family: var(--serif);
  font-size: 16px;
  margin: 0 0 4px;
  color: var(--ink);
}
.lead-action-form {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding-bottom: 12px;
  border-bottom: 1px dashed var(--line);
}
.lead-action-form:last-child { border-bottom: none; padding-bottom: 0; }
.lead-action-label {
  font-size: 10px;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.lead-action-static {
  font-size: 12px;
  color: var(--ink-2);
  letter-spacing: 0.04em;
  padding: 6px 0;
}
.lead-action-select,
.lead-action-input,
.lead-action-textarea {
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--paper);
  color: var(--ink);
  font-size: var(--fs-input);
  font-family: inherit;
  width: 100%;
}
.lead-action-textarea { font-family: inherit; resize: vertical; min-height: 60px; }

/* Activity timeline */
.lead-detail-timeline { margin-top: 8px; }
.lead-timeline {
  list-style: none;
  margin: 12px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0;
}
.lead-timeline-row {
  display: flex;
  gap: 12px;
  padding: 12px 0;
  border-bottom: 1px solid var(--line);
}
.lead-timeline-row:last-child { border-bottom: none; }
.lead-timeline-icon {
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--paper);
}
.lead-timeline-row--system .lead-timeline-icon { background: var(--ivory-2); }
.lead-timeline-body { flex: 1; min-width: 0; }
.lead-timeline-head {
  display: flex;
  align-items: baseline;
  gap: 4px;
  flex-wrap: wrap;
  font-size: 12px;
}
.lead-timeline-verb { color: var(--ink); font-weight: 600; }
.lead-timeline-author,
.lead-timeline-when { color: var(--ink-4); font-size: 11px; }
.lead-timeline-system {
  font-size: 11px;
  color: var(--ink-3);
  letter-spacing: 0.04em;
  margin-top: 2px;
}
.lead-timeline-text {
  margin-top: 4px;
  font-size: 13px;
  color: var(--ink-2);
  white-space: pre-wrap;
}

/* ── Tagline — "Property Match Maker" ─────────────────────────────
   Two-tone treatment: "Property" in the system sans (bold), "Match
   Maker" in the saffron-deep italic serif (same emphasis pattern
   the rishta-ticker uses for the verb "matched with"). Designed as
   a reusable class so navbar / hero / footer can all consume the
   same brand mark consistently.

   Markup:
     <span class="ph-tagline">
       <span class="ph-tagline__lead">Property</span>
       <span class="ph-tagline__em">Match Maker</span>
     </span>

   Sizing follows the parent's font-size (em units), so the tagline
   scales with whichever heading / body context it's dropped into.
   Override via .ph-tagline--lg / --sm modifiers below for canonical
   sizes the brand asset standardises around. */
.ph-tagline {
  display: inline-flex;
  align-items: baseline;
  gap: 0.28em;
  line-height: 1.05;
}
.ph-tagline__lead {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 500;
  color: var(--ink);
  letter-spacing: -0.01em;
}
.ph-tagline__em {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  color: var(--saffron-deep);
  letter-spacing: -0.01em;
}
/* Canonical sizes — keep these the only sanctioned variants so
   downstream consumers don't ad-hoc-size the tagline and drift the
   brand mark over time. */
.ph-tagline--lg { font-size: 64px; }
.ph-tagline--md { font-size: 36px; }
.ph-tagline--sm { font-size: 18px; }
@media (max-width: 700px) {
  .ph-tagline--lg { font-size: 44px; }
  .ph-tagline--md { font-size: 28px; }
}

/* ── Rishta Ticker — site-wide announcement strip ─────────────────
   Sits below the navbar on every page rendered through layouts/app.
   Mixes 10 buyer-match fixtures (founder-approved exception) with
   ~10 live listings from listings_local. 24s cycle, ~2.4s per entry,
   GPU-only animations (opacity + transform). Reduced-motion class
   freezes on the first entry per the existing global guard at the
   top of this file. */
.rishta-ticker {
  background: var(--ivory-2);
  border-top: 1px solid color-mix(in oklab, var(--saffron-deep) 18%, transparent);
  border-bottom: 1px solid color-mix(in oklab, var(--saffron-deep) 22%, transparent);
}
/* Screen-reader-only heading — describes the strip's purpose for
   assistive tech without rendering visually. Equivalent to the
   common .visually-hidden / .sr-only pattern; scoped here to avoid
   adding a new global class. */
.rishta-ticker__sr {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0);
  white-space: nowrap; border: 0;
}
/* Sizes bumped ~5–7% from the original spec (padding 10→11, line
   20→21, font 13→14, etc.). Same proportional balance, slightly
   more presence — total strip height now ~43px (was 40px). */
.rishta-ticker__inner {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 11px 14px;
  max-width: 1280px;
  margin: 0 auto;
}
.rishta-ticker__live {
  display: flex;
  align-items: center;
  gap: 7px;
  flex-shrink: 0;
}
.rishta-ticker__pulse {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--saffron-deep);
  animation: rishta-ticker-pulse 0.9s ease-in-out infinite;
}
.rishta-ticker__live-label {
  font-size: 11px;
  letter-spacing: 1.5px;
  color: var(--saffron-deep);
  font-weight: 500;
  text-transform: uppercase;
}
.rishta-ticker__sep {
  width: 1px;
  height: 15px;
  background: color-mix(in oklab, var(--saffron-deep) 30%, transparent);
  flex-shrink: 0;
}
.rishta-ticker__msgs {
  flex: 1;
  position: relative;
  height: 21px;
  overflow: hidden;
  min-width: 0;
}
.rishta-ticker__msg {
  position: absolute;
  inset: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-family: var(--sans);
  font-size: 14px;
  line-height: 21px;
  color: var(--ink-2);
  opacity: 0;
}
.rishta-ticker__name { font-weight: 500; color: var(--ink); }
.rishta-ticker__dim { color: var(--ink-3); }
.rishta-ticker__verb {
  font-family: var(--serif);
  font-style: italic;
  color: var(--saffron-deep);
}
.rishta-ticker__property {
  font-weight: 500;
  color: var(--green);            /* sage/forest tone — matches ROI's --green token, distinguishes the property phrase from the people-names */
}
.rishta-ticker__count {
  flex-shrink: 0;
  padding-left: 12px;
  border-left: 1px solid color-mix(in oklab, var(--saffron-deep) 22%, transparent);
  font-size: 11px;
  letter-spacing: 1.4px;
  color: var(--ink-3);
  font-weight: 500;
}

@keyframes rishta-ticker-pulse {
  0%, 100% { opacity: 0.5; transform: scale(1); }
  50%      { opacity: 1;   transform: scale(1.4); }
}
/* 10 entries cycle over 24s — each visible ~2.4s. Per entry: fade
   in over ~1%, hold ~7%, fade out over ~1%. Offsets evenly at 10%. */
@keyframes rt-e1  { 0%, 0% { opacity: 0; transform: translateY(6px); } 1% { opacity: 1; transform: translateY(0); } 8% { opacity: 1; transform: translateY(0); } 9.5% { opacity: 0; transform: translateY(-6px); } 100% { opacity: 0; } }
@keyframes rt-e2  { 0%, 10% { opacity: 0; transform: translateY(6px); } 11% { opacity: 1; transform: translateY(0); } 18% { opacity: 1; transform: translateY(0); } 19.5% { opacity: 0; transform: translateY(-6px); } 100% { opacity: 0; } }
@keyframes rt-e3  { 0%, 20% { opacity: 0; transform: translateY(6px); } 21% { opacity: 1; transform: translateY(0); } 28% { opacity: 1; transform: translateY(0); } 29.5% { opacity: 0; transform: translateY(-6px); } 100% { opacity: 0; } }
@keyframes rt-e4  { 0%, 30% { opacity: 0; transform: translateY(6px); } 31% { opacity: 1; transform: translateY(0); } 38% { opacity: 1; transform: translateY(0); } 39.5% { opacity: 0; transform: translateY(-6px); } 100% { opacity: 0; } }
@keyframes rt-e5  { 0%, 40% { opacity: 0; transform: translateY(6px); } 41% { opacity: 1; transform: translateY(0); } 48% { opacity: 1; transform: translateY(0); } 49.5% { opacity: 0; transform: translateY(-6px); } 100% { opacity: 0; } }
@keyframes rt-e6  { 0%, 50% { opacity: 0; transform: translateY(6px); } 51% { opacity: 1; transform: translateY(0); } 58% { opacity: 1; transform: translateY(0); } 59.5% { opacity: 0; transform: translateY(-6px); } 100% { opacity: 0; } }
@keyframes rt-e7  { 0%, 60% { opacity: 0; transform: translateY(6px); } 61% { opacity: 1; transform: translateY(0); } 68% { opacity: 1; transform: translateY(0); } 69.5% { opacity: 0; transform: translateY(-6px); } 100% { opacity: 0; } }
@keyframes rt-e8  { 0%, 70% { opacity: 0; transform: translateY(6px); } 71% { opacity: 1; transform: translateY(0); } 78% { opacity: 1; transform: translateY(0); } 79.5% { opacity: 0; transform: translateY(-6px); } 100% { opacity: 0; } }
@keyframes rt-e9  { 0%, 80% { opacity: 0; transform: translateY(6px); } 81% { opacity: 1; transform: translateY(0); } 88% { opacity: 1; transform: translateY(0); } 89.5% { opacity: 0; transform: translateY(-6px); } 100% { opacity: 0; } }
@keyframes rt-e10 { 0%, 90% { opacity: 0; transform: translateY(6px); } 91% { opacity: 1; transform: translateY(0); } 98% { opacity: 1; transform: translateY(0); } 99.5% { opacity: 0; transform: translateY(-6px); } 100% { opacity: 0; } }

/* Per-entry animation slot — caps at 20 in case future tweaks
   raise the entry count. Slots beyond the actual entry count
   simply have nothing to animate. */
.rishta-ticker__msg:nth-child(1)  { animation: rt-e1  24s linear infinite; }
.rishta-ticker__msg:nth-child(2)  { animation: rt-e2  24s linear infinite; }
.rishta-ticker__msg:nth-child(3)  { animation: rt-e3  24s linear infinite; }
.rishta-ticker__msg:nth-child(4)  { animation: rt-e4  24s linear infinite; }
.rishta-ticker__msg:nth-child(5)  { animation: rt-e5  24s linear infinite; }
.rishta-ticker__msg:nth-child(6)  { animation: rt-e6  24s linear infinite; }
.rishta-ticker__msg:nth-child(7)  { animation: rt-e7  24s linear infinite; }
.rishta-ticker__msg:nth-child(8)  { animation: rt-e8  24s linear infinite; }
.rishta-ticker__msg:nth-child(9)  { animation: rt-e9  24s linear infinite; }
.rishta-ticker__msg:nth-child(10) { animation: rt-e10 24s linear infinite; }

/* Mobile: hide non-essential elements so the message + pulse fit
   on a single line without overflow. Counter + live-label drop
   first; then "from City" hides on tightest screens. */
@media (max-width: 640px) {
  .rishta-ticker__count,
  .rishta-ticker__live-label,
  .rishta-ticker__sep { display: none; }
}
@media (max-width: 380px) {
  .rishta-ticker__dim:first-of-type { display: none; }
}

/* prefers-reduced-motion is enforced by the global rule at the
   top of this file — it zeroes animation-duration on every
   selector, so the ticker freezes on whichever entry's `0%`
   keyframe maps to current time. We additionally pin the FIRST
   entry visible so the strip isn't mid-fade-out forever. */
@media (prefers-reduced-motion: reduce) {
  .rishta-ticker__msg { animation: none; opacity: 0; }
  .rishta-ticker__msg:first-child { opacity: 1; }
  .rishta-ticker__pulse { animation: none; opacity: 1; }
}

/* ──────────────────────────────────────────────────────────────────
 * /leads — Phase 2.5 card density + inline actions
 * ────────────────────────────────────────────────────────────────── */

.lead-row-name-link {
  text-decoration: none;
  color: inherit;
}
.lead-row-name-link:hover .lead-row-name {
  text-decoration: underline;
}

/* Property line: ▸ Listing title · ₹ Budget · Source */
.lead-row-property {
  font-size: 12px;
  color: var(--ink-3);
  letter-spacing: 0.02em;
  margin-top: 6px;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: baseline;
}
.lead-row-property-link {
  color: var(--ink);
  text-decoration: none;
  font-weight: 600;
}
.lead-row-property-link:hover { text-decoration: underline; }
.lead-row-property-text { color: var(--ink-3); }
.lead-row-property-sep { color: var(--line); }
.lead-row-property-source { color: var(--ink-4); }

/* Inline action toolbar — call · WhatsApp · stage selector */
.lead-row-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 10px;
  flex-wrap: wrap;
}
.lead-row-action {
  display: inline-flex;
  align-items: center;
  padding: 5px 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink-2);
  font-size: 12px;
  font-family: var(--mono);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-decoration: none;
  cursor: pointer;
  transition: border-color 120ms ease, background 120ms ease;
}
.lead-row-action:hover { border-color: var(--ink-4); background: var(--ivory-2); }
.lead-row-action--call:hover {
  border-color: #2a6bb3;
  background: color-mix(in oklab, #4a90e2 12%, var(--paper));
  color: #2a6bb3;
}
.lead-row-action--wa:hover {
  border-color: var(--green);
  background: color-mix(in oklab, var(--green) 12%, var(--paper));
  color: var(--green);
}
.lead-row-action-spacer { flex: 1; }

/* Inline stage <select> — chip-styled, interactive. */
.lead-stage-select { display: inline-flex; }
.lead-stage-select-input {
  font: inherit;
  font-family: var(--mono);
  font-size: 11px; /* fs-input-allow — dense stage select, follow-up: --fs-input-sm */
  font-weight: 600;
  border-radius: 4px;
  padding: 2px 22px 2px 10px;
  cursor: pointer;
  letter-spacing: 0.04em;
  text-transform: capitalize;
}
.lead-stage-select-input:focus {
  outline: 2px solid var(--ink-4);
  outline-offset: 1px;
}

.lead-row .lead-row-meta { margin-top: 2px; }
.lead-row .lead-row-tags { margin-top: 8px; }

/* ─────────────────────────────────────────────────────────────────────
 * Phase 1.C / 1.D / 1.E / 1.I / 1.J / 1.K — Buyer's Match feature CSS.
 * Component styles ordered by surface: match feed → dashboard hero →
 * public buyers SRP → homepage live pulse → compose wizard → compose
 * preview pane → computing interstitial.
 * Uses existing tokens (--ink, --ivory, --saffron, --line) — no new
 * design primitives.
 * ─────────────────────────────────────────────────────────────────── */

/* ── Score ring (pair card) ───────────────────────────────────── */
.match-ring {
  position: relative;
  width: 64px;
  height: 64px;
  margin: 0 auto;
}
.match-ring svg { display: block; }
.match-ring-track {
  fill: none;
  stroke: var(--ivory-2);
  stroke-width: 4;
}
.match-ring-fill {
  fill: none;
  stroke: var(--saffron);
  stroke-width: 4;
  stroke-linecap: round;
  transition: stroke-dasharray 0.4s ease;
}
.match-ring--hot .match-ring-fill      { stroke: var(--saffron-deep); }
.match-ring--strong .match-ring-fill   { stroke: var(--saffron); }
.match-ring--possible .match-ring-fill { stroke: var(--ink-4); }
.match-ring-score {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-family: var(--mono);
  font-size: 15px;
  font-weight: 700;
  color: var(--ink);
}
.match-dial-decay {
  color: var(--ink-4);
  font-size: 10px;
  letter-spacing: 0.04em;
  margin-top: 2px;
}

/* ── Pair card additions ──────────────────────────────────────── */
.match-fresh-badge {
  color: var(--saffron-deep);
  font-weight: 600;
  margin-right: 4px;
}
.match-side-meta {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.match-reasons-expanded {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin: 6px 0 10px;
}
.match-reason-chip {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 2px 8px;
  border-radius: 3px;
  font-size: 11px;
  font-family: var(--mono);
  border: 1px solid var(--line);
}
.match-reason-chip--ok {
  background: oklch(0.95 0.03 140);
  color: oklch(0.35 0.12 140);
  border-color: oklch(0.85 0.05 140);
}
.match-reason-chip--miss {
  background: var(--ivory-2);
  color: var(--ink-3);
  border-color: var(--line);
  opacity: 0.85;
}

/* ── Thumbs feedback ──────────────────────────────────────────── */
.match-thumbs {
  position: relative;
  display: inline-flex;
  gap: 4px;
  margin-left: 6px;
}
.match-thumb {
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 3px;
  padding: 2px 6px;
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
  opacity: 0.55;
  transition: opacity 0.15s, background 0.15s;
}
.match-thumb:hover { opacity: 1; background: var(--ivory-2); }
.match-thumb--active {
  opacity: 1;
  background: var(--saffron-soft);
  border-color: var(--saffron);
}
.match-thumbs-reasons {
  position: absolute;
  top: 100%;
  right: 0;
  margin-top: 4px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 6px;
  background: var(--ivory);
  border: 1px solid var(--line);
  border-radius: 4px;
  z-index: 10;
  min-width: 140px;
  box-shadow: 0 4px 12px rgba(0,0,0,0.08);
}
.match-thumbs-reason-chip {
  background: transparent;
  border: none;
  text-align: left;
  padding: 4px 6px;
  cursor: pointer;
  border-radius: 3px;
  position: relative;
}
/* Pseudo-overlay grows the tap target to the 48 px floor without
   bloating the visible chip on desktop. Mobile rule (in the polish
   @media block) sets min-height directly on the chip itself so the
   visible chip is also 48 px there — fat-finger floor. */
.match-thumbs-reason-chip::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  min-width: var(--tap);
  min-height: var(--tap);
  transform: translate(-50%, -50%);
}
.match-thumbs-reason-chip:hover { background: var(--ivory-2); }

/* ── Bulk-select checkbox ─────────────────────────────────────── */
.match-bulk-check {
  display: inline-flex;
  margin-left: 6px;
  cursor: pointer;
}

/* ── Bulk-action bar ──────────────────────────────────────────── */
.matches-bulk-form { margin-bottom: 16px; }
.matches-bulk-bar {
  display: flex;
  gap: 12px;
  align-items: center;
  padding: 10px 14px;
  background: var(--ivory-2);
  border: 1px solid var(--line);
  border-radius: 6px;
}
.matches-bulk-count {
  font-size: 12px;
  color: var(--ink-3);
}
.matches-bulk-count--active { color: var(--saffron-deep); font-weight: 600; }
.matches-bulk-action {
  min-width: 220px;
  font-size: 13px;
}

/* Mobile: bulk-action is desktop-only post Frame-1 (the pair card's
   mobile DOM intentionally drops the bulk-select checkbox per the
   locked design — so the bar can never lift on mobile). Hide the
   whole form wrapper so we don't ship dead DOM + a window-wide
   input listener that fires on every keystroke for nothing. */
@media (max-width: 800px) {
  .matches-bulk-form { display: none; }
  .matches-bulk-bar {
    position: fixed;
    left: 0; right: 0;
    bottom: var(--bottom-nav-clearance-12, 76px);
    padding: 10px 14px;
    background: var(--ink);
    border: 0;
    border-top: 1px solid color-mix(in oklab, var(--paper) 20%, transparent);
    border-radius: 14px 14px 0 0;
    color: var(--paper);
    box-shadow: 0 -6px 16px -6px rgba(20, 18, 16, 0.25);
    /* bottom:76px positions the bar above the mobile-bottom-nav, so
       translateY(100%) alone only moves it down by ITS OWN height
       and the chip would still poke above the nav. The extra 100 px
       pushes it well below the viewport, off-screen until selection. */
    transform: translateY(calc(100% + 100px));
    transition: transform 180ms ease;
    z-index: 60;
    gap: 8px;
  }
  .matches-bulk-bar--active { transform: translateY(0); }
  .matches-bulk-bar .matches-bulk-count {
    color: var(--paper);
    flex: 0 0 auto;
    min-width: 84px;
  }
  .matches-bulk-bar .matches-bulk-count--active { color: var(--saffron, #c8541f); }
  .matches-bulk-bar .matches-bulk-action {
    flex: 1 1 0;
    min-width: 0;
    min-height: 44px;
    font-size: 16px;
    background: rgba(255, 255, 255, 0.08);
    border: 1px solid rgba(255, 255, 255, 0.18);
    color: var(--paper);
  }
  .matches-bulk-bar [type="submit"] {
    min-height: 44px;
    padding: 0 16px;
    flex: 0 0 auto;
  }
}

/* Mobile: hide the right-rail's 5 network panels (Buyer pulse, Top
   brokers, Hot segments, Top match-makers, Recent closes). They
   live on Dashboard / a future Network tab per user direction
   2026-06-07. The 5 SQL queries in MatchesController::loadRightRail
   still run for desktop renderers — display:none keeps DOM cheap
   and won't trip Sentry. */
@media (max-width: 800px) {
  .matches-layout > .app-rail.rail { display: none; }
  /* Same treatment for the left rail (Streams / My buyers / My
     listings / Saved searches / My tags). At ≤800 px the rail
     would otherwise stack ABOVE the feed via the 1-col layout,
     burying the actual matches behind navigation chrome. Streams
     + Saved searches move into the ⚙ Filters sheet on follow-up
     polish; for now the rail is hidden and the broker uses
     ⚙ Filters to switch view (filter pills already cover quality
     + sort, which are the daily controls). */
  .matches-layout > .app-rail.lrail { display: none; }
}

/* ── Saved searches in left rail ──────────────────────────────── */
.lrail-saved-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.lrail-saved-item {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 6px 8px;
  border-radius: 4px;
  transition: background 0.15s;
}
.lrail-saved-item:hover { background: var(--ivory-2); }
.lrail-saved-link {
  flex: 1;
  text-decoration: none;
  color: inherit;
  display: flex;
  flex-direction: column;
}
.lrail-saved-name { font-size: 13px; }
.lrail-saved-meta { color: var(--ink-4); margin-top: 1px; }
.lrail-saved-x {
  background: transparent;
  border: none;
  color: var(--ink-4);
  cursor: pointer;
  font-size: 16px;
  padding: 0 6px;
}
.lrail-saved-x:hover { color: var(--saffron-deep); }
.lrail-saved-add {
  width: 100%;
  text-align: left;
  background: transparent;
  border: 1px dashed var(--line);
  padding: 8px 10px;
  border-radius: 4px;
  cursor: pointer;
  color: var(--ink-3);
  font-size: 12px;
}
.lrail-saved-add:hover { color: var(--saffron-deep); border-color: var(--saffron); }
.lrail-saved-form { display: flex; gap: 6px; margin-top: 6px; }
.lrail-saved-input { flex: 1; font-size: var(--fs-input); }

/* ── Dashboard buyer's-match hero widget ──────────────────────── */
.dash-section--match-hero {
  margin-bottom: 24px;
  padding: 18px 20px;
  background: linear-gradient(180deg, var(--ivory), var(--ivory-2));
  border: 1px solid var(--line);
  border-radius: 8px;
}
.dash-match-hero-pulse {
  display: inline-block;
  width: 8px;
  height: 8px;
  background: var(--saffron-deep);
  border-radius: 50%;
  margin-right: 6px;
  animation: dashMatchPulse 1.5s ease-in-out infinite;
}
@keyframes dashMatchPulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.5; transform: scale(1.3); }
}
.dash-match-hero-counts {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
  margin: 14px 0;
}
.dash-match-hero-counts > div {
  padding: 10px 12px;
  background: var(--ivory);
  border-radius: 5px;
  border: 1px solid var(--line);
}
.dash-match-hero-counts dt {
  font-size: 10px;
  letter-spacing: 0.05em;
  color: var(--ink-3);
  text-transform: uppercase;
  margin-bottom: 4px;
}
.dash-match-hero-counts dd {
  font-size: 22px;
  font-weight: 600;
  margin: 0;
  color: var(--ink);
}
.dash-match-hero-counts dd a { color: var(--saffron-deep); text-decoration: none; }
.dash-match-hero-thumbs {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  margin-top: 12px;
}
.dash-match-hero-thumb {
  display: flex;
  gap: 10px;
  padding: 10px;
  background: var(--ivory);
  border: 1px solid var(--line);
  border-radius: 5px;
  text-decoration: none;
  color: inherit;
  transition: border-color 0.15s, transform 0.15s;
}
.dash-match-hero-thumb:hover {
  border-color: var(--saffron);
  transform: translateY(-1px);
}
.dash-match-hero-thumb-score {
  width: 36px;
  height: 36px;
  display: grid;
  place-items: center;
  background: var(--saffron-soft);
  color: var(--saffron-deep);
  border-radius: 50%;
  font-weight: 700;
  font-size: 13px;
  flex-shrink: 0;
}
.dash-match-hero-thumb-body { flex: 1; min-width: 0; }
.dash-match-hero-thumb-buyer { font-size: 13px; font-weight: 500; }
.dash-match-hero-thumb-listing {
  color: var(--ink-3);
  margin-top: 3px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.dash-match-hero-empty-cta { display: flex; gap: 10px; margin-top: 10px; }

/* ── Public buyers SRP ────────────────────────────────────────── */
.public-buyers-srp { padding-bottom: 60px; }
.buyers-srp-hero { padding: 24px 0; }
.buyers-srp-sub {
  color: var(--ink-3);
  font-size: 15px;
  max-width: 60ch;
  margin: 12px 0;
}
.buyers-srp-hero-cta { display: flex; gap: 12px; margin-top: 16px; }
.buyers-srp-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 14px;
  margin: 24px 0;
}
/* ─────────────────────────────────────────────────────────────────
 * Buyer SRP card — B12 (2026-05-19) richness uplift.
 * Reshape from data-row to proper card: eyebrow + urgency badge,
 * avatar with category-icon corner, intent line, prominent budget,
 * stat tiles (mirror .ps-card-stats), trust pills with kind-coded
 * backgrounds, CTA button, hover shadow lift. Privacy boundary
 * unchanged — all new visuals read presenter-derived display fields
 * that source from already-public columns only.
 * ───────────────────────────────────────────────────────────────── */
.buyer-srp-card {
  padding: 18px;
  background: var(--ivory);
  border: 1px solid var(--line);
  border-radius: 8px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  transition: border-color 0.18s ease, transform 0.18s ease, box-shadow 0.18s ease;
}
.buyer-srp-card:hover {
  border-color: var(--saffron);
  transform: translateY(-2px);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.06);
}

/* Eyebrow — vertical · locality · city | urgency badge */
.buyer-srp-card-eyebrow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-height: 18px;
}
.buyer-srp-card-eyebrow-meta {
  color: var(--ink-3);
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  min-width: 0;
}
.buyer-srp-card-vertical { color: var(--ink-2); font-weight: 600; }
.buyer-srp-card-where,
.buyer-srp-card-city { color: var(--ink-3); }
.buyer-srp-card-dot { color: var(--ink-4); }

/* Urgency badge — semantic color by kind */
.buyer-srp-card-urgency {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  padding: 3px 10px;
  border-radius: 999px;
  white-space: nowrap;
  flex-shrink: 0;
}
.buyer-srp-card-urgency-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}
.buyer-srp-card-urgency--fast {
  background: #fdecec;
  color: #b9342e;
}
.buyer-srp-card-urgency--normal {
  background: #fdf3e2;
  color: #8d5a16;
}
.buyer-srp-card-urgency--exploring {
  background: #eaf1fb;
  color: #2c5ea6;
}

/* Headline row — avatar + intent + budget */
.buyer-srp-card-headline {
  display: flex;
  gap: 12px;
  align-items: center;
}
.buyer-srp-card-avatar {
  position: relative;
  width: 44px;
  height: 44px;
  flex-shrink: 0;
  display: grid;
  place-items: center;
  background: var(--saffron-soft);
  color: var(--saffron-deep);
  border-radius: 50%;
  font-weight: 700;
  font-family: var(--mono);
  font-size: 13px;
}
.buyer-srp-card-initials {
  line-height: 1;
}
.buyer-srp-card-category-icon {
  position: absolute;
  right: -2px;
  bottom: -2px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--ivory);
  border: 1px solid var(--line);
  display: grid;
  place-items: center;
  color: var(--ink-2);
}
.buyer-srp-card-category-icon svg { width: 11px; height: 11px; }
.buyer-srp-card-headline-body { flex: 1; min-width: 0; }
.buyer-srp-card-intent {
  font-size: 15px;
  font-weight: 600;
  color: var(--ink);
  line-height: 1.3;
  margin-bottom: 2px;
}
.buyer-srp-card-budget {
  font-size: 15px;
  font-weight: 600;
  color: var(--saffron-deep);
  font-variant-numeric: tabular-nums;
}

/* Stat tiles — 3-up grid, mirror .ps-card-stats shape */
.buyer-srp-card-stats {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
}
.buyer-srp-card-stat {
  background: var(--ivory-2);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 8px 10px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.buyer-srp-card-stat-value {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
  line-height: 1.2;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.buyer-srp-card-stat-label {
  font-size: 10px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-4);
}

/* Trust pills — kind-coded backgrounds */
.buyer-srp-card-trust {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.buyer-srp-card-trust-pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 11px;
  font-weight: 500;
  padding: 3px 9px;
  border-radius: 999px;
  white-space: nowrap;
}
.buyer-srp-card-trust-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.7;
}
.buyer-srp-card-trust-pill--fresh {
  background: #fdf3e2;
  color: #8d5a16;
}
.buyer-srp-card-trust-pill--anonymized {
  background: #eaf1fb;
  color: #2c5ea6;
}
.buyer-srp-card-trust-pill--active {
  background: #e8f3ec;
  color: #1f6b3a;
}
.buyer-srp-card-trust-pill--roi-verified-partner {
  background: var(--saffron-soft);
  color: var(--saffron-deep);
  font-weight: 600;
}

/* Footer — posted timestamp | CTA button */
.buyer-srp-card-foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  color: var(--ink-4);
  border-top: 1px solid var(--line);
  padding-top: 10px;
  margin-top: auto;
}
.buyer-srp-card-posted {
  color: var(--ink-4);
}
.buyer-srp-card-cta-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--saffron-deep);
  color: #fff;
  text-decoration: none;
  font-size: 12px;
  font-weight: 600;
  padding: 7px 12px;
  border-radius: 6px;
  transition: background 0.15s ease, transform 0.15s ease;
}
.buyer-srp-card-cta-btn:hover {
  background: var(--saffron, #d8a35e);
  transform: translateX(2px);
}

/* Empty state — replaced by .buyers-srp-empty-cta in B12.6;
   keep the legacy class around for any non-SRP fallbacks. */
.buyers-srp-empty {
  grid-column: 1 / -1;
  text-align: center;
  padding: 40px 20px;
  color: var(--ink-3);
}
.buyers-srp-pagination {
  display: flex;
  justify-content: center;
  margin: 24px 0;
}
.buyers-srp-prose,
.buyers-srp-faq {
  margin: 32px 0;
  max-width: 70ch;
}
.buyers-srp-faq details {
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 12px 16px;
  margin: 8px 0;
  background: var(--ivory);
  transition: border-color 0.15s ease;
}
.buyers-srp-faq details[open] {
  border-color: var(--saffron);
  background: var(--ivory-2);
}
.buyers-srp-faq summary {
  cursor: pointer;
  font-weight: 600;
  color: var(--ink);
  list-style: none;
}
.buyers-srp-faq summary::-webkit-details-marker { display: none; }
.buyers-srp-faq summary::before {
  content: "Q";
  display: inline-grid;
  place-items: center;
  width: 18px;
  height: 18px;
  margin-right: 8px;
  border-radius: 4px;
  background: var(--saffron-soft);
  color: var(--saffron-deep);
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  vertical-align: middle;
}

/* ── Stat ribbon under H1 (B12.3) ─────────────────────────────── */
.buyers-srp-stat-ribbon {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 14px 0 18px;
}
.buyers-srp-stat-ribbon-pill {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  padding: 6px 12px;
  background: var(--ivory-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 12px;
  color: var(--ink-3);
}
.buyers-srp-stat-ribbon-pill strong {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

/* ── Hot-zone intro prose (B12.3) ─────────────────────────────── */
.buyers-srp-intro-hot {
  margin: 0 0 20px;
  padding: 14px 18px;
  background: var(--ivory-2);
  border-left: 3px solid var(--saffron);
  border-radius: 0 6px 6px 0;
  color: var(--ink-2);
  max-width: 75ch;
  font-size: 14px;
  line-height: 1.55;
}

/* ── Filter strip uplift (B12.2) ──────────────────────────────── */
.buyers-srp-filter-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  padding: 12px;
  background: var(--ivory-2);
  border: 1px solid var(--line);
  border-radius: 8px;
  margin: 16px 0;
}
.buyers-srp-filter-active {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}
.buyers-srp-filter-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 5px 11px;
  background: var(--ivory);
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 12px;
  color: var(--ink-2);
  text-decoration: none;
  transition: border-color 0.15s ease, background 0.15s ease, transform 0.15s ease;
}
.buyers-srp-filter-chip:hover {
  border-color: var(--saffron);
  transform: translateY(-1px);
}
.buyers-srp-filter-chip.is-active {
  background: var(--saffron-soft);
  border-color: var(--saffron-deep);
  color: var(--saffron-deep);
  font-weight: 600;
}
.buyers-srp-filter-chip--roi { border-color: var(--saffron); }
.buyers-srp-filter-chip-x {
  color: var(--ink-4);
  font-size: 14px;
  line-height: 1;
}
.buyers-srp-filter-chip.is-active .buyers-srp-filter-chip-x { color: var(--saffron-deep); }
.buyers-srp-filter-sort {
  /* Flows inline with the chips at the strip's even 8px gap (no
     margin-left:auto right-align) — with few active chips the pushed-
     right sort left an unbalanced gap. Same on every viewport. */
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  background: var(--ivory);
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 12px;
  color: var(--ink-2);
}
.buyers-srp-filter-sort-label { color: var(--ink-3); }
.buyers-srp-filter-sort-select {
  border: none;
  background: transparent;
  font-size: 12px; /* fs-input-allow — buyers filter strip select, follow-up: --fs-input-sm */
  color: var(--ink);
  cursor: pointer;
  padding: 2px 18px 2px 4px;
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 8px) 50%, calc(100% - 4px) 50%;
  background-size: 4px 4px, 4px 4px;
  background-repeat: no-repeat;
}
.buyers-srp-filter-sort-submit {
  border: none;
  background: var(--saffron-deep);
  color: #fff;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 11px;
  cursor: pointer;
}

/* ── Sibling links — 2-col on desktop (B12.5) ─────────────────── */
.buyers-srp-siblings {
  margin: 28px 0;
  padding: 18px;
  background: var(--ivory-2);
  border: 1px solid var(--line);
  border-radius: 8px;
}
.buyers-srp-siblings-heading {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-2);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin: 0 0 14px;
}
.buyers-srp-siblings-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
}
@media (min-width: 768px) {
  .buyers-srp-siblings-grid { grid-template-columns: repeat(2, 1fr); }
}
.buyers-srp-siblings-group { min-width: 0; }
.buyers-srp-siblings-group-label {
  display: block;
  font-size: 11px;
  font-weight: 600;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin: 0 0 8px;
}
.buyers-srp-siblings-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.buyers-srp-siblings-list li { margin: 0; }
.buyers-srp-siblings-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--ink);
  text-decoration: none;
  font-size: 13px;
  padding: 3px 0;
  transition: color 0.15s ease;
}
.buyers-srp-siblings-link::before {
  content: "+";
  color: var(--saffron-deep);
  font-weight: 700;
  font-family: var(--mono);
}
.buyers-srp-siblings-link:hover { color: var(--saffron-deep); }

/* ── Supply↔Demand bridge band uplift (B12.4) ─────────────────── */
.srp-bridge {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 18px;
  margin: 18px 0;
  border-radius: 8px;
  border: 1px solid var(--line);
  text-decoration: none;
  color: var(--ink);
  font-size: 13px;
  transition: transform 0.18s ease, box-shadow 0.18s ease;
}
.srp-bridge:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
}
.srp-bridge--supply-to-demand {
  background: linear-gradient(90deg, var(--ivory-2) 0%, var(--saffron-soft) 100%);
  border-color: var(--saffron-soft);
}
.srp-bridge--demand-to-supply {
  background: linear-gradient(90deg, var(--saffron-soft) 0%, var(--ivory-2) 100%);
  border-color: var(--saffron-soft);
}
.srp-bridge-icon {
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  background: var(--ivory);
  border-radius: 50%;
  color: var(--saffron-deep);
  flex-shrink: 0;
}
.srp-bridge-icon svg { width: 16px; height: 16px; }
.srp-bridge-body { flex: 1; min-width: 0; }
.srp-bridge-count {
  font-weight: 700;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.srp-bridge-cta {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--saffron-deep);
  font-weight: 600;
  white-space: nowrap;
  flex-shrink: 0;
}

/* ── Zero-state CTA card (B12.6) ──────────────────────────────── */
.buyers-srp-empty-cta {
  grid-column: 1 / -1;
  text-align: center;
  padding: 48px 24px;
  background: var(--ivory);
  border: 1px dashed var(--saffron);
  border-radius: 10px;
}
.buyers-srp-empty-cta-icon {
  width: 56px;
  height: 56px;
  margin: 0 auto 16px;
  display: grid;
  place-items: center;
  background: var(--saffron-soft);
  color: var(--saffron-deep);
  border-radius: 50%;
}
.buyers-srp-empty-cta-icon svg { width: 26px; height: 26px; }
.buyers-srp-empty-cta-title {
  font-size: 17px;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 6px;
}
.buyers-srp-empty-cta-sub {
  font-size: 13px;
  color: var(--ink-3);
  margin-bottom: 18px;
  max-width: 48ch;
  margin-left: auto;
  margin-right: auto;
}
.buyers-srp-empty-cta-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--saffron-deep);
  color: #fff;
  text-decoration: none;
  font-size: 13px;
  font-weight: 600;
  padding: 10px 18px;
  border-radius: 6px;
  transition: background 0.15s ease, transform 0.15s ease;
}
.buyers-srp-empty-cta-btn:hover {
  background: var(--saffron);
  transform: translateY(-1px);
}

/* Mobile collapses stat tiles to 2-col */
@media (max-width: 480px) {
  .buyer-srp-card-stats { grid-template-columns: repeat(2, 1fr); }
  .buyer-srp-card-eyebrow { flex-wrap: wrap; }
}

/* ════════════════════════════════════════════════════════════════════
   BUYER SRP LEAN — Phase 5 mobile parity (2026-06-02)

   The supply-side property SRP got the Phase-5 lean-mobile treatment
   (see "HOME LEAN" + the .ps-* @max-width:700px blocks); the demand-side
   buyer SRP never did — its only mobile rule was the 480px stat-tile
   collapse above + the sibling-grid 768px rule. This block ports the
   SAME decisions the property side shipped, grounded in
   [[mobile-ergonomics-rubric]]: D3 (≥44/48px tap targets), D5 (fluid
   headline), D2 (safe-area on the sticky filter strip), D16 (trust/
   urgency pills ≥22px). Desktop is untouched — every rule is gated
   @max-width:700px except the fluid clamp (continuous, safe at all
   widths) and the safe-area padding (no-op on non-notch viewports).
   ════════════════════════════════════════════════════════════════════ */

/* D5 — fluid H1 (the buyers hero reuses .page-h1; scope to the SRP so
   we don't touch the global heading). Continuous scale, no breakpoint
   pop. Mirrors the property H1's clamp. */
.public-buyers-srp .page-h1 { font-size: clamp(22px, 5.5vw, var(--fs-2xl)); }

@media (max-width: 700px) {
  /* D1/D3 — hero CTA row: stop the two buttons squishing in a no-wrap
     flex. Stack full-width, 48px tall, primary action first (it already
     is in the DOM). Bottom-third reachability for the page's main CTA. */
  .buyers-srp-hero-cta {
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
  }
  .buyers-srp-hero-cta .btn {
    width: 100%;
    min-height: 48px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  /* D3 — the card's primary CTA ("Have a match?"). ~30px/12px font is
     the demand-side twin of the property "Contact at 22px" the brief
     flagged as the #1 SRP fix. Bump to 44px + 15px font, full-width so
     the whole card foot is one reliable thumb target. */
  .buyer-srp-card-foot {
    flex-wrap: wrap;
    row-gap: 10px;
  }
  .buyer-srp-card-cta-btn {
    min-height: 44px;
    font-size: 15px;
    padding: 0 16px;
    justify-content: center;
    flex: 1 1 auto;
  }

  /* D2/D3 — filter strip becomes a sticky, horizontally-scrollable
     single row on phone (was a wrapping block). Sticky-top keeps
     filters reachable while scrolling results (brief decision 2); the
     navbar is 60px (cf. the SRP audit's top:60px). Safe-area padding is
     a no-op off-notch. nowrap + x-scroll + scroll-snap for haptic feel. */
  .buyers-srp-filter-strip {
    position: sticky;
    top: 60px;
    z-index: 20;
    flex-wrap: nowrap;
    overflow-x: auto;
    scroll-snap-type: x proximity;
    -webkit-overflow-scrolling: touch;
    padding-top: max(12px, var(--inset-top));
    /* hide the scrollbar but keep scrollability */
    scrollbar-width: none;
  }
  .buyers-srp-filter-strip::-webkit-scrollbar { display: none; }
  /* Flatten the active-chips wrapper into the strip so EVERY pill —
     active chips, the ROI toggle, the sort control — is a direct flex
     child sharing the strip's single 8px gap + align-items:center.
     Without this, active chips sit one level deeper (their own 6px gap,
     own baseline) → uneven spacing + height vs the toggle/sort. */
  .buyers-srp-filter-active {
    display: contents;
  }

  /* D3 — filter chips 40px min (brief decision 3: 36→40, never below on
     a primary surface). Each chip is an x-removable filter — must not
     misfire. scroll-snap aligns chips as the user swipes. */
  .buyers-srp-filter-chip {
    min-height: 40px;
    padding: 0 14px;
    flex-shrink: 0;
    scroll-snap-align: start;
  }
  /* The × hit-area inside an active chip — give it real width so
     removing a filter doesn't depend on a pixel-perfect tap on "×". */
  .buyers-srp-filter-chip-x {
    font-size: 16px;
    padding: 0 2px;
  }

  /* D3 — sort control 40px; the native <select> inside inherits the
     height so the OS picker opens on a comfortable tap. (Even spacing
     is handled by the base rule, which no longer right-aligns sort.) */
  .buyers-srp-filter-sort {
    min-height: 40px;
    flex-shrink: 0;
  }
  .buyers-srp-filter-sort-select {
    min-height: 40px;
  }

  /* D16 — trust + urgency pills are trust-load-bearing, never sub-22px.
     The 3px vertical padding + 11px font lands ~20px; nudge to a 22px
     floor on mobile. */
  .buyer-srp-card-urgency,
  .buyer-srp-card-trust-pill {
    min-height: 22px;
  }

  /* D3 — pagination: the shared roi-paginator is 34px (below floor).
     Bump to 44px on phone only, scoped to the buyer SRP so the app-wide
     paginator density elsewhere is unchanged (brief decision 5). */
  .buyers-srp-pagination .roi-pag-num,
  .buyers-srp-pagination .roi-pag-step {
    min-width: 44px;
    height: 44px;
  }

  /* D4 — card body copy: the intent line + budget read at 15px (already
     fine); the eyebrow meta at 11px is acceptable for mono labels. No
     change needed — noted so a future pass doesn't "fix" what's correct. */
}

/* ════════════════════════════════════════════════════════════════════
   BUYER PAN-INDIA HUB — Phase B7 (2026-06-02)

   City-list directory at the segment-root URL (/{segment} with no city).
   Hub-and-spoke: city cards → city SRPs. Mobile-first per
   [[mobile-ergonomics-rubric]]: D6 (auto-fit grid, no breakpoint flips),
   D3 (whole card is a ≥48px tap target), D5 (fluid H1 via the shared
   .public-buyers-srp clamp — reused below).
   ════════════════════════════════════════════════════════════════════ */
.public-buyers-hub { padding-bottom: 60px; }
.public-buyers-hub .page-h1 { font-size: clamp(24px, 6vw, var(--fs-2xl)); }
.buyers-hub-hero { padding: 24px 0 8px; }
.buyers-hub-sub {
  color: var(--ink-3);
  font-size: 15px;
  line-height: 1.6;
  max-width: 64ch;
  margin: 12px 0;
}
.buyers-hub-hero-cta { margin-top: 16px; }

/* D6 — content-driven city grid; collapses cleanly 320→desktop. */
.buyers-hub-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 12px;
  margin: 24px 0;
}

/* D3 — each card is one large tap target (>48px). */
.buyers-hub-city-card {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 64px;
  padding: 14px 16px;
  background: var(--ivory);
  border: 1px solid var(--line);
  border-radius: 10px;
  text-decoration: none;
  color: var(--ink);
  transition: border-color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
}
.buyers-hub-city-card:hover {
  border-color: var(--saffron);
  transform: translateY(-2px);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.06);
}
.buyers-hub-city-name {
  font-weight: 600;
  font-size: 16px;
  line-height: 1.2;
}
.buyers-hub-city-count {
  margin-left: auto;
  font-size: 12px;
  color: var(--ink-3);
  white-space: nowrap;
}
.buyers-hub-city-arrow {
  color: var(--saffron-deep);
  font-weight: 600;
  flex-shrink: 0;
}

@media (max-width: 700px) {
  /* D1/D3 — hero CTA full-width thumb target on phone. */
  .buyers-hub-hero-cta .btn {
    width: 100%;
    min-height: 48px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
  /* Single column on the narrowest phones so the count never wraps
     awkwardly under a long city name. auto-fill handles tablet+. */
  .buyers-hub-grid { grid-template-columns: 1fr; }
}

/* ── Homepage live-pulse strip ────────────────────────────────── */
.ph-live-pulse {
  padding: 12px 0;
  background: var(--ivory-2);
  border-bottom: 1px solid var(--line);
}
.ph-live-pulse-inner {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 24px;
  display: flex;
  align-items: center;
  gap: 24px;
  flex-wrap: wrap;
}
.ph-live-pulse-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--ink-3);
  font-size: 11px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}
.ph-live-pulse-dot {
  width: 8px;
  height: 8px;
  background: var(--saffron-deep);
  border-radius: 50%;
  animation: dashMatchPulse 1.5s ease-in-out infinite;
}
.ph-live-pulse-stats { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.ph-live-pulse-stat { display: inline-flex; align-items: baseline; gap: 6px; }
.ph-live-pulse-stat strong {
  font-size: 18px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.ph-live-pulse-sep { color: var(--ink-4); }

/* ── Compose computing interstitial ───────────────────────────── */
.compose-computing { padding: 40px 24px; }
.compose-computing-pulse {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin: 16px 0;
  padding: 10px 14px;
  background: var(--ivory-2);
  border: 1px solid var(--line);
  border-radius: 4px;
}
.compose-computing-pulse[data-state="queued"] .compose-computing-pulse-dot,
.compose-computing-pulse[data-state="computing"] .compose-computing-pulse-dot {
  animation: dashMatchPulse 1.5s ease-in-out infinite;
}
.compose-computing-pulse-dot {
  width: 10px;
  height: 10px;
  background: var(--saffron-deep);
  border-radius: 50%;
}
.compose-computing-pulse-label { font-weight: 500; }
.compose-computing-pulse-elapsed { color: var(--ink-3); }
.compose-computing-counts {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
  margin: 20px 0;
  max-width: 600px;
}
.compose-computing-counts > div {
  padding: 12px;
  background: var(--ivory);
  border: 1px solid var(--line);
  border-radius: 5px;
}
.compose-computing-counts dt { color: var(--ink-3); font-size: 11px; }
.compose-computing-counts dd { font-size: 22px; font-weight: 600; margin: 4px 0 0; }
.compose-computing-error {
  padding: 16px;
  background: oklch(0.96 0.04 30);
  border: 1px solid oklch(0.75 0.10 30);
  border-radius: 5px;
  max-width: 600px;
  margin: 16px 0;
}
.compose-computing-actions { margin-top: 16px; }

/* ── Listing compose inline match preview pane ────────────────── */
.compose-match-preview {
  margin-top: 24px;
  padding: 16px;
  background: var(--ivory-2);
  border: 1px solid var(--line);
  border-radius: 6px;
  position: sticky;
  bottom: 16px;
}
.compose-match-preview-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 10px;
}
.compose-match-preview-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--ink-3);
  font-size: 11px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}
.compose-match-preview-pulse {
  width: 8px;
  height: 8px;
  background: var(--saffron-deep);
  border-radius: 50%;
  animation: dashMatchPulse 1.5s ease-in-out infinite;
}
.compose-match-preview-count { font-weight: 600; color: var(--saffron-deep); }
.compose-match-preview-samples {
  list-style: none;
  padding: 0;
  margin: 8px 0 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.compose-match-preview-sample {
  padding: 8px 10px;
  background: var(--ivory);
  border-radius: 4px;
  border: 1px solid var(--line);
}
.compose-match-preview-sample-head { display: flex; justify-content: space-between; }
.compose-match-preview-sample-initials { font-family: var(--mono); font-weight: 600; }
.compose-match-preview-sample-score { color: var(--saffron-deep); }
.compose-match-preview-sample-meta {
  display: flex;
  justify-content: space-between;
  margin-top: 4px;
}
.compose-match-preview-empty,
.compose-match-preview-hint {
  color: var(--ink-3);
  margin-top: 8px;
}

/* ── Buyer compose wizard ───────────────────────────────────────
   All rules scoped to `.compose-buyer-wizard` so the bare-`.wizard-*`
   classes (`.wizard-strip*`, `.wizard-chip*`, `.wizard-locality-rank*`,
   `.wizard-preview-*`, `.wizard-actions`, etc.) can't collide with the
   older listing-wizard chrome at L843+ (which uses its own
   `.wizard-step*` family). Only the buyer wizard's step CONTAINER
   shares `.wizard-step` with the listing wizard — that one is scoped
   below; everything else lives under `.compose-buyer-wizard`. */

/* Shell — single comfortable max-width that contains the recap chip
   strip (full row at top) AND the form column (also full row, no
   horizontal split). 1100px reads well for form-grid-N layouts; the
   recap chips wrap to additional rows when there are many. */
.compose-buyer-wizard { max-width: 1100px; margin: 0 auto; padding: 24px 32px; }

/* Layout container — previously a 2-col grid with sticky sidebar;
   reworked to a single-column flow so the form gets the full shell
   width and the recap renders inline above the form as a horizontal
   chip strip (see .wizard-recap below). Class kept for blade
   compatibility, rule body intentionally minimal. */
.compose-buyer-wizard .wizard-layout {
  display: block;
}

/* Horizontal recap strip. Each filled piece of state becomes a chip
   inline above the form, wrapping to multiple rows on narrow
   viewports. Hides via Alpine when nothing's been filled yet. */
.compose-buyer-wizard .wizard-recap {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 0 0 24px;
  padding: 12px 16px;
  background: var(--ivory-2);
  border: 1px solid var(--line);
  border-radius: 8px;
}
/* "YOUR BUYER SO FAR" mono prefix on the strip. */
.compose-buyer-wizard .wizard-recap-head {
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-4);
  font-family: var(--mono);
  font-size: 11px;
  margin-right: 6px;
  flex-shrink: 0;
}
/* Individual recap chip. Blade still renders (label, value) inside
   each item; only the value shows visually — the label is hidden
   (the chip's value speaks for itself by context). */
.compose-buyer-wizard .wizard-recap-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 12px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 13px;
  color: var(--ink-2);
}
.compose-buyer-wizard .wizard-recap-label {
  display: none;  /* legacy label hidden — value alone is the chip */
}
.compose-buyer-wizard .wizard-recap-value {
  font-size: 13px;
  color: var(--ink-2);
}
.compose-buyer-wizard .wizard-recap-sub {
  color: var(--ink-3);
}

/* Main column wrapper — full shell width now that the recap is
   inline above. Form sections inside use their own grid widths
   (form-grid-2/3/6 etc.) to lay out within the available space. */
.compose-buyer-wizard .wizard-main {
  min-width: 0;
}

/* Step indicator (top strip) */
.compose-buyer-wizard .wizard-strip { margin-bottom: 24px; }
.compose-buyer-wizard .wizard-strip-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}
.compose-buyer-wizard .wizard-start-over-form { margin: 0; }
.compose-buyer-wizard .wizard-start-over {
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 5px 12px;
  font-size: 12px;
  color: var(--ink-3);
  cursor: pointer;
  font-family: inherit;
  letter-spacing: 0.02em;
  transition: border-color 0.15s, color 0.15s;
}
.compose-buyer-wizard .wizard-start-over:hover {
  border-color: var(--red);
  color: var(--red);
}
.compose-buyer-wizard .wizard-strip-steps {
  list-style: none;
  padding: 0;
  margin: 16px 0 0;
  display: flex;
  gap: 6px;
  overflow-x: auto;
}
.compose-buyer-wizard .wizard-strip-step {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  background: var(--ivory-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 12px;
  cursor: default;
  white-space: nowrap;
}
.compose-buyer-wizard .wizard-strip-step--visited { cursor: pointer; }
.compose-buyer-wizard .wizard-strip-step--visited:hover { border-color: var(--saffron); }
.compose-buyer-wizard .wizard-strip-step--active {
  background: var(--ink);
  color: var(--ivory);
  border-color: var(--ink);
}
.compose-buyer-wizard .wizard-strip-num { font-family: var(--mono); }
.compose-buyer-wizard .wizard-autosave-hint {
  color: var(--ink-4);
  font-size: 11px;
  margin: 4px 0 16px;
}

/* Step container + action footer.
   `display: block` is required to override the base `.wizard-step {
   display: flex; flex: 1 1 0; }` at L859 (listing-wizard step
   INDICATOR — totally different concept from this step CONTAINER).
   Without this, the listing-wizard's flex-row leaks into every buyer
   wizard step and renders headline/fieldsets/actions side-by-side. */
.compose-buyer-wizard .wizard-step { display: block; padding: 16px 0; }
.compose-buyer-wizard .wizard-actions {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin-top: 24px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
}

/* Chip-grid inputs (multi-select for tags / preferences) */
.compose-buyer-wizard .wizard-chip-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
}
.compose-buyer-wizard .wizard-chip {
  padding: 6px 12px;
  background: var(--ivory-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 13px;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}
.compose-buyer-wizard .wizard-chip:hover { border-color: var(--saffron); }
.compose-buyer-wizard .wizard-chip--active {
  background: var(--saffron-soft);
  border-color: var(--saffron);
  color: var(--saffron-deep);
  font-weight: 500;
}

/* Dual-thumb budget range slider — used on step 3 (Budget) for
   sale / rent / per-bed variants. Two <input type="range"> elements
   are absolutely positioned over a shared track; the filled middle
   band (active range) is drawn via the ::before / ::after pseudos
   on the wrapper, reading position from --fill-from / --fill-to
   CSS variables set inline from Alpine (`budgetFillStyle()` method).
   Only the thumbs receive pointer-events; the bare track is decorative. */
.compose-buyer-wizard .budget-range {
  position: relative;
  height: 44px;
  margin: 16px 0 4px;
  --fill-from: 0%;
  --fill-to: 100%;
}
.compose-buyer-wizard .budget-range::before {
  /* Inactive track */
  content: '';
  position: absolute;
  left: 12px; right: 12px;
  top: 50%;
  height: 4px;
  background: var(--line);
  border-radius: 2px;
  transform: translateY(-50%);
  pointer-events: none;
}
.compose-buyer-wizard .budget-range::after {
  /* Filled middle band (active range) */
  content: '';
  position: absolute;
  left: calc(12px + var(--fill-from) * (100% - 24px) / 100);
  right: calc(12px + (100% - var(--fill-to)) * (100% - 24px) / 100);
  top: 50%;
  height: 4px;
  background: var(--saffron-deep);
  border-radius: 2px;
  transform: translateY(-50%);
  pointer-events: none;
}
.compose-buyer-wizard .budget-range__thumb {
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 100%;
  background: transparent;
  pointer-events: none;
  -webkit-appearance: none;
  appearance: none;
  margin: 0;
  padding: 0;
}
.compose-buyer-wizard .budget-range__thumb:focus {
  outline: none;
}
.compose-buyer-wizard .budget-range__thumb::-webkit-slider-runnable-track {
  background: transparent;
  border: 0;
}
.compose-buyer-wizard .budget-range__thumb::-moz-range-track {
  background: transparent;
  border: 0;
}
.compose-buyer-wizard .budget-range__thumb::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  pointer-events: auto;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--paper);
  border: 2px solid var(--saffron-deep);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
  cursor: grab;
  margin-top: -9px; /* centers thumb on the 4px track */
}
.compose-buyer-wizard .budget-range__thumb::-webkit-slider-thumb:active {
  cursor: grabbing;
  transform: scale(1.08);
}
.compose-buyer-wizard .budget-range__thumb::-moz-range-thumb {
  pointer-events: auto;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--paper);
  border: 2px solid var(--saffron-deep);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
  cursor: grab;
}
/* Max thumb sits above the min thumb so when both coincide the user
   can still grab the max. A future polish pass could swap z-index
   dynamically based on which thumb the click is nearest to. */
.compose-buyer-wizard .budget-range__thumb--max {
  z-index: 2;
}

.compose-buyer-wizard .budget-range-labels {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 12px;
  margin-top: 18px;
}
.compose-buyer-wizard .budget-range-value {
  font-family: var(--serif);
  font-size: 26px;
  letter-spacing: -0.01em;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.compose-buyer-wizard .budget-range-separator {
  font-family: var(--sans);
  font-size: 13px;
  color: var(--ink-4);
  letter-spacing: 0.02em;
}

/* Derived-city confirmation pill — shown after the first locality
   picks resolve to a city (city dropdown stays hidden). Read-only
   chip the broker sees once and forgets; if no city resolves the
   pill stays hidden and the hidden <select> shows for manual pick. */
.compose-buyer-wizard .wizard-derived-city {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 10px 0 0;
  padding: 6px 12px;
  background: var(--ivory-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 13px;
  color: var(--ink-2);
}

/* Locality drag-to-rank list */
.compose-buyer-wizard .wizard-locality-rank {
  list-style: none;
  padding: 0;
  margin: 12px 0 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.compose-buyer-wizard .wizard-locality-rank-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  background: var(--ivory);
  border: 1px solid var(--line);
  border-radius: 4px;
  cursor: move;
}
.compose-buyer-wizard .wizard-locality-rank-pos {
  font-size: 10px;
  letter-spacing: 0.05em;
  color: var(--ink-4);
  min-width: 60px;
}
.compose-buyer-wizard .wizard-locality-rank-pos--primary {
  color: var(--saffron-deep);
  font-weight: 600;
}
.compose-buyer-wizard .wizard-locality-rank-name { flex: 1; }
.compose-buyer-wizard .wizard-locality-rank-x {
  background: transparent;
  border: none;
  color: var(--ink-4);
  cursor: pointer;
  font-size: 18px;
  padding: 0 6px;
}
.compose-buyer-wizard .wizard-locality-rank-x:hover { color: var(--saffron-deep); }

/* Consent + check rows */
.compose-buyer-wizard .wizard-check {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 0;
  cursor: pointer;
}
.compose-buyer-wizard .wizard-consent { background: var(--ivory-2); padding: 16px; border-radius: 6px; }

/* Inline match preview ("X listings would match now") */
.compose-buyer-wizard .wizard-preview-block {
  margin: 20px 0;
  padding: 14px;
  background: var(--ivory-2);
  border: 1px solid var(--line);
  border-radius: 6px;
}
.compose-buyer-wizard .wizard-preview-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 10px;
}
.compose-buyer-wizard .wizard-preview-samples {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin: 8px 0;
}
.compose-buyer-wizard .wizard-preview-sample {
  display: flex;
  gap: 8px;
  padding: 6px 10px;
  background: var(--ivory);
  border-radius: 4px;
  font-size: 13px;
}

/* Publish-step server-error banner */
.compose-buyer-wizard .wizard-publish-errors {
  margin-top: 12px;
  padding: 12px;
  background: var(--red-soft);
  border: 1px solid var(--red);
  border-radius: 5px;
}

/* Form-section title modifier (right-aligned aside next to legend) */
.compose-buyer-wizard .form-section-title-aside {
  font-weight: 400;
  color: var(--ink-4);
  margin-left: 8px;
}

/* ── Mobile collapse for the matches feed 3-column grid ───────── */
@media (max-width: 900px) {
  .match-pair-grid {
    grid-template-columns: 1fr;
    gap: 12px;
  }
  .match-dial {
    flex-direction: row;
    justify-content: center;
    gap: 12px;
  }
  .dash-match-hero-counts {
    grid-template-columns: repeat(2, 1fr);
  }
  .dash-match-hero-thumbs {
    grid-template-columns: 1fr;
  }
}

/* ── Matches "How it works" documentation page ───────────────── */
.matches-docs { max-width: 760px; margin: 0 auto; padding: 32px 24px 80px; }
.matches-docs-lede {
  font-size: 17px;
  color: var(--ink-3);
  margin: 12px 0 32px;
  line-height: 1.55;
  max-width: 60ch;
}
.matches-docs-section {
  margin: 36px 0;
  padding-bottom: 28px;
  border-bottom: 1px solid var(--line);
}
.matches-docs-section:last-child { border-bottom: none; }
.matches-docs-section h2 {
  font-family: var(--serif, var(--font-serif, serif));
  font-size: 24px;
  margin: 0 0 14px;
}
.matches-docs-section p { line-height: 1.6; margin: 8px 0; }
.matches-docs-section ul,
.matches-docs-section ol {
  line-height: 1.6;
  margin: 12px 0;
  padding-left: 24px;
}
.matches-docs-section li { margin: 4px 0; }
.matches-docs-table {
  width: 100%;
  border-collapse: collapse;
  margin: 14px 0;
  font-size: 14px;
}
.matches-docs-table th,
.matches-docs-table td {
  padding: 8px 12px;
  text-align: left;
  border-bottom: 1px solid var(--line);
}
.matches-docs-table th {
  background: var(--ivory-2);
  font-weight: 600;
  letter-spacing: 0.02em;
}
.matches-docs-table tfoot td {
  background: var(--ivory-2);
  border-top: 2px solid var(--ink-4);
}
.matches-docs-note {
  color: var(--ink-3);
  background: var(--ivory-2);
  padding: 10px 14px;
  border-left: 3px solid var(--saffron);
  border-radius: 0 4px 4px 0;
  margin: 14px 0;
}
.matches-docs-bands {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
  margin: 14px 0;
}
.matches-docs-band {
  padding: 14px 16px;
  background: var(--ivory);
  border: 1px solid var(--line);
  border-radius: 6px;
  border-top: 3px solid var(--ink-4);
}
.matches-docs-band--hot { border-top-color: var(--saffron-deep); }
.matches-docs-band--strong { border-top-color: var(--saffron); }
.matches-docs-band--possible { border-top-color: var(--ink-4); }
.matches-docs-band-label {
  font-family: var(--mono);
  font-weight: 700;
  margin-bottom: 6px;
}
.matches-docs-dl dt {
  font-weight: 600;
  margin-top: 12px;
}
.matches-docs-dl dd { margin: 4px 0 0 16px; color: var(--ink-3); }
.matches-docs-section--cta {
  text-align: center;
  background: var(--ivory-2);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 28px;
  margin-top: 40px;
}
.matches-docs-section--cta .btn { margin: 8px 6px 0; }

.matches-sort-line { margin: 8px 0 6px; }
.matches-howitworks-link {
  color: var(--ink-3);
  text-decoration: none;
  border-bottom: 1px dotted var(--ink-4);
}
.matches-howitworks-link:hover {
  color: var(--saffron-deep);
  border-bottom-color: var(--saffron);
}

@media (max-width: 700px) {
  .matches-docs-bands { grid-template-columns: 1fr; }
}

/* ── Leads inbox: rich cards ──────────────────────────────────────
   Cards replace .lead-row in the inbox grid. The .lead-row-* classes
   stay defined for backward compatibility (any other surface that
   still includes the row partial keeps working). Cards intentionally
   reuse .lead-row-tag and .lead-row-reminder--* color modifiers so
   chip styling stays single-sourced. */

.leads-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
  gap: 12px;
}

.lead-card {
  display: grid;
  grid-template-columns: 0 1fr; /* gutter collapses to 0 until bulk-select silo populates it */
  gap: 0;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--paper);
  transition: border-color 120ms ease, background 120ms ease, box-shadow 120ms ease;
}
/* A lead just moved to Lost (hidden from default view): greyed in place after
   the in-place swap, gone on next reload. Visual de-emphasis only. */
.lead-card--lost {
  opacity: 0.55;
  background: var(--ivory-2, #f5f4f0);
}
.lead-card--lost:hover { opacity: 0.8; }
.lead-card:hover {
  border-color: var(--ink-4);
  background: var(--ivory-2);
  box-shadow: 0 2px 6px -3px rgba(0, 0, 0, 0.08);
}
.lead-card-gutter {
  /* Reserved column for the future bulk-select checkbox (silo: bulk
     actions). Today it's an explicit 0-width placeholder so the
     bulk silo only flips this width to 28px to land the checkbox. */
  width: 0;
}
.lead-card-body {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
}

.lead-card-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  min-width: 0;
}
.lead-card-name-link {
  text-decoration: none;
  color: inherit;
  min-width: 0;
  cursor: pointer;
}
.lead-card-name-link:hover .lead-card-name {
  color: var(--saffron-deep);
}
.lead-card-name {
  font-family: var(--serif);
  font-size: 18px;
  line-height: 1.2;
  color: var(--ink);
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lead-card-captured {
  font-size: 11px;
  color: var(--ink-4);
  flex-shrink: 0;
}

.lead-card-contact {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  font-size: 12px;
  color: var(--ink-3);
}
.lead-card-contact-sep { color: var(--line); }

.lead-card-attached {
  font-size: 12px;
  color: var(--ink-2);
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}
.lead-card-attached-link {
  color: var(--ink-2);
  text-decoration: none;
}
.lead-card-attached-link:hover { text-decoration: underline; color: var(--saffron-deep); }
.lead-card-attached-text { color: var(--ink-3); }
.lead-card-attached-sep { color: var(--line); }
.lead-card-attached-source { color: var(--ink-4); font-size: 11px; }

.lead-card-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  /* Slot row — tag chips (silo: tagging) and score chip (Horizon 3)
     will append here without layout changes. */
}

.lead-card-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  flex-wrap: wrap;
  padding-top: 4px;
  border-top: 1px dashed var(--line);
  margin-top: 2px;
}
.lead-card-status {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  min-width: 0;
}
.lead-card-reminder {
  font-size: 11px;
  font-family: var(--mono);
  letter-spacing: 0.04em;
}
.lead-card-owner {
  font-size: 10px;
  letter-spacing: 0.06em;
  color: var(--ink-4);
}
.lead-card-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}
.lead-card-last {
  font-size: 11px;
  color: var(--ink-3);
}
.lead-card-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  padding: 4px 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink-2);
  font-size: 12px;
  font-family: var(--mono);
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition: border-color 120ms ease, background 120ms ease, color 120ms ease;
}
.lead-card-action:hover { border-color: var(--ink-4); background: var(--ivory-2); }
.lead-card-action.lead-row-action--call:hover {
  border-color: #2a6bb3;
  background: color-mix(in oklab, #4a90e2 12%, var(--paper));
  color: #2a6bb3;
}
.lead-card-action.lead-row-action--wa { color: var(--green); }
.lead-card-action.lead-row-action--wa:hover {
  border-color: var(--green);
  background: color-mix(in oklab, var(--green) 12%, var(--paper));
  color: var(--green);
}
.lead-card-action .channel-icon { display: block; }

@media (max-width: 640px) {
  .leads-grid { grid-template-columns: 1fr; }
  .lead-card { padding: 12px; }
  .lead-card-name { font-size: 16px; }
  .lead-card-footer { gap: 6px; }
}

/* ════════════════════════════════════════════════════════════════════
   CRM Phase 9 — mobile-first broker inbox (2026-06-07)
   Grounded in [[audit_mobile_leads]] vs the ergonomics rubric:
   D2 (safe-area on the drawer + the new needs-response strip),
   D3 (≥48px tap targets on the filter pills, tier pills, quick-contact
   icons, drawer close). Desktop untouched: every tap bump is gated
   ≤800px (the lint's mobile threshold + where the bottom-nav shows),
   and the safe-area padding is a no-op off-notch (--inset-bottom=0).
   ════════════════════════════════════════════════════════════════════ */

/* D2 — the drawer is full-height (top:0/bottom:0) and z-91 (above the
   bottom-nav), so its last action button can sit under the iOS home
   indicator. Pad the scrolling body so it clears. No-op off-notch. */
.lead-drawer-body { padding-bottom: var(--inset-bottom); }

/* Sticky "Needs response" strip — desktop hidden; phone shows it fixed
   directly ABOVE the mobile bottom-nav (which is fixed bottom:0 h:64px). */
.leads-needs-strip { display: none; }

/* Swipe-to-stage (lead-swipe.js): the "release to advance" cue while
   dragging + the undo toast. Only rendered on touch (JS creates the toast
   + adds the class), so base styles can live top-level. */
.lead-card--will-advance { box-shadow: inset 4px 0 0 var(--green, #16a34a); }
.lead-swipe-toast {
  position: fixed;
  left: 16px;
  right: 16px;
  bottom: calc(64px + var(--inset-bottom) + 60px); /* clears the nav + needs-strip */
  z-index: 95;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  background: var(--ink);
  color: var(--paper);
  padding: 10px 16px;
  border-radius: 10px;
  font-size: 13px;
  box-shadow: 0 8px 24px -8px rgba(0, 0, 0, 0.4);
}
.lead-swipe-undo {
  background: none;
  border: 0;
  color: #fbbf24;
  font-weight: 600;
  font-size: 14px;
  cursor: pointer;
  padding: 6px 8px;
  min-height: 44px;
}

@media (max-width: 800px) {
  /* Scroll-safety: the browser owns vertical pan (native scroll); only
     horizontal gestures reach lead-swipe.js, so we never preventDefault. */
  .lead-card { touch-action: pan-y; }

  /* D3 — tap-target floor (var(--tap)=48px) on the primary touch controls.
     The lint is @media-aware (≤800px counts) and these selectors are
     enrolled in scripts/lint-tap-targets.php so they can't regress. */
  .leads-pill,
  .leads-tier-pill,
  .lead-card-action,
  .lead-drawer-close {
    min-height: var(--tap);
    min-width: var(--tap);
  }
  /* The inline stage select is a one-handed primary control — give it
     the floor height too (full-width, so width is already fine). */
  .lead-action-select { min-height: var(--tap); }

  /* Needs-response strip: warn-accent, thumb-zone, above the bottom-nav. */
  .leads-needs-strip {
    display: flex;
    align-items: center;
    gap: 10px;
    position: fixed;
    left: 0;
    right: 0;
    bottom: calc(64px + var(--inset-bottom)); /* directly above the bottom-nav */
    z-index: 29;                              /* just under the nav (z-30) */
    min-height: var(--tap);
    padding: 10px 16px;
    background: #b45309;                       /* amber-700 — matches the warn pill family */
    color: #fff;
    text-decoration: none;
    font-size: 13px;
    box-shadow: 0 -4px 16px -6px rgba(0, 0, 0, 0.3);
  }
  .leads-needs-strip-icon { font-size: 16px; }
  .leads-needs-strip-text { flex: 1; }
  .leads-needs-strip-go { font-size: 18px; opacity: 0.9; }
  /* Keep the last cards / pagination from hiding behind the fixed strip. */
  .leads-grid,
  .leads-table,
  .leads-pagination { margin-bottom: calc(var(--tap) + 8px); }
}

/* ── Lead drawer: slide-in detail panel ──────────────────────────
   Mounted once on /leads (Alpine x-data="leadDrawer()"). Fetches the
   drawer-body Blade partial via /leads/{source}/{id}?_partial=drawer.
   On narrow viewports the drawer becomes a full-width sheet. */

.body--drawer-open { overflow: hidden; }

.lead-drawer-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.32);
  z-index: 90;
}

.lead-drawer {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: min(560px, 100vw);
  background: var(--paper);
  border-left: 1px solid var(--line);
  box-shadow: -8px 0 24px -8px rgba(0, 0, 0, 0.14);
  z-index: 91;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* Alpine transition classes — slide from the right. */
.lead-drawer--enter,
.lead-drawer--leave {
  transition: transform 200ms cubic-bezier(0.22, 0.61, 0.36, 1), opacity 160ms ease;
}
.lead-drawer--enter-start { transform: translateX(100%); opacity: 0; }
.lead-drawer--enter-end   { transform: translateX(0);     opacity: 1; }

.lead-drawer-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 14px;
  border-bottom: 1px solid var(--line);
  background: var(--ivory-2);
  flex-shrink: 0;
}
.lead-drawer-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink-2);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  padding: 0;
  transition: border-color 120ms ease, background 120ms ease;
}
.lead-drawer-close:hover { border-color: var(--ink-4); background: var(--ivory-2); }
.lead-drawer-fullpage {
  font-size: 11px;
  color: var(--ink-3);
  text-decoration: none;
  letter-spacing: 0.04em;
}
.lead-drawer-fullpage:hover { color: var(--ink); text-decoration: underline; }

.lead-drawer-body {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 18px 20px 24px;
  /* The drawer-body partial uses .lead-detail / .lead-detail-grid which
     already have full styling; we just scope the scroll container. */
}
.lead-drawer-skeleton {
  font-size: 12px;
  color: var(--ink-4);
  padding: 24px 4px;
}
.lead-drawer-error {
  font-size: 13px;
  color: var(--ink-2);
  padding: 24px 4px;
}
.lead-drawer-retry {
  color: var(--saffron-deep);
  text-decoration: underline;
}

/* Drawer: inside the narrow column the two-column actions grid from
   .lead-detail-grid would crush; stack it. */
.lead-drawer-body .lead-detail-grid {
  grid-template-columns: 1fr;
}
.lead-drawer-body .lead-detail {
  padding: 0;
}

@media (max-width: 640px) {
  .lead-drawer { width: 100vw; border-left: none; }
}

/* ── Leads: List ↔ Board view toggle ──────────────────────────── */
.leads-view-toggle {
  display: inline-flex;
  padding: 3px;
  background: var(--ivory-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 12px;
  font-family: var(--mono);
  margin-bottom: 10px;
  width: fit-content;
}
.leads-view-toggle-btn {
  padding: 4px 12px;
  border-radius: 999px;
  color: var(--ink-3);
  text-decoration: none;
  letter-spacing: 0.04em;
  font-weight: 600;
  transition: background 120ms ease, color 120ms ease;
}
.leads-view-toggle-btn:hover { color: var(--ink-2); }
.leads-view-toggle-btn--active {
  background: var(--ink);
  color: var(--paper);
}
.leads-view-toggle-btn--active:hover { color: var(--paper); }

/* ── Leads kanban board ───────────────────────────────────────── */
/* `.page-inner-fluid` is the wide container the board sits in —
   the regular `.matches-wide` cap is too narrow for 6 columns of
   ~320px cards. Board mode opts out of the page-width cap and
   lets the horizontal scroll carry overflow. */
.page-inner-fluid {
  width: 100%;
  padding: 0 24px;
}

.kanban-board {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(300px, 1fr);
  gap: 14px;
  overflow-x: auto;
  padding-bottom: 12px;
  align-items: start;
  /* Board takes the rest of the viewport height; columns scroll
     internally so the page itself doesn't grow infinitely. */
  max-height: calc(100vh - 280px);
  min-height: 480px;
}
.kanban-board::-webkit-scrollbar { height: 8px; }
.kanban-board::-webkit-scrollbar-thumb { background: var(--line); border-radius: 4px; }

.kanban-column {
  display: flex;
  flex-direction: column;
  background: var(--ivory-2);
  border: 1px solid var(--line);
  border-radius: 12px;
  overflow: hidden;
  max-height: 100%;
  min-width: 0;
}
.kanban-column--lost {
  background: var(--paper);
  opacity: 0.75;
}
.kanban-column-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 14px;
  border-bottom: 1px solid var(--line);
  background: var(--paper);
  flex-shrink: 0;
}
.kanban-column-title {
  font-family: var(--serif);
  font-size: 14px;
  color: var(--ink);
  letter-spacing: 0.01em;
}
.kanban-column-count {
  font-size: 11px;
  font-family: var(--mono);
  font-weight: 600;
  color: var(--ink-3);
  background: var(--ivory-2);
  padding: 2px 8px;
  border-radius: 999px;
  min-width: 24px;
  text-align: center;
}
.kanban-column-list {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 10px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 80px;
}
.kanban-column-list .lead-card {
  /* In board context the card has no grid neighbors; let it fill the
     column width and shed the dual-column gutter layout that the
     list view's grid imposes. */
  grid-template-columns: 1fr;
  cursor: grab;
}
.kanban-column-list .lead-card-gutter { display: none; }
.kanban-column-list .lead-card:active { cursor: grabbing; }
.kanban-column-empty {
  font-size: 11px;
  color: var(--ink-4);
  text-align: center;
  padding: 24px 8px;
}
.kanban-column-overflow {
  font-size: 11px;
  color: var(--ink-3);
  padding: 8px 12px;
  border-top: 1px solid var(--line);
  background: var(--paper);
  text-align: center;
  flex-shrink: 0;
}
.kanban-column-overflow a {
  color: var(--saffron-deep);
  text-decoration: underline;
}

/* SortableJS visual feedback. `--ghost` is the placeholder slot in the
   source column while dragging; `--drag` is the floating clone the
   user sees under the cursor. */
.kanban-card--ghost {
  opacity: 0.35;
  background: var(--ivory-2);
  border-style: dashed;
}
.kanban-card--drag {
  box-shadow: 0 8px 24px -6px rgba(0, 0, 0, 0.22);
  transform: rotate(0.5deg);
}

@media (max-width: 900px) {
  /* Board on tablets: let columns shrink a bit more before the
     horizontal scroll kicks in. */
  .kanban-board { grid-auto-columns: minmax(260px, 1fr); }
}
@media (max-width: 640px) {
  /* Phones: one column at a time, swipe to reveal next. */
  .kanban-board { grid-auto-columns: 88vw; max-height: none; }
  .page-inner-fluid { padding: 0 12px; }
}

/* ── Leads: saved-views row ─────────────────────────────────────── */
.leads-saved-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  margin-bottom: 8px;
  background: color-mix(in oklab, var(--saffron) 6%, var(--paper));
  border: 1px solid color-mix(in oklab, var(--saffron) 28%, var(--line));
  border-radius: 10px;
}
.leads-saved-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 12px;
  border: 1px solid var(--line);
  background: var(--paper);
  border-radius: 999px;
  color: var(--ink-2);
  font-size: 12px;
  font-family: var(--mono);
  font-weight: 600;
  letter-spacing: 0.02em;
  text-decoration: none;
  transition: border-color 120ms ease, background 120ms ease;
}
.leads-saved-chip:hover {
  border-color: var(--saffron-deep);
  background: color-mix(in oklab, var(--saffron) 14%, var(--paper));
}
.leads-saved-chip--pinned { font-weight: 700; }
.leads-saved-chip--pinned span { color: var(--saffron-deep); }
.leads-saved-remove { display: inline-flex; margin-right: 4px; }
.leads-saved-remove-btn {
  border: none;
  background: transparent;
  color: var(--ink-4);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  padding: 0 4px;
}
.leads-saved-remove-btn:hover { color: var(--accent); }

/* ── Leads: extra filter chrome ─────────────────────────────────── */
.leads-pill--ghost {
  background: transparent;
  border-style: dashed;
  color: var(--ink-3);
}
.leads-pill--accent {
  border-color: var(--saffron-deep);
  color: var(--saffron-deep);
  background: color-mix(in oklab, var(--saffron) 10%, var(--paper));
}
.leads-pill--accent:hover { background: color-mix(in oklab, var(--saffron) 18%, var(--paper)); }

.leads-range-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  margin-top: 4px;
  background: var(--ivory-2);
  border: 1px dashed var(--line);
  border-radius: 8px;
}
.leads-range-label {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  color: var(--ink-3);
  letter-spacing: 0.04em;
}
.leads-range-input {
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 4px 8px;
  font-family: var(--mono);
  font-size: 12px; /* fs-input-allow — narrow range cell, follow-up: --fs-input-sm */
  background: var(--paper);
  color: var(--ink);
}
.leads-range-clear {
  color: var(--ink-3);
  font-size: 11px;
  text-decoration: underline;
  margin-left: auto;
}
.leads-range-clear:hover { color: var(--accent); }

/* ── Save-view modal ────────────────────────────────────────────── */
.save-view-modal {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(480px, calc(100vw - 32px));
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 12px;
  box-shadow: 0 18px 48px -12px rgba(0, 0, 0, 0.28);
  z-index: 95;
  display: flex;
  flex-direction: column;
  max-height: 80vh;
  overflow: hidden;          /* clip to the rounded container so the body
                                scrolls INSIDE instead of spilling out */
}
.save-view-modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 18px;
  border-bottom: 1px solid var(--line);
}
.save-view-modal-title {
  font-family: var(--serif);
  font-size: 18px;
  color: var(--ink);
  margin: 0;
}
.save-view-modal-body {
  padding: 16px 18px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  overflow-y: auto;
  /* flex:1 + min-height:0 = the flexbox-scroll fix: the body shrinks to fit
     the modal's max-height and scrolls internally instead of overflowing
     (which was pushing the last fields off-screen / behind the bottom nav). */
  flex: 1 1 auto;
  min-height: 0;
}
.save-view-label {
  font-size: 11px;
  color: var(--ink-3);
  letter-spacing: 0.04em;
}
.save-view-label--inline {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--ink-2);
}
.save-view-input {
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 8px 10px;
  font-size: var(--fs-input);
  background: var(--paper);
  color: var(--ink);
}
.save-view-input:focus { outline: 2px solid var(--saffron); outline-offset: -2px; }
.save-view-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  font-size: 11px;
  color: var(--ink-3);
  background: var(--ivory-2);
  border-radius: 6px;
  padding: 8px 10px;
}
.save-view-summary span {
  display: inline-block;
  padding: 1px 6px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 4px;
}
.save-view-modal-foot {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 12px 18px;
  border-top: 1px solid var(--line);
  /* Pin the footer (with the "Add lead" submit) so the body scrolls beneath
     it instead of pushing it off the bottom of the modal. */
  flex-shrink: 0;
  background: var(--paper);
}

/* ── Reply templates (Phase 7a) ─────────────────────────────────── */
/* Quick-insert chips above the drawer composer. */
.lead-templates {
  margin: 8px 0 4px;
}
.lead-templates-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.lead-templates-manage {
  border: 0;
  background: none;
  color: var(--saffron);
  font-size: 12px;
  cursor: pointer;
  padding: 2px 4px;
  min-height: 32px;        /* keep it tappable */
}
.lead-templates-manage:hover { text-decoration: underline; }
.lead-templates-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 4px;
}
.lead-templates-empty {
  font-size: 11px;
  color: var(--ink-3);
}
.lead-template-chip {
  border: 1px solid var(--line);
  background: var(--ivory-2);
  color: var(--ink-2);
  border-radius: 14px;
  padding: 5px 12px;
  font-size: 12px;
  cursor: pointer;
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-height: 32px;
}
.lead-template-chip:hover {
  border-color: var(--saffron);
  background: var(--paper);
}

/* Manage modal — list + create/edit form. Shares .save-view-modal chrome. */
.templates-modal { width: min(540px, calc(100vw - 32px)); }
.templates-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.templates-list-item {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--ivory-2);
}
.templates-list-main {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.templates-list-name {
  font-weight: 600;
  font-size: 13px;
  color: var(--ink);
}
.templates-list-badge {
  display: inline-block;
  font-size: 10px;
  letter-spacing: 0.04em;
  color: var(--ink-3);
  text-transform: uppercase;
}
.templates-list-body {
  font-size: 11px;
  color: var(--ink-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 360px;
}
.templates-list-actions {
  display: flex;
  gap: 4px;
  flex-shrink: 0;
}
.templates-list-empty {
  font-size: 12px;
  color: var(--ink-3);
  padding: 4px 0;
}
.templates-form {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px dashed var(--line);
}
.templates-form-hint {
  font-size: 11px;
  color: var(--ink-3);
}
.templates-form-hint code {
  background: var(--ivory-2);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 0 4px;
}
.templates-form-row {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

/* ── Super-admin impersonation banner ───────────────────────────── */
.impersonation-banner {
  position: sticky;
  top: 0;
  z-index: 999;
  background: linear-gradient(90deg, #c2410c, #ea580c);
  color: #fff;
  border-bottom: 2px solid #9a3412;
  box-shadow: 0 2px 6px rgba(0,0,0,0.18);
}
.impersonation-banner-inner {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 16px;
  max-width: 1400px;
  margin: 0 auto;
  font-size: 13px;
}
.impersonation-banner-pulse {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #fde68a;
  box-shadow: 0 0 0 0 rgba(253, 230, 138, 0.7);
  animation: imp-pulse 1.6s infinite;
  flex: 0 0 auto;
}
@keyframes imp-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(253, 230, 138, 0.7); }
  70%  { box-shadow: 0 0 0 10px rgba(253, 230, 138, 0); }
  100% { box-shadow: 0 0 0 0 rgba(253, 230, 138, 0); }
}
.impersonation-banner-text { flex: 1 1 auto; }
.impersonation-banner-meta {
  opacity: 0.85;
  font-size: 11.5px;
  margin-left: 4px;
}
.impersonation-banner-exit { margin: 0; }
.impersonation-banner-btn {
  background: rgba(255,255,255,0.18);
  border: 1px solid rgba(255,255,255,0.35);
  color: #fff;
  padding: 4px 12px;
  border-radius: 6px;
  font-size: 12px;
  cursor: pointer;
  font-family: inherit;
}
.impersonation-banner-btn:hover {
  background: rgba(255,255,255,0.28);
}
/* Slight outline on the body when impersonating so the super-admin
   never forgets they're not seeing their own UI. */
.body--impersonating {
  outline: 3px solid rgba(234, 88, 12, 0.5);
  outline-offset: -3px;
}

/* ── Seeker dashboard — fresh-since-last-visit + quick actions ──── */
.seeker-fresh-callout {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 12px 0 16px;
  padding: 10px 14px;
  background: rgba(34, 197, 94, 0.07);
  border: 1px solid rgba(34, 197, 94, 0.30);
  border-radius: 8px;
  color: var(--ink);
  font-size: 14px;
}
.seeker-fresh-pulse {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #16a34a;
  box-shadow: 0 0 0 0 rgba(22, 163, 74, 0.5);
  animation: seeker-fresh-pulse 2s infinite;
  flex: 0 0 auto;
}
@keyframes seeker-fresh-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(22, 163, 74, 0.55); }
  70%  { box-shadow: 0 0 0 10px rgba(22, 163, 74, 0); }
  100% { box-shadow: 0 0 0 0 rgba(22, 163, 74, 0); }
}

.seeker-quick-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 24px;
}
.seeker-quick-action {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--ink);
  text-decoration: none;
  font-size: 13px;
  transition: background 0.15s, border-color 0.15s;
}
.seeker-quick-action:hover {
  background: var(--ivory-2);
  border-color: var(--ink-4);
}
.seeker-quick-action-badge {
  background: rgba(220, 38, 38, 0.10);
  color: #b91c1c;
  border-radius: 999px;
  padding: 1px 7px;
  font-size: 11px;
}

/* ── My enquiries (seeker outbound inbox) ───────────────────────── */
.my-enquiries-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
  margin-top: 16px;
}
@media (min-width: 900px) {
  .my-enquiries-grid { grid-template-columns: 1fr 1fr; }
}
.my-enquiry-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 14px 16px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 10px;
}
.my-enquiry-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.my-enquiry-broker {
  display: flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  color: inherit;
  min-width: 0;
}
.my-enquiry-broker-info {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.my-enquiry-broker-name { font-weight: 600; color: var(--ink); }
.my-enquiry-firm { color: var(--ink-3); }
.my-enquiry-status {
  background: var(--ivory-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 3px 10px;
  color: var(--ink-3);
  white-space: nowrap;
  font-size: 11px;
}
.my-enquiry-status--ok {
  background: rgba(34,197,94,0.08);
  border-color: rgba(34,197,94,0.35);
  color: #15803d;
}
.my-enquiry-listing {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding-top: 8px;
  border-top: 1px dashed var(--line);
}
.my-enquiry-listing-link {
  color: var(--ink);
  text-decoration: none;
}
.my-enquiry-listing-link:hover { text-decoration: underline; }
.my-enquiry-listing-meta { color: var(--ink-3); }
.my-enquiry-card-foot {
  display: flex;
  gap: 6px;
  color: var(--ink-3);
}
.my-enquiry-channel { font-weight: 600; }

.impersonate-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 10px;
}
.impersonate-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--paper);
}
.impersonate-row-info { display: flex; flex-direction: column; gap: 2px; }

/* ── Manual lead entry modal ────────────────────────────────────── */
.manual-lead-modal { width: min(620px, calc(100vw - 32px)); }
.manual-lead-body { gap: 14px; }
.manual-lead-row { display: flex; flex-direction: column; gap: 4px; }
.manual-lead-label { font-size: 11px; color: var(--ink-3); letter-spacing: 0.04em; }
.manual-lead-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
@media (max-width: 480px) {
  .manual-lead-grid { grid-template-columns: 1fr; }
}
.manual-lead-error {
  color: var(--accent-red, #b00020);
  font-size: 11px;
  margin: 2px 0 0;
}
.manual-lead-consent {
  background: var(--ivory-2);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 8px 10px;
  align-items: flex-start;
  line-height: 1.4;
}



/* ── Intro edit + withdraw ─────────────────────────────────────
 * Withdrawn intros and declined/expired ones share an inert
 * visual treatment — greyed-out, lower contrast, no actions.
 * The two edit/withdraw buttons sit inline next to status badge
 * on outgoing pending intros.
 */
.intro-card--inert {
  opacity: 0.6;
  background: var(--ivory-2);
}
.intro-card--inert .intro-card-name { color: var(--ink-3); }
.intro-card--inert blockquote.intro-card-note { color: var(--ink-3); font-style: italic; }
.intro-edit-withdraw-form {
  display: inline-flex;
  margin-left: 8px;
}
.intro-edit-withdraw-btn {
  color: var(--ink-3);
}
.intro-edit-withdraw-btn:hover {
  color: oklch(0.45 0.18 30);
  border-color: oklch(0.65 0.12 30);
}
.intro-card-actions form.intro-decline-form { display: inline-flex; gap: 6px; align-items: center; }

.page-flash--error {
  background: oklch(0.96 0.04 30);
  border: 1px solid oklch(0.75 0.10 30);
  color: oklch(0.35 0.15 30);
}

/* ========== Buyer-question surface on broker lead-inbox row =====
   Highlights leads that carry a free-text question so the broker
   sees them as actionable. The "Answer" link routes to the new
   ListingQuestionController; "Answered" state stays visually
   present so the broker can re-edit / toggle publicity. */
.lead-row-question {
  margin-top: 8px;
  padding: 10px 12px;
  background: var(--ivory-2, #faf3e3);
  border-radius: 8px;
  border-left: 3px solid var(--accent);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.lead-row-question-q {
  color: var(--ink, #1a1a1a);
  flex: 1;
  line-height: 1.4;
}
.lead-row-question-cta {
  flex-shrink: 0;
  padding: 4px 10px;
  background: var(--accent);
  color: var(--paper);
  border-radius: 6px;
  font-size: 12px;
  font-weight: 600;
  text-decoration: none;
}
.lead-row-question-cta:hover { opacity: 0.9; }
.lead-row-question-cta--answered {
  background: var(--surface-2);
  color: var(--ink-2, #555);
  border: 1px solid var(--border);
}

/* Answer-buyer-question form (broker side). */
.listing-question-card {
  margin: 16px 0;
  padding: 14px 16px;
  background: var(--ivory-2, #faf3e3);
  border-left: 3px solid var(--accent);
  border-radius: 8px;
}
.listing-question-card-q-label {
  color: var(--ink-3, #888);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: 4px;
}
.listing-question-card-q {
  margin: 0;
  font-size: 16px;
  line-height: 1.5;
  color: var(--ink, #1a1a1a);
}
.listing-question-form .form-help {
  display: block;
  margin-top: 4px;
  color: var(--ink-3, #888);
}
.listing-question-public-notice {
  color: var(--ink-3, #888);
  padding: 8px 12px;
  background: var(--surface-2);
  border-radius: 6px;
}

/* Buyer-questions panel on the broker show page. Pending rows get
 * the accent border (action-needed); answered rows are calmer.
 * Mirrors the FAQ drafts panel's visual rhythm so the broker sees
 * both surfaces as part of the same "stuff to deal with" stack. */
.listing-question-drafts {
  margin-top: 16px;
}
.listing-question-drafts-count {
  display: inline-block;
  margin-left: 8px;
  padding: 2px 10px;
  background: var(--accent);
  color: var(--paper);
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  vertical-align: middle;
}
.listing-question-drafts-list {
  list-style: none;
  padding: 0;
  margin: 12px 0 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.listing-question-draft {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px;
  padding: 12px 14px;
  border-radius: 10px;
  background: var(--surface);
  border: 1px solid var(--border);
}
.listing-question-draft--pending {
  border-left: 3px solid var(--accent);
  background: var(--ivory-2, #faf3e3);
}
.listing-question-draft--answered {
  border-left: 3px solid var(--ink-3, #888);
  background: var(--surface-2);
}
.listing-question-draft-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.listing-question-draft-meta {
  color: var(--ink-3, #888);
}
.listing-question-draft-q {
  font-size: 15px;
  line-height: 1.4;
  color: var(--ink, #1a1a1a);
}
.listing-question-draft-a {
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink-2, #555);
  margin-top: 4px;
}
.listing-question-public-flag { color: var(--accent); font-weight: 600; }
.listing-question-private-flag { color: var(--ink-3, #888); }
.listing-question-draft-actions { flex-shrink: 0; }
.listing-question-drafts-answered {
  margin-top: 14px;
}
.listing-question-drafts-answered-toggle {
  cursor: pointer;
  color: var(--ink-3, #888);
  padding: 6px 0;
  user-select: none;
}
.listing-question-drafts-answered[open] .listing-question-drafts-answered-toggle {
  color: var(--ink, #1a1a1a);
}

/* ──────────────────────────────────────────────────────────────────
 * /brokers/edit/integrations — Phase 4 inbound webhook tokens
 * ────────────────────────────────────────────────────────────────── */

.integrations-head { margin: 24px 0 16px; }
.integrations-intro { font-size: 13px; color: var(--ink-2); line-height: 1.6; margin-top: 8px; }
.integrations-back { display: inline-block; margin-top: 12px; font-size: 12px; color: var(--ink-3); text-decoration: none; }
.integrations-back:hover { color: var(--ink); text-decoration: underline; }

.integrations-section {
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--paper);
  padding: 20px 24px;
  margin-top: 20px;
}
.integrations-section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 16px;
}
.integrations-section-title {
  font-family: var(--serif);
  font-size: 20px;
  margin: 0;
  color: var(--ink);
}

/* Mint form */
.integrations-mint-form {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 16px;
  border: 1px dashed var(--line);
  border-radius: 8px;
  background: var(--ivory-2);
  margin-bottom: 16px;
}
.integrations-label {
  font-size: 10px;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.integrations-input, .integrations-select {
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--paper);
  color: var(--ink);
  font-size: var(--fs-input);
  font-family: inherit;
  width: 100%;
  max-width: 480px;
}
.integrations-mint-actions { margin-top: 4px; }

/* Token list */
.integrations-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.integrations-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 16px;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--ivory-2);
}
.integrations-row-main { flex: 1; min-width: 0; }
.integrations-row-label {
  font-family: var(--serif);
  font-size: 16px;
  color: var(--ink);
}
.integrations-row-meta {
  font-size: 11px;
  color: var(--ink-3);
  letter-spacing: 0.04em;
  margin-top: 2px;
}
.integrations-row-url {
  font-size: 12px;
  color: var(--ink-4);
  margin-top: 6px;
  word-break: break-all;
}
.integrations-row-actions form { margin: 0; }

/* Fresh-mint banner */
.integrations-fresh-banner {
  border: 2px solid var(--saffron);
  border-radius: 12px;
  background: color-mix(in oklab, var(--saffron) 10%, var(--paper));
  padding: 18px 20px;
  margin: 16px 0 20px;
}
.integrations-fresh-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 8px;
}
.integrations-fresh-head strong {
  font-family: var(--serif);
  font-size: 17px;
  color: var(--ink);
}
.integrations-fresh-note {
  font-size: 11px;
  color: var(--saffron-deep);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.integrations-fresh-label {
  font-size: 11px;
  color: var(--ink-3);
  letter-spacing: 0.04em;
  margin-bottom: 8px;
}
.integrations-fresh-url-row {
  display: flex;
  gap: 8px;
  margin-top: 8px;
}
.integrations-fresh-url {
  flex: 1;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--paper);
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink);
}
.integrations-fresh-howto {
  margin-top: 12px;
  font-size: 13px;
  color: var(--ink-2);
  line-height: 1.6;
}
.integrations-fresh-howto summary {
  cursor: pointer;
  font-weight: 600;
  color: var(--saffron-deep);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-size: 11px;
}
.integrations-fresh-howto ol { padding-left: 20px; margin: 8px 0 12px; }
.integrations-fresh-howto li { margin: 6px 0; }

/* Payload reference */
.integrations-payload {
  margin: 12px 0;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--ink);
  color: var(--ivory);
  font-family: var(--mono);
  font-size: 12px;
  line-height: 1.5;
  overflow-x: auto;
}
.integrations-payload code {
  background: none;
  color: inherit;
  font-family: inherit;
  white-space: pre;
}

/* Aux link on the broker edit page → Integrations tab. */
.onboarding-aux-link {
  display: inline-block;
  margin: 12px 0 18px;
  padding: 8px 14px;
  border: 1px solid var(--saffron);
  border-radius: 999px;
  background: color-mix(in oklab, var(--saffron) 8%, var(--paper));
  color: var(--saffron-deep);
  font-size: 12px;
  letter-spacing: 0.04em;
  text-decoration: none;
  font-weight: 600;
}
.onboarding-aux-link:hover {
  background: color-mix(in oklab, var(--saffron) 18%, var(--paper));
}

/* ─────────────────────────────────────────────────────────────────
   M1 feature 6 — soft-wall auth modal (auth-wall-modal.blade.php).
   Triggered by the global `auth-wall` Alpine event when a guest
   taps a Like / Save / Follow / RSVP button. Mirrors the
   compose-modal visual language — same border, same radius — so
   guests recognise the same paper-y card pattern after sign-in.
   ───────────────────────────────────────────────────────────── */
.auth-wall-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.42);
  backdrop-filter: blur(4px);
  z-index: 9000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}
.auth-wall-card {
  background: var(--paper);
  border: 1px solid var(--ink-line, rgba(0,0,0,0.12));
  border-radius: 14px;
  box-shadow: 0 24px 64px rgba(0, 0, 0, 0.18);
  max-width: 440px;
  width: 100%;
  padding: 20px 22px 18px;
}
.auth-wall-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 8px;
}
.auth-wall-title {
  font-size: 18px;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0;
}
.auth-wall-close {
  background: none;
  border: 0;
  font-size: 26px;
  line-height: 1;
  color: var(--ink-3);
  cursor: pointer;
  padding: 0 6px;
}
.auth-wall-close:hover { color: var(--ink); }
.auth-wall-copy {
  margin: 6px 0 16px;
  color: var(--ink-2);
  line-height: 1.45;
}
.auth-wall-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  margin-bottom: 14px;
}
.auth-wall-fineprint {
  font-size: 11.5px;
  color: var(--ink-3);
  margin: 0;
}
.auth-wall-fineprint a {
  color: inherit;
  text-decoration: underline;
}

/* M1 feature 5 — inline @handle mention pill. Light affordance only;
   no chip background so the mention reads as flowing text but is
   still clearly clickable. */
.post-mention {
  color: var(--saffron-deep, var(--ink));
  text-decoration: none;
  font-weight: 500;
}
.post-mention:hover { text-decoration: underline; }

/* M1 feature 3 — /settings/notifications matrix. Plain HTML table
   with one row per kind, columns per channel; toggles are the only
   interactive elements. */
.settings-form { display: flex; flex-direction: column; gap: 18px; }
.settings-table-wrap { overflow-x: auto; }
.settings-matrix {
  width: 100%;
  border-collapse: collapse;
  border: 1px solid var(--ink-line, rgba(0,0,0,0.08));
  border-radius: 10px;
  overflow: hidden;
}
.settings-matrix th,
.settings-matrix td {
  padding: 12px 14px;
  border-bottom: 1px solid var(--ink-line, rgba(0,0,0,0.06));
  vertical-align: top;
  text-align: left;
}
.settings-matrix thead th {
  background: var(--ivory-2, var(--paper));
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.settings-matrix-channel { white-space: nowrap; }
.settings-matrix-soon {
  display: inline-block;
  margin-left: 6px;
  font-size: 10px;
  letter-spacing: 0.08em;
  color: var(--ink-4);
}
.settings-matrix-kind { min-width: 220px; }
.settings-matrix-label { display: block; font-weight: 600; }
.settings-matrix-desc { display: block; margin-top: 4px; }
/* ROI Verified perk row — gated notification kinds. */
.settings-matrix-perk {
  display: inline-block;
  margin-left: 8px;
  padding: 1px 7px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: #0a5d3b;
  background: #e7f3ec;
  border: 1px solid #c9e3d3;
  border-radius: 999px;
  vertical-align: middle;
}
.settings-matrix-upsell { display: block; margin-top: 4px; color: var(--ink-4); }
.settings-matrix-upsell a { color: #0a5d3b; font-weight: 600; }
.settings-matrix-row-locked .settings-matrix-label { opacity: 0.85; }
.settings-matrix-row-locked .settings-toggle input:disabled { opacity: 0.4; }
.settings-matrix-cell { width: 96px; text-align: center; }
.settings-toggle { display: inline-flex; cursor: pointer; }
.settings-toggle input { cursor: pointer; }
.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;
}
.settings-form-actions {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}

/* ── Admin notifications console ─────────────────────────────────── */
.ncon-totals { display: flex; gap: 18px; flex-wrap: wrap; }
.ncon-total {
  display: flex; flex-direction: column; align-items: flex-start;
  min-width: 90px; padding: 12px 16px;
  background: var(--paper); border: 1px solid var(--line-2);
  border-radius: 8px;
}
.ncon-total-n { font-size: 22px; font-weight: 700; line-height: 1.1; }
.ncon-total-l { font-size: 12px; color: var(--ink-4); margin-top: 2px; }
.ncon-matrix th, .ncon-matrix td { vertical-align: middle; }
.ncon-kind { min-width: 200px; border-right: 1px solid var(--line-2); }
.ncon-channel { white-space: nowrap; }
.ncon-stats { white-space: nowrap; }
.ncon-n-ok { color: var(--green); font-weight: 600; }
.ncon-n-bad { color: var(--red); font-weight: 600; }
.ncon-n-mute { color: var(--ink-4); }
.ncon-inline-form { display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 0; }
.ncon-row-paused { background: var(--red-soft); }
.ncon-pill {
  display: inline-block; padding: 1px 8px; font-size: 11px; font-weight: 600;
  border-radius: 999px; letter-spacing: 0.03em;
}
.ncon-pill-ok { color: var(--green); background: var(--green-soft); border: 1px solid color-mix(in oklch, var(--green) 30%, transparent); }
.ncon-pill-bad { color: var(--red); background: var(--red-soft); border: 1px solid color-mix(in oklch, var(--red) 30%, transparent); }
.ncon-pill-mute { color: var(--ink-4); background: color-mix(in oklch, var(--ink) 8%, transparent); border: 1px solid var(--line-2); }
.btn-tiny { padding: 3px 10px; font-size: 12px; line-height: 1.3; }

/* Email copy editor (admin notifications console). */
.ncon-tpl { border: 1px solid var(--line-2); border-radius: 8px; margin-bottom: 12px; background: var(--paper); }
.ncon-tpl > summary { padding: 12px 16px; cursor: pointer; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.ncon-tpl > summary::-webkit-details-marker { color: var(--ink-4); }
.ncon-tpl-body { padding: 4px 16px 18px; border-top: 1px solid var(--line-2); }
.ncon-tpl-body code { background: color-mix(in oklch, var(--ink) 8%, transparent); color: var(--ink-2); padding: 1px 5px; border-radius: 4px; font-size: 12px; }
.ncon-tpl-form { display: flex; flex-direction: column; gap: 12px; margin: 12px 0; }
.ncon-tpl-label { display: flex; flex-direction: column; gap: 5px; font-size: 13px; font-weight: 600; color: var(--ink-2); }
.ncon-tpl-input, .ncon-tpl-textarea {
  width: 100%; padding: 9px 11px; font-size: var(--fs-input); font-weight: 400;
  color: var(--ink);
  border: 1px solid var(--line-2); border-radius: 6px; background: var(--paper);
  font-family: inherit; min-height: 40px;
}
.ncon-tpl-textarea { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: var(--fs-input); line-height: 1.55; resize: vertical; }
.ncon-tpl-actions { display: flex; gap: 10px; }
.ncon-tpl-aux { display: flex; gap: 12px; flex-wrap: wrap; padding-top: 10px; border-top: 1px dashed var(--line-2); }

/* ── Notifications console tabs (pure CSS radio-tabs, no JS) ───────────── */
/* Radio inputs live just before the tab bar + panels; the checked one
   drives which panel shows. Radios are visually hidden (off-screen). */
.ncon-tab-radio {
  position: absolute;
  width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}
.ncon-tabs {
  display: flex; gap: 4px; flex-wrap: wrap;
  border-bottom: 1px solid var(--line-2);
  margin: 18px 0 22px;
}
.ncon-tab {
  padding: 9px 16px; cursor: pointer; font-size: 14px; font-weight: 600;
  color: var(--ink-4); border-bottom: 2px solid transparent;
  margin-bottom: -1px; user-select: none; border-radius: 6px 6px 0 0;
  transition: color .12s, border-color .12s, background .12s;
}
.ncon-tab:hover { color: var(--ink-2); background: color-mix(in oklch, var(--ink) 6%, transparent); }
.ncon-panel { display: none; }
/* Each checked radio → highlight its label + reveal its panel. The radios
   precede .ncon-tabs and the panels as siblings (general-sibling combinator). */
#ncon-tab-overview:checked ~ .ncon-tabs label[for="ncon-tab-overview"],
#ncon-tab-rules:checked    ~ .ncon-tabs label[for="ncon-tab-rules"],
#ncon-tab-leads:checked    ~ .ncon-tabs label[for="ncon-tab-leads"],
#ncon-tab-copy:checked     ~ .ncon-tabs label[for="ncon-tab-copy"],
#ncon-tab-scheduling:checked ~ .ncon-tabs label[for="ncon-tab-scheduling"] {
  color: var(--accent, #0a5d3b); border-bottom-color: var(--accent, #0a5d3b);
}
#ncon-tab-overview:checked ~ .ncon-panel[data-tab="overview"],
#ncon-tab-rules:checked    ~ .ncon-panel[data-tab="rules"],
#ncon-tab-leads:checked    ~ .ncon-panel[data-tab="leads"],
#ncon-tab-copy:checked     ~ .ncon-panel[data-tab="copy"],
#ncon-tab-scheduling:checked ~ .ncon-panel[data-tab="scheduling"] {
  display: block;
}
/* Keyboard focus ring on the active label when its radio is focused. */
#ncon-tab-overview:focus-visible ~ .ncon-tabs label[for="ncon-tab-overview"],
#ncon-tab-rules:focus-visible    ~ .ncon-tabs label[for="ncon-tab-rules"],
#ncon-tab-leads:focus-visible    ~ .ncon-tabs label[for="ncon-tab-leads"],
#ncon-tab-copy:focus-visible     ~ .ncon-tabs label[for="ncon-tab-copy"],
#ncon-tab-scheduling:focus-visible ~ .ncon-tabs label[for="ncon-tab-scheduling"] {
  outline: 2px solid var(--accent, #0a5d3b); outline-offset: 2px;
}
/* "Coming soon" tab — muted, with a small badge. */
.ncon-tab-soon { color: var(--ink-4); opacity: 0.8; }
.ncon-tab-badge {
  display: inline-block; margin-left: 5px; padding: 0 6px;
  font-size: 10px; font-weight: 600; letter-spacing: 0.04em;
  color: var(--ink-4); background: color-mix(in oklch, var(--ink) 8%, transparent);
  border-radius: 999px; vertical-align: middle;
}
/* Roadmap stub cards (Scheduling placeholder). */
.ncon-soon-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 12px;
}
.ncon-soon-card {
  display: flex; flex-direction: column; gap: 5px;
  padding: 14px 16px; border: 1px dashed var(--line-2); border-radius: 8px;
  background: color-mix(in oklch, var(--ink) 3%, transparent);
}

/* ─────────────────────────────────────────────────────────────────
   M2 feature 4 — public post detail card (/p/{id}/{slug}).
   Single-column reading shell; share + react actions at the bottom.
   ───────────────────────────────────────────────────────────── */
.public-post-card {
  border: 1px solid var(--ink-line, rgba(0,0,0,0.10));
  border-radius: 12px;
  background: var(--paper);
  padding: 22px 24px;
  margin-top: 14px;
}
.public-post-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
  /* No-crop reflex D7 — long broker names get a wrap row instead of
     pushing the time stamp off-screen. */
  flex-wrap: wrap;
  row-gap: 6px;
}
.public-post-author {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: inherit;
  text-decoration: none;
}
.public-post-author:hover strong { text-decoration: underline; }
.public-post-time { color: var(--ink-3); font-size: 12px; }
.public-post-photo {
  display: block;
  width: 100%;
  max-height: 520px;
  /* D9 — aspect-ratio + width/height attrs in markup eliminate CLS
     during photo load. 16/9 is the canonical share-preview ratio;
     even off-ratio sources still get a stable layout box because
     object-fit:cover absorbs the difference. */
  aspect-ratio: 16 / 9;
  height: auto;
  object-fit: cover;
  object-position: 50% 30%;
  border-radius: 10px;
  margin: 14px 0 6px;
}
.public-post-meta {
  display: flex;
  /* No-crop reflex D7 — meta line is the natural wrap candidate. */
  flex-wrap: wrap;
  row-gap: 6px;
  gap: 10px;
  color: var(--ink-3);
  font-size: 12px;
  margin: 10px 0 16px;
}
.public-post-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

/* ─────────────────────────────────────────────────────────────────
   M2 feature 2 — reaction picker on the like-button widget.
   Default state: single chip showing the user's reaction (or ♡).
   Click → expands a row of 4 reaction chips; tapping one submits.
   ───────────────────────────────────────────────────────────── */
.post-card-react {
  position: relative;
  display: inline-block;
}
.post-react-primary {
  font-variant-emoji: emoji;
}
.post-react-picker {
  position: absolute;
  bottom: calc(100% + 6px);
  left: 0;
  display: flex;
  gap: 4px;
  padding: 6px 8px;
  border: 1px solid var(--ink-line, rgba(0,0,0,0.10));
  border-radius: 999px;
  background: var(--paper);
  box-shadow: 0 6px 18px rgba(0,0,0,0.10);
  z-index: 30;
  white-space: nowrap;
}
.post-react-picker-form { margin: 0; }
.post-react-chip {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 0;
  background: transparent;
  font-size: 18px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.08s ease, background 0.12s ease;
}
.post-react-chip:hover { transform: scale(1.18); background: color-mix(in oklab, var(--ink) 4%, var(--paper)); }
.post-react-chip.is-active {
  background: color-mix(in oklab, var(--saffron, #f59e0b) 12%, var(--paper));
}

/* ─────────────────────────────────────────────────────────────────
   M2 feature 3 — nested comments (one level deep) on /posts/{id}.
   Reply form switches into "reply mode" via Alpine; the indented
   replies hang under their parent comment.
   ───────────────────────────────────────────────────────────── */
.post-comment-actions {
  margin-top: 4px;
}
.btn-link {
  background: none;
  border: 0;
  color: var(--ink-3);
  padding: 0;
  cursor: pointer;
  font-size: 12px;
  text-decoration: underline;
}
.btn-link:hover { color: var(--ink); }
.post-comment-replies {
  margin: 8px 0 0 22px;
  padding-left: 12px;
  border-left: 2px solid var(--ink-line, rgba(0,0,0,0.08));
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.post-comment.is-reply {
  padding-top: 6px;
}
.post-comment-reply-banner {
  background: color-mix(in oklab, var(--saffron, #f59e0b) 8%, var(--paper));
  border-radius: 6px;
  padding: 6px 10px;
  margin-bottom: 6px;
  font-size: 12px;
  color: var(--ink-2);
  display: flex;
  align-items: center;
  gap: 10px;
}

/* M2 feature 5 — "edited" badge on the post card header. */
.post-card-edited {
  color: var(--ink-3);
  font-size: 11px;
  margin-left: 4px;
}
.page-flash-error {
  background: color-mix(in oklab, #c0392b 12%, var(--paper));
  border: 1px solid color-mix(in oklab, #c0392b 30%, var(--paper));
  color: #7a2018;
}

/* ─────────────────────────────────────────────────────────────────
   M2 feature 6 — "Recent posts" rail on /in/{state}/{city}/{loc}.
   ───────────────────────────────────────────────────────────── */
.pll-recent-posts { margin-top: 32px; }
.pll-recent-posts-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 12px;
  margin-top: 12px;
}
.pll-recent-post {
  display: block;
  padding: 14px 16px;
  border: 1px solid var(--ink-line, rgba(0,0,0,0.10));
  border-radius: 10px;
  background: var(--paper);
  color: inherit;
  text-decoration: none;
  transition: border-color 0.12s ease, transform 0.12s ease;
}
.pll-recent-post:hover {
  border-color: var(--saffron, #f59e0b);
  transform: translateY(-1px);
}
.pll-recent-post-author {
  font-size: 11px;
  color: var(--ink-3);
  margin-bottom: 6px;
}
.pll-recent-post-body {
  margin: 0 0 8px;
  font-size: 14px;
  line-height: 1.45;
  color: var(--ink-2);
}
.pll-recent-post-meta {
  font-size: 11px;
  color: var(--ink-3);
}

/* ─────────────────────────────────────────────────────────────────
   Phase 3.3 — broker profile engagement (verified-only).
   Two surfaces: a one-line strip under the stats row, and a right-
   rail "Trending this week" section listing the broker's top items
   by engagement total.
   ───────────────────────────────────────────────────────────── */
.broker-engagement-strip {
  margin: 4px 0 14px;
  padding: 8px 14px;
  background: linear-gradient(90deg, rgba(200, 84, 31, 0.10) 0%, rgba(200, 84, 31, 0.02) 100%);
  border: 1px solid rgba(200, 84, 31, 0.18);
  border-radius: 999px;
  font-size: 12px;
  color: var(--saffron-deep, #b04a1a);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  letter-spacing: 0.01em;
}
.broker-engagement-flame {
  display: inline-block;
  filter: saturate(1.2);
}
.broker-trending-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.broker-trending-item {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 8px 10px;
  text-decoration: none;
  color: inherit;
  background: var(--paper);
  border: 1px solid var(--ink-line, rgba(0,0,0,0.06));
  border-radius: 8px;
  transition: border-color 0.12s ease, transform 0.12s ease;
}
.broker-trending-item:hover {
  border-color: var(--saffron, #c8541f);
  transform: translateY(-1px);
}
.broker-trending-kind {
  font-size: 10px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.broker-trending-title {
  font-size: 13px;
  line-height: 1.35;
  color: var(--ink-2);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.broker-trending-total {
  font-size: 11px;
  color: var(--saffron-deep, #b04a1a);
}

/* ─────────────────────────────────────────────────────────────────
   Phase 3.2 — social-proof engagement badges on public PDPs + posts.
   Renders only when an item has ≥3 events in the window (component
   bails sub-threshold so CSS is dead code below that line). The
   buyer-funnel triad (view / save / enquiry) gets a saffron tint;
   social signals (like / comment / share) stay muted ink.
   ───────────────────────────────────────────────────────────── */
.engagement-badges {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 10px;
  margin: 10px 0;
  font-size: 12px;
  color: var(--ink-2);
}
.engagement-badges--compact {
  margin: 8px 0;
  font-size: 11px;
  gap: 4px 8px;
}
.engagement-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--ivory-2, #faf6ef);
  border: 1px solid var(--ink-line, rgba(0,0,0,0.08));
  font-weight: 500;
  letter-spacing: 0.01em;
}
.engagement-badge--view,
.engagement-badge--save,
.engagement-badge--enquiry {
  background: rgba(200, 84, 31, 0.08);
  border-color: rgba(200, 84, 31, 0.18);
  color: var(--saffron-deep, #b04a1a);
}
.engagement-badge--like,
.engagement-badge--comment,
.engagement-badge--share_click {
  color: var(--ink-2);
}
.engagement-badges-window {
  color: var(--ink-3);
  font-size: 11px;
}

/* ─────────────────────────────────────────────────────────────────
   Phase 3.1 — "Trending in {locality}" widget on public locality
   pages. Reads trending_cache (15-min refresh) filtered by locality.
   Sits above "Top contributors" so crawlers + first-paint visitors
   see fresh engagement-ranked content.
   ───────────────────────────────────────────────────────────── */
.pll-trending {
  margin-top: 32px;
  padding: 18px 20px;
  border: 1px solid var(--ink-line, rgba(0,0,0,0.10));
  border-radius: 12px;
  background: linear-gradient(180deg, rgba(200, 84, 31, 0.04) 0%, var(--paper) 100%);
}
.pll-trending .pll-section-title {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.pll-trending-flame {
  font-size: 1.1em;
  filter: saturate(1.2);
}
.pll-trending-grid {
  list-style: none;
  margin: 14px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.pll-trending-card {
  background: var(--paper);
  border: 1px solid var(--ink-line, rgba(0,0,0,0.08));
  border-radius: 10px;
  transition: border-color 0.12s ease, transform 0.12s ease;
}
.pll-trending-card:hover {
  border-color: var(--saffron, #c8541f);
  transform: translateY(-1px);
}
.pll-trending-link {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  padding: 12px 14px;
  text-decoration: none;
  color: inherit;
}
.pll-trending-rank {
  flex: 0 0 28px;
  font-size: 22px;
  font-weight: 800;
  line-height: 1;
  color: var(--saffron, #c8541f);
  letter-spacing: -0.02em;
}
.pll-trending-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.pll-trending-kind {
  font-size: 10px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.pll-trending-title {
  font-size: 14px;
  line-height: 1.4;
  color: var(--ink-2);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.pll-trending-when {
  color: var(--ink-3);
  font-size: 12px;
}
.pll-trending-reason {
  margin-top: 2px;
  font-size: 11px;
  color: var(--saffron-deep, #b04a1a);
}
@media (min-width: 720px) {
  .pll-trending-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
  }
  .pll-trending-grid > .pll-trending-card:first-child {
    grid-column: 1 / -1;
  }
}

/* M2 feature 1a — autosave status pill in the composer. */
.compose-draft-status {
  font-size: 11px;
  color: var(--ink-3);
  margin: 4px 24px 0;
  padding: 4px 10px;
  display: inline-block;
  border-radius: 999px;
  background: color-mix(in oklab, var(--ink) 4%, var(--paper));
}

/* ─────────────────────────────────────────────────────────────────
   M2 feature 1b/1c — write-time embed snapshot card.
   Same shape for listing + link embeds; the discriminator is the
   eyebrow text.
   ───────────────────────────────────────────────────────────── */
.post-embed {
  display: flex;
  align-items: stretch;
  gap: 14px;
  margin: 12px 0;
  padding: 12px;
  border: 1px solid var(--ink-line, rgba(0,0,0,0.10));
  border-radius: 10px;
  background: color-mix(in oklab, var(--ink) 2%, var(--paper));
  color: inherit;
  text-decoration: none;
  transition: border-color 0.12s ease;
}
.post-embed:hover { border-color: var(--saffron, #f59e0b); }
.post-embed-photo {
  width: 96px;
  height: 96px;
  border-radius: 8px;
  object-fit: cover;
  flex-shrink: 0;
}
.post-embed-body {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.post-embed-eyebrow {
  font-size: 11px;
  color: var(--ink-3);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
/* Dark-mode pinning for slabs that should never re-theme.
   Four homepage sections render a fixed palette regardless of the
   page's light/dark setting:
     • .ph-persist        — dark charcoal slab with cream text
     • .ph-why--dark      — dark charcoal slab with cream text
     • .ph-final-cta      — cream/ivory slab with ink text
     • .ph-problem        — ivory comparison slab with ink text
                             ("WHY ROI EXISTS" phone-journey contrast)
   In dark mode, the theme-aware tokens (--cream, --charcoal, --ink,
   --ivory, --paper) flip globally and these slabs lose contrast
   (e.g. cream text on cream-that-is-now-dark, dark text on dark-
   that-is-still-cream). Re-pin the palette locally to the light-
   mode values so the slabs read correctly regardless of which
   theme the rest of the page is in.

   Covers both explicit [data-theme="dark"] and the
   prefers-color-scheme fallback for users on system-default. */
[data-theme="dark"] .ph-persist,
[data-theme="dark"] .ph-why--dark,
[data-theme="dark"] .ph-final-cta,
[data-theme="dark"] .ph-problem {
  --ivory:      oklch(0.985 0.008 85);
  --ivory-2:    oklch(0.965 0.012 85);
  --paper:      oklch(0.995 0.004 85);
  --paper-2:    oklch(0.975 0.010 85);
  --ink:        oklch(0.22 0.015 60);
  --ink-2:      oklch(0.35 0.015 60);
  --ink-3:      oklch(0.50 0.015 60);
  --ink-4:      oklch(0.62 0.015 60);
  --cream:      oklch(0.97 0.022 80);
  --charcoal:   oklch(0.22 0.012 60);
  --charcoal-2: oklch(0.28 0.012 60);
  --line:       oklch(0.92 0.010 85);
}
@media (prefers-color-scheme: dark) {
  html:not([data-theme="light"]):not([data-theme="dark"]) .ph-persist,
  html:not([data-theme="light"]):not([data-theme="dark"]) .ph-why--dark,
  html:not([data-theme="light"]):not([data-theme="dark"]) .ph-final-cta,
  html:not([data-theme="light"]):not([data-theme="dark"]) .ph-problem {
    --ivory:      oklch(0.985 0.008 85);
    --ivory-2:    oklch(0.965 0.012 85);
    --paper:      oklch(0.995 0.004 85);
    --paper-2:    oklch(0.975 0.010 85);
    --ink:        oklch(0.22 0.015 60);
    --ink-2:      oklch(0.35 0.015 60);
    --ink-3:      oklch(0.50 0.015 60);
    --ink-4:      oklch(0.62 0.015 60);
    --cream:      oklch(0.97 0.022 80);
    --charcoal:   oklch(0.22 0.012 60);
    --charcoal-2: oklch(0.28 0.012 60);
    --line:       oklch(0.92 0.010 85);
  }
}

.post-embed-title {
  font-weight: 600;
  font-size: 15px;
  line-height: 1.3;
  color: var(--ink);
}
.post-embed-price {
  font-size: 13px;
  color: var(--ink-2);
  margin-top: 4px;
}
.post-embed-desc {
  font-size: 12px;
  color: var(--ink-2);
  margin-top: 2px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Video embed — 16:9 click-to-play surface. The poster button shows
   the YouTube thumbnail with a centered play glyph; clicking swaps in
   the iframe via Alpine. We don't fetch youtube.com on every feed
   render, just on the click that signals real intent. */
.post-embed-video {
  position: relative;
  aspect-ratio: 16 / 9;
  width: 100%;
  border-radius: 8px;
  overflow: hidden;
  background: #000;
  display: block;
  padding: 0;
}
.post-embed-video:hover { border-color: transparent; }
.post-embed-video-poster {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.post-embed-video-thumb {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.post-embed-video-play {
  position: relative;
  z-index: 1;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.7);
  color: #fff;
  font-size: 22px;
  line-height: 56px;
  text-align: center;
  padding-left: 4px; /* visual centering for the ▶ glyph */
  transition: background 120ms ease, transform 120ms ease;
}
.post-embed-video-poster:hover .post-embed-video-play {
  background: var(--saffron, #c8541f);
  transform: scale(1.05);
}
.post-embed-video-iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* ── Admin → Queues (operational observability) ────────────────────
   Surfaces match-compute job health. The red banner fires when a
   match_compute_jobs row has been queued/computing for > 5 minutes
   (the "stuck worker" signal). */
.queue-banner {
  padding: 12px 16px;
  border-radius: 6px;
  margin: 12px 0 20px;
  font-family: var(--mono);
  font-size: 13px;
  line-height: 1.5;
}
.queue-banner--red {
  background: oklch(0.96 0.04 25);
  border: 1px solid oklch(0.75 0.10 25);
  color: oklch(0.35 0.15 25);
}
.queue-banner--amber {
  background: oklch(0.96 0.04 60);
  border: 1px solid oklch(0.75 0.10 60);
  color: oklch(0.35 0.15 60);
}

.queue-async-strip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  background: var(--ivory-2);
  border-radius: 4px;
  margin: 8px 0 20px;
  font-size: 12px;
}
.queue-async-strip code {
  background: transparent;
  padding: 0;
}

.queue-exception-preview {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 480px;
  display: inline-block;
  vertical-align: middle;
}

/* ── Queue health rows (per-queue severity + descriptors) ───── */
.queue-rows-table td { vertical-align: top; }
.queue-row-status { white-space: nowrap; }
.queue-row-status .small { color: var(--ink-3); }
.queue-row--red .queue-row-status .small { color: oklch(0.45 0.18 25); }
.queue-row--amber .queue-row-status .small { color: oklch(0.50 0.15 60); }
.queue-row--green .queue-row-status .small { color: oklch(0.45 0.12 140); }

.queue-status-dot--unknown {
  background: var(--ink-4);
}

.queue-row-desc { max-width: 540px; line-height: 1.4; }
.queue-row-jobs { margin-top: 6px; }
.queue-row-jobs summary {
  cursor: pointer;
  color: var(--ink-3);
  user-select: none;
}
.queue-row-jobs summary:hover { color: var(--saffron-deep); }
.queue-row-jobs-list {
  margin: 6px 0 0 16px;
  padding: 0;
  list-style: disc;
  color: var(--ink-3);
}
.queue-row-jobs-list li { margin: 2px 0; }
.queue-row-reason {
  margin: 6px 0 0;
  padding: 6px 10px;
  background: var(--ivory-2);
  border-radius: 3px;
  color: var(--ink-2);
}
.queue-row--red .queue-row-reason {
  background: oklch(0.96 0.04 25);
  color: oklch(0.35 0.15 25);
}
.queue-row--amber .queue-row-reason {
  background: oklch(0.96 0.04 60);
  color: oklch(0.35 0.15 60);
}

/* --- Phase 1: Smart For You attribution line --------------------- */
.feed-attribution {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  margin-top: 6px;
  margin-bottom: 2px;
  padding: 0;
  background: none;
  border: none;
  cursor: pointer;
  font-size: 11px;
  color: var(--ink-3);
  font-style: italic;
  font-family: inherit;
}
.feed-attribution:hover {
  color: var(--ink-2);
  text-decoration: underline;
}
.feed-attribution::before {
  content: "ⓘ";
  font-style: normal;
  margin-right: 2px;
  opacity: 0.7;
}

/* Pulse animation fired on the left-rail pill that matches the
   attribution the user clicked. Saffron-tinted to align with the
   existing accent system. Auto-removed after the keyframe completes. */
.pill-highlight {
  animation: pill-pulse 1.8s ease-out;
}
@keyframes pill-pulse {
  0%   { box-shadow: 0 0 0 0 var(--saffron, #c8541f); }
  50%  { box-shadow: 0 0 0 8px rgba(200, 84, 31, 0.18); }
  100% { box-shadow: 0 0 0 0 transparent; }
}

/* --- Phase 1.5: Left-rail filter toggles ------------------------- */
.feed-rail-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 12px 0;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--line);
}
.feed-rail-filter {
  /* Visible chip stays at ~26px tall to keep rail density;
     ::before extends hit area to 48x48 (rubric D3).
     position: relative anchors the ::before. */
  position: relative;
  display: inline-block;
  padding: 4px 10px;
  font-size: 11px;
  font-family: inherit;
  color: var(--ink-2);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 999px;
  text-decoration: none;
  cursor: pointer;
}
.feed-rail-filter::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  min-width: var(--tap);
  min-height: var(--tap);
}
.feed-rail-filter:hover {
  background: var(--ivory-2);
  border-color: var(--ink-3);
}
.feed-rail-filter--active {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}
.feed-rail-filter--active:hover {
  background: var(--ink);
  color: var(--paper);
}

/* --- Phase 2: Trending tab + widget + hero ----------------------- */

/* Per-card eyebrow that surfaces "63 saves in 2 days" reasoning on
   the Trending tab. Saffron-tinted so it's visually distinct from
   the italic "Because you follow X" attribution on For You. */
.feed-trending-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin: 0 0 6px;
  padding: 3px 9px;
  font-size: 11px;
  background: rgba(200, 84, 31, 0.10);
  color: var(--saffron, #c8541f);
  border-radius: 999px;
  letter-spacing: 0.02em;
  width: fit-content;
}

/* Trending tab header — state label + "Updated N min ago". */
.feed-trending-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin: 16px 0 12px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--line);
  /* No-crop reflex D7 — wraps on narrow viewports instead of forcing
     a horizontal scroll the page-level overflow:clip would swallow. */
  flex-wrap: wrap;
  row-gap: 6px;
}
.feed-trending-label {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
  color: var(--ink);
}
.feed-trending-updated {
  font-size: 11px;
  color: var(--ink-3);
}

/* Cold-start hero — shown only in sparse state with <5 items.
   Three discovery rails in a responsive grid. */
.trending-hero {
  margin: 8px 0 20px;
  padding: 16px;
  background: var(--ivory-2, #faf6ef);
  border: 1px solid var(--line);
  border-radius: 8px;
}
.trending-hero-head {
  margin-bottom: 14px;
}
.trending-hero-title {
  margin: 0 0 4px;
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
}
.trending-hero-sub {
  margin: 0;
  font-size: 12px;
  color: var(--ink-3);
}
.trending-hero-grid {
  display: grid;
  /* minmax(0, 1fr) lets the columns shrink below their intrinsic content
     width — otherwise an unbreakable locality name like "Migsun Lucknow
     Central, Sector-A, Pocket-1, Sushant Golf City, Lucknow, Up" combined
     with white-space:nowrap on the title expands the column, overflowing
     the .feed-stream-col into the sticky right rail's space. */
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}
@media (max-width: 720px) {
  .trending-hero-grid {
    grid-template-columns: 1fr;
  }
}
.trending-hero-card {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  /* Belt + braces with grid minmax(0,1fr) above: ensures the flex-column
     card can shrink below its content min size when its single-line
     children carry overflow:hidden ellipsis. */
  min-width: 0;
}
.trending-hero-card-title {
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--ink-3);
  text-transform: uppercase;
}
.trending-hero-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.trending-hero-link {
  display: flex;
  align-items: center;
  gap: 8px;
  text-decoration: none;
  color: var(--ink);
  padding: 2px 0;
}
.trending-hero-link:hover {
  color: var(--saffron, #c8541f);
}
.trending-hero-avatar {
  width: 26px;
  height: 26px;
  flex: 0 0 26px;
  border-radius: 50%;
  background: var(--ivory-2);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  color: var(--ink-2);
}
.trending-hero-link-body {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}
.trending-hero-link-title {
  font-size: 13px;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.trending-hero-link-meta {
  font-size: 10px;
  color: var(--ink-3);
}
.trending-hero-more {
  margin-top: 2px;
  font-size: 11px;
  color: var(--saffron, #c8541f);
  text-decoration: none;
}
.trending-hero-more:hover {
  text-decoration: underline;
}

/* Right-rail trending widget — top 3 ranked items, numbered. */
.trending-widget .feed-rail-section-head {
  margin-bottom: 8px;
}
.trending-widget-more {
  font-size: 11px;
  color: var(--saffron, #c8541f);
  text-decoration: none;
}
.trending-widget-more:hover {
  text-decoration: underline;
}
.trending-widget-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
  counter-reset: trending-rank;
}
.trending-widget-link {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  text-decoration: none;
  color: var(--ink);
}
.trending-widget-link:hover .trending-widget-title {
  color: var(--saffron, #c8541f);
}
.trending-widget-rank {
  flex: 0 0 22px;
  font-size: 14px;
  font-weight: 700;
  color: var(--saffron, #c8541f);
  line-height: 1.2;
}
.trending-widget-body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.trending-widget-title {
  font-size: 12px;
  line-height: 1.35;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.trending-widget-reason {
  font-size: 10px;
  color: var(--ink-3);
}
/* ROI Muhurat — daily horoscope banner.
 * Editorial parchment palette to differentiate from operational KPIs.
 * Muted apothecary green for "Good", faded brick red for "Avoid" —
 * almanac aesthetic that doesn't compete with the rest of the dash.
 */
.muhurat-banner {
    background: #FBF7F0;
    border: 1px solid rgba(200, 84, 31, 0.12);
    border-radius: 4px;
    padding: 18px 24px;
    margin-bottom: 24px;
    font-family: Georgia, 'Times New Roman', serif;
    color: #2A2419;
    display: grid;
    gap: 12px;
}

.muhurat-banner__masthead {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    border-bottom: 1px solid rgba(42, 36, 25, 0.08);
    padding-bottom: 10px;
}

.muhurat-banner__eyebrow {
    font-family: 'IBM Plex Mono', ui-monospace, monospace;
    font-size: 10px;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: #C8541F;
}

.muhurat-banner__date {
    font-family: 'IBM Plex Mono', ui-monospace, monospace;
    font-size: 11px;
    color: #6B5F4A;
    margin-left: 12px;
}

.muhurat-banner__sign {
    display: flex;
    align-items: center;
    gap: 8px;
}

.muhurat-banner__glyph {
    font-size: 22px;
    color: #C8541F;
}

.muhurat-banner__sign-name {
    font-family: 'IBM Plex Mono', ui-monospace, monospace;
    font-size: 11px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
}

.muhurat-banner__lines {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 24px;
}

.muhurat-line {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 10px;
    align-items: start;
}

.muhurat-line__tag {
    font-family: 'IBM Plex Mono', ui-monospace, monospace;
    font-size: 10px;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    padding: 5px 9px;
    border-radius: 2px;
    line-height: 1.2;
    white-space: nowrap;
    font-weight: 600;
}

.muhurat-line--good .muhurat-line__tag {
    background: rgba(60, 110, 78, 0.12);
    color: #2F6B47;
    border: 1px solid rgba(60, 110, 78, 0.25);
}

.muhurat-line--good .muhurat-line__text {
    color: #2A2419;
}

.muhurat-line--avoid .muhurat-line__tag {
    background: rgba(168, 60, 50, 0.10);
    color: #A83C32;
    border: 1px solid rgba(168, 60, 50, 0.25);
}

.muhurat-line--avoid .muhurat-line__text {
    color: #2A2419;
}

.muhurat-line__text {
    font-size: 14.5px;
    line-height: 1.5;
    margin: 0;
}

.muhurat-banner__reasoning {
    display: flex;
    align-items: center;
    gap: 8px;
    padding-top: 10px;
    border-top: 1px dashed rgba(42, 36, 25, 0.12);
}

.muhurat-banner__reasoning-glyph {
    color: #C8541F;
    font-size: 11px;
}

.muhurat-banner__reasoning-text {
    font-family: 'IBM Plex Mono', ui-monospace, monospace;
    font-size: 10.5px;
    letter-spacing: 0.06em;
    color: #6B5F4A;
}

@media (max-width: 640px) {
    .muhurat-banner__lines {
        grid-template-columns: 1fr;
        gap: 14px;
    }
    .muhurat-banner__masthead {
        flex-direction: column;
        align-items: flex-start;
        gap: 6px;
    }
}

/* --- 2026-05-20: Wordmark in left rail + inline composer card ----
   Middle-column header (eyebrow + h1 + sub) is gone; the wordmark
   now lives at the top of the left rail so the feed itself gets
   more vertical room. Composer rail is now a card with a type-
   picker row inline. */

.feed-rail-wordmark {
  display: block;
  margin: 0 0 14px;
  padding: 0 0 14px;
  font-family: var(--mono);
  font-size: 18px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--saffron-deep, #b04a1a);
  text-decoration: none;
  border-bottom: 1px solid var(--line);
}
.feed-rail-wordmark:hover {
  color: var(--saffron, #c8541f);
}

/* Composer card — replaces the old single-button .feed-composer-rail.
   Top row: "share something" placeholder text on the left, Post button
   on the right. Bottom row: 5 type pills. Both placeholder and button
   navigate to /compose?type=<picked> so any click in the card lands on
   the right composer with the right type pre-selected. */
.feed-composer-card {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 14px 16px;
  margin: 0 0 16px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
/* Mobile entries flow through the bottom-nav center "+" FAB (the
   .mobile-bottom-nav fab routes to compose.show with the same type
   pre-select the card chips would). Hiding the inline card on
   `<=800px` retires the duplicate CTA — see Phase A of
   memory/brief_phase5_feed.md. Desktop unchanged. */
@media (max-width: 800px) {
  .feed-composer-card { display: none; }
}

/* ── Phase 5 #4 — RealtyX preferences strip + sheet ──────────────────
   Strip is a sleek "hanging" button at the top of the feed on mobile
   that opens a sheet wrapping the existing _left-rail include via
   display: contents. Single source of truth — the rail's 6 sections
   (Cities, Localities, Categories, Price Band, Tags, Builders)
   render in-place on desktop AND inside the sheet on mobile from the
   same Blade include. See memory/brief_phase5_feed.md.

   Locked sleek floor (do not bloat heavier):
     radius 12px · margin 10px · shadow alpha 0.10 · padding 8/14 ·
     hairline border. */

/* ── Strip — envelope-flap below the rishta ticker ─────────────────
   User direction 2026-06-05: place strip BELOW the ticker (not
   inside navbar) AND give it bottom-rounded "envelope close strip"
   corners. The strip is pushed into @stack('post-ticker-chrome')
   in layouts/app.blade.php, so its DOM position is right after the
   ticker. It still needs its OWN sticky/background/blur math now
   (no parent chrome to inherit) — but the colour-mismatch from
   the prior attempts is solved by adopting the navbar's exact
   colour-mix + backdrop-filter recipe so the strip reads as the
   chrome's natural continuation when sticky kicks in.

   When the page loads at scroll-top:
     live-bar → navbar → ticker → strip (envelope flap) → main
   When the user scrolls:
     live-bar scrolls away · navbar sticks at top:0 · ticker
     scrolls away · strip sticks at top:64px (below navbar) and
     stays through the feed scroll.

   Bottom-only border-radius + subtle side margin gives the
   "envelope close strip" visual the user described. */
.realtyx-prefs-strip {
  /* Hidden by default — the strip is a mobile-only surface. On
     desktop the left rail handles preferences inline; rendering
     the strip there would duplicate the controls. When the strip
     lived inside .navbar (commit eaf3ef8) it inherited the
     navbar's mobile collapse for free; moving it out to
     @stack('post-ticker-chrome') (commit d5a9a7b) lost that
     inheritance, so the explicit hide rule is the gate now. */
  display: none;
  position: sticky;
  top: var(--navbar-h, 64px);
  z-index: 19;
  margin: 0 6px;
  background: color-mix(in oklab, var(--ivory) 88%, transparent);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border: 0;
  border-radius: 0 0 14px 14px;
  box-shadow: 0 4px 12px -8px rgba(20, 18, 16, 0.12);
}
[data-theme="dark"] .realtyx-prefs-strip {
  /* Match the .navbar dark override at app.css L4847-4849 — same
     opacity drop so the strip and navbar read as one chrome
     treatment when sticky. */
  background: color-mix(in oklab, var(--ivory) 70%, transparent);
}

@media (max-width: 800px) {
  /* Same 800 px breakpoint the navbar pill rail uses for its
     mobile collapse (see [[navbar-mobile-breakpoint-800]]) so the
     strip appears at exactly the viewport where the rail's
     desktop chrome is no longer visible. */
  .realtyx-prefs-strip { display: block; }
}
.realtyx-prefs-strip-btn {
  width: 100%;
  min-height: 30px;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 16px;
  background: transparent;
  border: 0;
  font: 500 14px/1.2 var(--sans);
  color: var(--ink);
  cursor: pointer;
  text-align: left;
}
.realtyx-prefs-strip-btn-name { font-weight: 600; }
.realtyx-prefs-strip-btn-sep  { color: var(--ink-3); }
.realtyx-prefs-strip-btn-city {
  font-weight: 600;
  color: var(--saffron-deep, #b04a1a);
}
.realtyx-prefs-strip-btn-cog {
  margin-left: auto;
  font-size: 16px;
  color: var(--ink-3);
}

/* ── Rail-wrap → desktop = display:contents passes through the rail
   to the feed-shell grid. Mobile = wrap becomes a bottom-sheet
   overlay when prefsOpen is true. */
.realtyx-prefs-rail-wrap { display: contents; }
.realtyx-prefs-rail-backdrop { display: none; }
.realtyx-prefs-rail-head { display: none; }
.realtyx-prefs-rail-panel { display: contents; }
.realtyx-prefs-rail-body { display: contents; }

@media (max-width: 800px) {
  /* Wrap hidden by default on mobile; opens when prefsOpen is true.
     Both display: none / display: block at the wrap level cleanly
     mounts/unmounts the panel without DOM duplication. */
  .realtyx-prefs-rail-wrap { display: none; }
  .realtyx-prefs-rail-wrap--open { display: block; }

  .realtyx-prefs-rail-backdrop {
    display: block;
    position: fixed; inset: 0;
    background: rgba(20, 18, 16, 0.45);
    z-index: 80;
    touch-action: none;
  }
  .realtyx-prefs-rail-panel {
    display: flex;
    flex-direction: column;
    position: fixed;
    left: 0; right: 0; bottom: 0;
    max-height: 80dvh;
    background: var(--paper);
    border-radius: 16px 16px 0 0;
    box-shadow: 0 -8px 40px -8px rgba(20, 18, 16, 0.3);
    z-index: 81;
    animation: realtyx-prefs-rail-in 0.2s cubic-bezier(0.2, 0.8, 0.4, 1);
  }
  .realtyx-prefs-rail-head {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 8px 16px 12px;
    border-bottom: 1px solid var(--line);
  }
  .realtyx-prefs-rail-handle {
    display: block;
    width: 36px; height: 4px;
    margin: 0 auto;
    background: var(--line-2, #d8d2c2);
    border: 0; border-radius: 999px;
    padding: 0;
    cursor: pointer;
    /* Expand hit-area via a transparent ::before so the visible
       handle stays compact but the tap target meets rubric D3. */
    position: relative;
  }
  .realtyx-prefs-rail-handle::before {
    content: '';
    position: absolute;
    top: 50%; left: 50%;
    transform: translate(-50%, -50%);
    min-width: 48px; min-height: 32px;
  }
  .realtyx-prefs-rail-head-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
  }
  .realtyx-prefs-rail-title {
    font: 600 15px/1 var(--sans);
    color: var(--ink);
  }
  .realtyx-prefs-rail-autosave {
    font: 500 11px/1.3 var(--sans);
    color: var(--ink-3);
  }
  .realtyx-prefs-rail-body {
    display: block;
    flex: 1 1 auto;
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    padding: 12px 16px calc(16px + var(--inset-bottom));
  }
  /* Re-skin the legacy .feed-rail inside the sheet body — kill its
     own sticky / max-height / padding-right so it lays out as a
     flat stack of sections. The .app-rail primitive sticky rules
     don't fire here because the body element isn't a container-
     queried shell. */
  .realtyx-prefs-rail-body .feed-rail,
  .realtyx-prefs-rail-body .app-rail {
    position: static;
    max-height: none;
    overflow: visible;
    padding-right: 0;
    margin: 0;
    gap: 16px;
  }
  /* The rail's wordmark + broker identity card sit above the
     sections in markup. Inside the sheet both are redundant: the
     sheet head says "Your feed preferences" and the strip already
     carries the broker name. Hide them so the sheet body opens
     straight onto the 6 preference sections. */
  .realtyx-prefs-rail-body .feed-rail-wordmark,
  .realtyx-prefs-rail-body .feed-identity-card { display: none; }
}

@keyframes realtyx-prefs-rail-in {
  from { transform: translateY(20px); opacity: 0; }
  to   { transform: translateY(0); opacity: 1; }
}

.feed-composer-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.feed-composer-placeholder {
  flex: 1;
  min-width: 0;
  font-size: 14px;
  color: var(--ink-3);
  text-decoration: none;
  cursor: text;
}
.feed-composer-placeholder:hover {
  color: var(--ink-2);
}
.feed-composer-types {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.feed-composer-type {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 5px 12px;
  /* Rubric D3 48px floor — composer type chip grows to 48px tall.
     Padding kept; min-height adds breathing. See [[brief_realtyx_tap_44_lint]]. */
  min-height: var(--tap);
  min-width: var(--tap);
  font-size: 12px;
  font-family: inherit;
  color: var(--ink-2);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 999px;
  cursor: pointer;
}
.feed-composer-type:hover {
  background: var(--ivory-2);
  border-color: var(--ink-3);
}
.feed-composer-type--active,
.feed-composer-type--active:hover {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}
@media (max-width: 600px) {
  .feed-composer-top {
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
  }
  .feed-composer-top .btn {
    width: 100%;
    text-align: center;
  }
}

/* ==========================================================================
   Ad Spots (Phase 1) — <x-ad-slot> render. Component-scoped; only loads
   on pages where ad-slot has a render-able creative. Returns zero DOM
   otherwise so these rules are no-ops on dry pages.
   ========================================================================== */
.ad-slot {
  display: block;
  position: relative;
  text-decoration: none;
  color: inherit;
  border: 1px solid #e6e6e6;
  border-radius: 8px;
  overflow: hidden;
  margin: 16px 0;
  background: #fff;
  transition: border-color 0.15s ease, transform 0.15s ease;
}
.ad-slot:hover {
  border-color: #c8c8c8;
}
.ad-slot img {
  width: 100%;
  height: auto;
  display: block;
}
.ad-slot-marker {
  position: absolute;
  top: 6px;
  right: 6px;
  font-size: 10px;
  padding: 2px 6px;
  background: rgba(0, 0, 0, 0.65);
  color: #fff;
  border-radius: 3px;
  letter-spacing: 0.5px;
  text-transform: uppercase;
}
.ad-slot--native {
  display: flex;
  gap: 12px;
  padding: 12px;
  align-items: stretch;
}
.ad-slot--native img {
  width: 120px;
  height: 120px;
  flex: 0 0 120px;
  border-radius: 4px;
  object-fit: cover;
}
.ad-slot-native-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.ad-slot-native-body h3 {
  margin: 0;
  font-size: 16px;
  line-height: 1.3;
}
.ad-slot-native-body p {
  margin: 0;
  font-size: 13px;
  color: #555;
}
.ad-slot-cta {
  font-size: 12px;
  font-weight: 600;
  color: #1f6feb;
  margin-top: auto;
}
@media (max-width: 600px) {
  .ad-slot--native img {
    width: 88px;
    height: 88px;
    flex-basis: 88px;
  }
  .ad-slot-native-body h3 { font-size: 15px; }
  .ad-slot-native-body p  { font-size: 12px; }
}

/* ==========================================================================
   Ad Spots Phase 3 dashboard — KPI tiles, sparkline cards, two-col split.
   ========================================================================== */
.ads-kpi-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 16px;
    margin: 24px 0;
}
.ads-kpi {
    border: 1px solid #e6e6e6;
    border-radius: 8px;
    padding: 16px;
    background: #fff;
}
.ads-kpi--alert {
    border-color: #f59e0b;
    background: #fffbeb;
}
.ads-kpi-label {
    color: #6b7280;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin-bottom: 8px;
}
.ads-kpi-value {
    font-size: 28px;
    font-weight: 600;
    line-height: 1.1;
    margin-bottom: 4px;
}
.ads-kpi-sub { color: #6b7280; }

.ads-dashboard-split {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(220px, 1fr);
    gap: 24px;
    margin-top: 24px;
}
@media (max-width: 900px) {
    .ads-dashboard-split { grid-template-columns: 1fr; }
}
.ads-dashboard-side .section-h2:not(:first-child) { margin-top: 24px; }

.ads-top-advertisers {
    list-style: none;
    padding: 0;
    margin: 0;
}
.ads-top-advertisers li {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 8px 0;
    border-bottom: 1px solid #f0f0f0;
}
.ads-top-name { margin-right: 6px; }
.ads-vacancy-list { list-style: none; padding: 0; margin: 0; }
.ads-vacancy-list li {
    display: flex;
    justify-content: space-between;
    padding: 6px 0;
    border-bottom: 1px solid #f0f0f0;
}
.ads-vacancy-cta { color: #6b7280; margin-top: 8px; }

.sparkline { margin: 0; }
.sparkline svg { display: block; }
.sparkline figcaption { margin-top: 4px; color: #6b7280; }

.yield-spark-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 16px;
    margin: 24px 0;
}
.yield-spark-card {
    border: 1px solid #e6e6e6;
    border-radius: 8px;
    padding: 16px;
    background: #fff;
}
.yield-spark-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    margin-bottom: 10px;
}
.yield-spark-total {
    font-weight: 600;
    font-size: 15px;
}
.ads-tune-form { max-width: 560px; margin-bottom: 32px; }

/* ==========================================================================
   Ad Spots Phase 4 — public /advertise marketplace.
   ========================================================================== */
.advertise-hero {
    text-align: left;
    margin: 24px 0 40px;
    max-width: 720px;
}
.advertise-lede {
    font-size: 17px;
    line-height: 1.6;
    color: #444;
    margin: 16px 0 24px;
}
.advertise-hero-cta { display: flex; gap: 12px; flex-wrap: wrap; }
.btn-lg { padding: 12px 22px; font-size: 15px; }

.advertise-flash {
    margin: 24px 0;
    border-color: #16a34a;
    background: #f0fdf4;
}

.advertise-why {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 20px;
    margin: 32px 0;
}
.advertise-why-card {
    border: 1px solid #e6e6e6;
    border-radius: 8px;
    padding: 20px;
    background: #fff;
}
.advertise-why-num { color: #9ca3af; font-size: 12px; margin-bottom: 8px; }
.advertise-why-title {
    font-size: 17px;
    margin: 0 0 8px;
    line-height: 1.3;
}
.advertise-why-card p { margin: 0; color: #555; font-size: 14px; line-height: 1.5; }

.advertise-rate-card { margin: 40px 0; }
.advertise-rate-card-sub { color: #6b7280; margin: -8px 0 16px; }
.advertise-rate-table th { white-space: nowrap; }

.advertise-lead { margin: 40px 0; max-width: 720px; }
.advertise-lead-sub { color: #6b7280; margin: -8px 0 16px; }
.advertise-form .form-row + .form-row { margin-top: 12px; }

.advertise-honeypot {
    position: absolute;
    left: -9999px;
    top: -9999px;
    height: 0;
    overflow: hidden;
}

.advertise-faq { margin: 40px 0 60px; max-width: 720px; }
.advertise-faq details {
    border-bottom: 1px solid #e6e6e6;
    padding: 12px 0;
}
.advertise-faq summary {
    cursor: pointer;
    font-weight: 600;
    font-size: 15px;
    padding: 4px 0;
}
.advertise-faq details[open] summary { margin-bottom: 8px; }
.advertise-faq details p { margin: 0; color: #555; line-height: 1.5; }

.page-flash--error {
    border-color: #dc2626;
    background: #fef2f2;
    color: #991b1b;
}

.inquiry-message {
    border-left: 3px solid #c8c8c8;
    padding-left: 12px;
    margin: 8px 0 16px;
    color: #444;
    font-style: italic;
}
.inquiry-message--internal {
    border-left-color: #f59e0b;
    background: #fffbeb;
    padding: 8px 12px;
    font-style: normal;
}
.inquiry-action-form { margin-bottom: 24px; }

.page-flash--info {
    border-color: #1f6feb;
    background: #eff6ff;
    color: #1e40af;
}

/* ==========================================================================
   Ad Spots Phase 6 — advertiser self-serve dashboard.
   ========================================================================== */
.advertiser-back { margin: 8px 0 16px; font-size: 13px; }
.advertiser-back a { color: #6b7280; }
.advertiser-back a:hover { color: #1f6feb; }

.advertiser-empty {
    border: 1px dashed #d0d0d0;
    border-radius: 8px;
    padding: 32px;
    text-align: center;
    margin: 32px 0;
    color: #6b7280;
}
.advertiser-empty p { margin: 0 0 16px; }

.advertiser-foot { color: #6b7280; margin-top: 24px; }
.advertiser-foot a { color: #1f6feb; }

.advertise-dashboard-banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 12px 16px;
    margin: 16px 0 24px;
    border: 1px solid #d1e9ff;
    background: #f0f8ff;
    border-radius: 8px;
    color: #1e40af;
    font-size: 14px;
}
@media (max-width: 600px) {
    .advertise-dashboard-banner { flex-direction: column; align-items: flex-start; }
}

/* ──────────────────────────────────────────────────────────────────
   Phase 10.7 — Developer pending-verification screen.
   Reuses .dash-section / .seeker-quick-actions / .page-h1 from the
   broader dashboard surface; only adds the bespoke card + meta grid
   for the "what we received" panel and the "what you'll get" perks
   list.
   ────────────────────────────────────────────────────────────────── */

.dev-pending-card {
    border: 1px solid var(--line);
    border-radius: 8px;
    padding: 18px 20px;
    background: var(--paper);
}

.dev-pending-meta {
    display: grid;
    grid-template-columns: minmax(140px, 220px) 1fr;
    row-gap: 10px;
    column-gap: 16px;
    margin: 0 0 16px;
}

.dev-pending-row {
    display: contents;
}
.dev-pending-row dt {
    color: var(--ink-3);
    font-size: 13px;
    align-self: center;
}
.dev-pending-row dd {
    margin: 0;
    color: var(--ink);
}

.dev-pending-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    border-top: 1px dashed var(--line);
    padding-top: 14px;
    margin-top: 4px;
}

.dev-pending-perks {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.dev-pending-perks li {
    border: 1px solid var(--line);
    border-radius: 8px;
    padding: 10px 14px;
    background: var(--paper);
    color: var(--ink);
    font-size: 14px;
}
.dev-pending-perks li::before {
    content: "✓";
    color: var(--accent, #2563eb);
    margin-right: 10px;
    font-weight: 600;
}

@media (max-width: 600px) {
    .dev-pending-meta {
        grid-template-columns: 1fr;
        row-gap: 4px;
    }
    .dev-pending-row dt {
        margin-top: 8px;
    }
}

/* ──────────────────────────────────────────────────────────────────
   Phase 11 — Public developer + project pages.

   Two URL families:
     /builders/{slug}  — developer-brand hub (Organization)
     /projects/{slug}  — project detail page (ApartmentComplex)

   Reuses .dash-section / .do-property-grid / .do-property-card from
   the dashboard surface so brand chrome stays consistent; adds only
   the page-specific bits (hero, stat strip, configurations table,
   listing list, sibling list, brand chips on the listing detail).
   ────────────────────────────────────────────────────────────────── */

.public-hero {
    margin: 0 0 24px;
}

.public-stat-strip {
    display: flex;
    flex-wrap: wrap;
    gap: 24px;
    margin-top: 12px;
    padding: 12px 16px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--paper);
}
.public-stat {
    display: flex;
    align-items: baseline;
    gap: 6px;
    color: var(--ink-3);
    font-size: 13px;
}
.public-stat strong {
    color: var(--ink);
    font-size: 18px;
    font-weight: 600;
}

.public-availability-strip {
    display: inline-flex;
    flex-wrap: wrap;
    gap: 10px;
    align-items: center;
    padding: 8px 14px;
    margin: 0 0 16px;
    border: 1px solid var(--accent, #2563eb);
    border-radius: 999px;
    background: rgba(37, 99, 235, 0.05);
    color: var(--ink);
    font-size: 13px;
}
.public-availability-strip strong {
    color: var(--accent, #2563eb);
}

.public-narrative {
    color: var(--ink);
    line-height: 1.6;
    margin: 8px 0;
}

.public-config-table {
    width: 100%;
    border-collapse: collapse;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: 8px;
    overflow: hidden;
}
.public-config-table th,
.public-config-table td {
    padding: 10px 14px;
    text-align: left;
    border-bottom: 1px solid var(--line);
}
.public-config-table thead th {
    background: var(--ivory-2);
    color: var(--ink-3);
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.public-config-table tbody tr:last-child td {
    border-bottom: 0;
}

.public-chip-row {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
.public-chip {
    display: inline-flex;
    align-items: center;
    padding: 4px 10px;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--paper);
    color: var(--ink);
    font-size: 12px;
}

.public-listing-list,
.public-sibling-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.public-listing-row {
    border: 1px solid var(--line);
    border-radius: 8px;
    padding: 10px 14px;
    background: var(--paper);
}
.public-listing-row:hover {
    background: var(--ivory-2);
}
.public-listing-title {
    color: var(--ink);
    text-decoration: none;
    font-weight: 500;
}
.public-listing-title:hover {
    text-decoration: underline;
}
.public-sibling-list li {
    border: 1px solid var(--line);
    border-radius: 8px;
    padding: 8px 14px;
    background: var(--paper);
}
.public-sibling-list a {
    color: var(--ink);
    text-decoration: none;
}
.public-sibling-list a:hover {
    text-decoration: underline;
}

/* Hero brand chips on the public listing detail page —
   "In {Project} · By {Builder}" linked to the brand hubs. */
.pl-hero-brand-chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin: 6px 0 4px;
    color: var(--ink-3);
}
.pl-hero-brand-chip {
    color: var(--ink);
    text-decoration: none;
    border-bottom: 1px dashed var(--ink-3);
}
.pl-hero-brand-chip:hover {
    border-bottom-color: var(--ink);
    color: var(--ink);
}
.pl-hero-brand-chip--static {
    border-bottom: 0;
    color: var(--ink);
}

/* ──────────────────────────────────────────────────────────────────
   Phase 11.6 — Suggest-a-project workflow.
   - .ac-empty / .ac-suggest-btn : compose-listing autocomplete empty
     state with the "Suggest it" CTA.
   - .ac-modal* : inline modal that opens from the empty state.
   - .lsugg-* : admin queue list view (/admin/listing-suggestions).
   ────────────────────────────────────────────────────────────────── */

.ac-empty {
    padding: 14px 16px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.ac-empty-line { color: var(--ink-3); font-size: 12px; }
.ac-suggest-btn {
    align-self: flex-start;
    padding: 6px 12px;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--paper);
    color: var(--ink);
    font-size: 13px;
    cursor: pointer;
    transition: border-color 0.12s ease, background 0.12s ease;
}
.ac-suggest-btn:hover {
    border-color: var(--ink-3);
    background: var(--ivory-2);
}
.ac-empty-help { color: var(--ink-3); }

.ac-modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
}
.ac-modal {
    background: var(--paper);
    border-radius: 12px;
    border: 1px solid var(--line);
    max-width: 520px;
    width: 100%;
    max-height: 90vh;
    overflow-y: auto;
    box-shadow: 0 16px 48px rgba(0, 0, 0, 0.18);
}
.ac-modal-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 16px 20px;
    border-bottom: 1px solid var(--line);
}
.ac-modal-head h3 {
    margin: 0;
    font-size: 17px;
    color: var(--ink);
}
.ac-modal-close {
    background: none;
    border: 0;
    font-size: 22px;
    line-height: 1;
    cursor: pointer;
    color: var(--ink-3);
    padding: 4px 8px;
}
.ac-modal-close:hover { color: var(--ink); }
.ac-modal-form {
    padding: 18px 20px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}
.ac-modal-form .form-label {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: 13px;
    color: var(--ink-2);
}
.ac-modal-foot {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    padding-top: 6px;
    border-top: 1px dashed var(--line);
    margin-top: 6px;
}

/* Admin queue rows. */
.lsugg-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 14px;
}
.lsugg-row {
    border: 1px solid var(--line);
    border-radius: 10px;
    padding: 16px 20px;
    background: var(--paper);
}
.lsugg-row-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 10px;
}
.lsugg-row-title { margin: 0; font-size: 17px; color: var(--ink); }
.lsugg-row-when { color: var(--ink-3); }
.lsugg-row-meta {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 10px 24px;
    margin: 0 0 12px;
}
.lsugg-row-meta > div { display: contents; }
.lsugg-row-meta dt {
    color: var(--ink-3);
    text-transform: uppercase;
    font-size: 11px;
    letter-spacing: 0.04em;
}
.lsugg-row-meta dd {
    margin: 0 0 8px;
    color: var(--ink);
}
.lsugg-row-notes {
    margin: 8px 0;
    padding: 10px 14px;
    border-left: 3px solid var(--ink-3);
    background: var(--ivory-2);
    color: var(--ink-2);
    font-size: 13px;
    line-height: 1.5;
}
.lsugg-row-review {
    margin: 8px 0;
    color: var(--ink-3);
}
.lsugg-row-status { color: var(--ink-3); }
.lsugg-row-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    padding-top: 12px;
    border-top: 1px dashed var(--line);
    margin-top: 8px;
}
.lsugg-action-form {
    display: flex;
    gap: 8px;
    flex: 1 1 280px;
}
.lsugg-action-form .form-input {
    flex: 1;
    font-size: 12px; /* fs-input-allow — inline action form, follow-up: --fs-input-sm */
    padding: 6px 10px;
}

@media (max-width: 700px) {
    .lsugg-row-meta { grid-template-columns: 1fr; }
}

/* Phase 11.5a — AI-enrich button on suggestion rows.
   Solo form so it doesn't share the inline text input layout of
   approve/reject rows. */
.lsugg-action-form--solo {
    flex: 0 0 auto;
}

/* Phase 11.5a — Anthropic usage totals strip. */
.anthropic-totals {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 14px;
}
.anthropic-total {
    border: 1px solid var(--line);
    border-radius: 10px;
    padding: 14px 18px;
    background: var(--paper);
}
.anthropic-total-label { color: var(--ink-3); margin-bottom: 4px; }
.anthropic-total-value {
    font-size: 26px;
    font-weight: 600;
    color: var(--ink);
    letter-spacing: -0.01em;
}
.anthropic-total-sub { color: var(--ink-3); margin-top: 4px; }

/* Empty-state CTA list on /projects/{slug}. */
.public-empty-cta-list {
    list-style: none;
    padding: 0;
    margin: 12px 0 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.public-empty-cta-list li {
    border: 1px solid var(--line);
    border-radius: 8px;
    padding: 10px 14px;
    background: var(--paper);
    color: var(--ink);
}

/* Phase 11 — public /projects + /builders index pages. */
.public-index-search {
    display: flex;
    gap: 8px;
    margin-top: 14px;
    max-width: 540px;
}
.public-index-search .form-input { flex: 1; }

.public-index-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: 10px;
}
.public-index-row {
    display: flex;
    flex-direction: column;
    gap: 4px;
    border: 1px solid var(--line);
    border-radius: 8px;
    padding: 12px 14px;
    background: var(--paper);
    color: var(--ink);
    text-decoration: none;
    transition: border-color 0.12s ease, background 0.12s ease;
}
.public-index-row:hover {
    border-color: var(--ink-3);
    background: var(--ivory-2);
}
.public-index-row-title {
    font-weight: 600;
    color: var(--ink);
}
.public-index-row-meta {
    color: var(--ink-3);
}
.public-index-row-pill {
    display: inline-block;
    padding: 1px 7px;
    border: 1px solid var(--accent, #2563eb);
    border-radius: 999px;
    color: var(--accent, #2563eb);
    font-size: 10px;
    letter-spacing: 0.03em;
}

/* Phase 11.5b — builder dedupe admin tool. */
.bdedupe-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 14px; }
.bdedupe-row {
    border: 1px solid var(--line);
    border-radius: 10px;
    padding: 14px 18px;
    background: var(--paper);
}
.bdedupe-grid {
    display: grid;
    grid-template-columns: 1fr 40px 1fr;
    gap: 14px;
    align-items: start;
    margin-bottom: 14px;
}
.bdedupe-side { min-width: 0; }
.bdedupe-side-label { color: var(--ink-3); margin-bottom: 4px; }
.bdedupe-side-name { font-size: 17px; font-weight: 600; color: var(--ink); margin-bottom: 6px; }
.bdedupe-side-name a { color: inherit; text-decoration: none; border-bottom: 1px dotted var(--ink-3); }
.bdedupe-side-name a:hover { border-bottom-color: var(--ink); }
.bdedupe-side-meta { color: var(--ink-3); line-height: 1.5; }
.bdedupe-arrow {
    align-self: center;
    text-align: center;
    color: var(--ink-3);
    font-size: 20px;
}
.bdedupe-actions {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
    padding-top: 12px;
    border-top: 1px dashed var(--line);
}
@media (max-width: 700px) {
    .bdedupe-grid { grid-template-columns: 1fr; }
    .bdedupe-arrow { display: none; }
}

/* Phase 11.5b funnel — /builders index pills + claim CTA strip,
   /builders/{slug} hero status pill + claim section, /projects
   cross-link to /builders. */

.public-index-filters {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px dashed var(--line);
}
.public-index-pill {
    display: inline-block;
    padding: 4px 12px;
    border: 1px solid var(--line);
    border-radius: 999px;
    color: var(--ink-3);
    text-decoration: none;
    background: var(--paper);
}
.public-index-pill:hover { color: var(--ink); border-color: var(--ink-3); }
.public-index-pill--active {
    color: var(--ink);
    background: var(--ivory-2);
    border-color: var(--ink-3);
    font-weight: 500;
}
.public-index-claim-cta {
    margin-left: auto;
    color: var(--ink-3);
}
.public-index-claim-cta a {
    color: var(--accent, #2563eb);
    font-weight: 500;
}
.public-index-cross-link {
    margin-top: 8px;
    color: var(--ink-3);
}
.public-index-cross-link a { color: var(--ink); border-bottom: 1px dotted var(--ink-3); text-decoration: none; }
.public-index-cross-link a:hover { border-bottom-color: var(--ink); }

/* Index row pills — Verified / Claimed beside the name. */
.public-index-row-pill {
    display: inline-block;
    margin-left: 6px;
    padding: 1px 8px;
    border-radius: 999px;
    font-size: 10px;
    letter-spacing: 0.03em;
    vertical-align: middle;
}
.public-index-row-pill--verified {
    background: rgba(34, 139, 70, 0.12);
    color: #15803d;
    border: 1px solid rgba(34, 139, 70, 0.3);
}
.public-index-row-pill--pending {
    background: rgba(216, 163, 94, 0.12);
    color: #b06c12;
    border: 1px solid rgba(216, 163, 94, 0.3);
}

/* Hero pill on /builders/{slug}. */
.public-hero-pill {
    display: inline-block;
    margin-left: 10px;
    padding: 3px 10px;
    border-radius: 999px;
    font-size: 13px;
    letter-spacing: 0.02em;
    vertical-align: middle;
}
.public-hero-pill--verified {
    background: rgba(34, 139, 70, 0.12);
    color: #15803d;
    border: 1px solid rgba(34, 139, 70, 0.3);
}
.public-hero-pill--pending {
    background: rgba(216, 163, 94, 0.12);
    color: #b06c12;
    border: 1px solid rgba(216, 163, 94, 0.3);
}

/* Builder claim section on sparse hubs — the revenue funnel CTA. */
.dash-section--cta-builder {
    background: linear-gradient(180deg, var(--ivory-2) 0%, var(--paper) 100%);
    border: 1px solid var(--saffron-deep, #d8a35e);
    border-radius: 12px;
}
.dash-section--cta-builder .dash-section-title {
    color: var(--ink);
}

/* ────────────────────────────────────────────────────────────────
   Phase 11.7 — developer self-service surfaces
     - /developer/profile      brand profile editor
     - /developer/projects     my-projects index + edit
     - /builders/{slug}        logo + description + contact card
   ──────────────────────────────────────────────────────────────── */

/* Public hero: logo + heading row, brand description, contact card. */
.public-hero-head {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
}
.public-hero-logo {
    width: 64px;
    height: 64px;
    border-radius: 8px;
    object-fit: contain;
    background: var(--paper);
    border: 1px solid var(--line);
    flex: 0 0 auto;
}
.public-hero-description {
    color: var(--ink);
    line-height: 1.55;
    max-width: 64ch;
    margin: 12px 0 0;
}
.public-brand-contact {
    display: inline-block;
    margin-top: 16px;
    padding: 10px 16px;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: 8px;
}
.public-brand-contact strong {
    display: block;
    margin-bottom: 4px;
    color: var(--ink);
    font-size: 13px;
}
.public-brand-contact-row {
    color: var(--ink-3);
}
.public-brand-contact-row a {
    color: var(--ink);
    text-decoration: none;
    border-bottom: 1px dotted var(--ink-3);
}
.public-brand-contact-row a:hover {
    border-bottom-color: var(--ink);
}

/* Developer projects index — row list with actions. */
.dev-project-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.dev-project-row {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 16px;
    padding: 14px 18px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--paper);
}
.dev-project-row-main {
    flex: 1 1 320px;
    min-width: 0;
}
.dev-project-row-title {
    margin: 0 0 6px;
    font-size: 17px;
    color: var(--ink);
}
.dev-project-row-title a {
    color: var(--ink);
    text-decoration: none;
}
.dev-project-row-title a:hover {
    text-decoration: underline;
}
.dev-project-row-meta {
    color: var(--ink-3);
    line-height: 1.55;
}
.dev-project-row-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: flex-start;
}

@media (max-width: 600px) {
    .dev-project-row {
        flex-direction: column;
    }
    .dev-project-row-actions {
        width: 100%;
    }
}

/* ==========================================================================
   Admin edit-form context strip (Phase 11.7 — /admin/builders/{id}/edit).
   Five-cell grid above the form: projects count, claimed-by, verification,
   last-touched, actions (view public + impersonate). Builds the situational
   awareness an admin needs without flipping tabs.
   ========================================================================== */
.admin-context-strip {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 12px;
    margin: 16px 0 8px;
    padding: 12px 14px;
    border: 1px solid var(--line);
    background: color-mix(in oklab, var(--ink) 3%, var(--paper));
    border-radius: 6px;
}
.admin-context-cell {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}
.admin-context-cell--actions {
    align-items: flex-start;
    justify-content: center;
    gap: 6px;
}
.admin-context-label {
    color: var(--ink-3);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-size: 11px;
}
.admin-context-value {
    font-weight: 600;
    color: var(--ink);
    text-decoration: none;
    overflow: hidden;
    text-overflow: ellipsis;
}
a.admin-context-value:hover {
    color: var(--accent, #1f6feb);
    text-decoration: underline;
}
.admin-context-value--empty {
    color: var(--ink-4);
    font-weight: 400;
    font-style: italic;
}
@media (max-width: 900px) {
    .admin-context-strip {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
    .admin-context-cell--actions {
        grid-column: 1 / -1;
        flex-direction: row;
        flex-wrap: wrap;
    }
}
@media (max-width: 480px) {
    .admin-context-strip {
        grid-template-columns: 1fr;
    }
}

/* Banner inside a fieldset for warnings / advisory notes — e.g. the
   "developer self-edits these fields" overlap notice on the Brand
   presentation group. Distinct from form-note (which is a single-field
   inline hint) by living above all fields and reading group-wide. */
.form-fieldset-note {
    margin: 0 0 12px;
    padding: 10px 12px;
    background: #fffbeb;
    border-left: 3px solid #f59e0b;
    color: #92400e;
    font-size: 13px;
    line-height: 1.5;
    border-radius: 4px;
}
.form-fieldset-note a {
    color: #92400e;
    text-decoration: underline;
}

/* Amber warning variant of the existing .page-flash. Used by the
   merged-builder banner + any future admin advisory. */
.page-flash--warning {
    border-color: #f59e0b;
    background: #fffbeb;
    color: #92400e;
}
.page-flash--warning a {
    color: #92400e;
    text-decoration: underline;
}

/* Builder autocomplete (admin society edit/create) — same dropdown
   shape as .ac-society / .ac-locality. Adds an inline "Clear" button
   so admin can detach a project from its current builder without
   typing-over (which would still leave builder_id stale). */
.ac-builder { position: relative; }
.ac-builder-row {
    display: flex;
    align-items: stretch;
    gap: 6px;
}
.ac-builder-row > .form-input { flex: 1; }
.ac-builder-clear {
    flex: 0 0 auto;
    padding: 0 12px;
    border: 1px solid var(--line);
    background: var(--paper);
    color: var(--ink-3);
    border-radius: 6px;
    cursor: pointer;
}
.ac-builder-clear:hover {
    color: #b91c1c;
    border-color: #b91c1c;
}

/* Danger zone — separated from the main form so the Delete button is
   visually distant from Save. Used on /admin/builders/{id}/edit +
   /admin/societies/{id}/edit. The card has a red-tinged border so
   admin reads it as "not the main flow". */
.admin-danger-zone {
    margin-top: 32px;
    padding: 14px 16px;
    border: 1px solid #fecaca;
    background: #fef2f2;
    border-radius: 6px;
}
.admin-danger-zone-row {
    display: flex;
    align-items: center;
    gap: 16px;
    justify-content: space-between;
    flex-wrap: wrap;
}
.admin-danger-zone-row > div:first-child { flex: 1 1 320px; min-width: 0; }
.admin-danger-zone-row > .btn-danger { flex: 0 0 auto; }

/* Admin filter context banner — surfaces "you're looking at the subset
   filtered by X" so admin doesn't lose track when arriving via a deep
   link. Used on /admin/societies?builder_id=… today. */
.admin-filter-banner {
    margin: 12px 0 16px;
    padding: 10px 14px;
    border-left: 3px solid var(--accent, #1f6feb);
    background: color-mix(in oklab, var(--ink) 3%, var(--paper));
    border-radius: 4px;
}
.admin-filter-banner a { text-decoration: underline; }
.admin-filter-banner--warn {
    border-left-color: #f59e0b;
    background: #fffbeb;
    color: #92400e;
}
.admin-filter-banner--warn a { color: #92400e; }

/* Bulk action bar — sticky at top of the table wrapper, appears when
   ≥1 row is selected. Houses the target builder typeahead + Move /
   Detach / Cancel actions. The form wraps both this bar and the
   table so the per-row checkboxes submit naturally. */
.admin-societies-bulk { display: block; }
.bulk-action-bar {
    position: sticky;
    top: 8px;
    z-index: 20;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px 20px;
    margin-bottom: 12px;
    padding: 12px 14px;
    background: var(--paper);
    border: 1px solid var(--accent, #1f6feb);
    border-radius: 8px;
    box-shadow: 0 4px 12px color-mix(in oklab, var(--ink) 12%, transparent);
}
.bulk-action-bar-count { flex: 0 0 auto; }
.bulk-action-bar-count strong { font-size: 16px; }
.bulk-action-bar-target {
    flex: 1 1 320px;
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 280px;
}
.bulk-action-bar-target > .form-label { flex: 0 0 auto; white-space: nowrap; }
.bulk-action-bar-target > .ac-builder { flex: 1 1 auto; min-width: 0; }
.bulk-action-bar-actions {
    flex: 0 0 auto;
    display: flex;
    gap: 6px;
}

/* Checkbox column on admin tables. Narrow, centered. Checked rows get
   a tint so admin can see selection state across a long list. */
.admin-table--checkable .admin-table-check {
    width: 36px;
    padding-left: 12px;
    padding-right: 0;
}
.admin-table-row--checked {
    background: color-mix(in oklab, var(--accent, #1f6feb) 6%, var(--paper));
}

/* Wrapping variant of .directory-filters for admin pages that carry
   more than 2-3 filter inputs (e.g. /admin/societies now has q +
   city + state + builder + needs_review). */
.directory-filters--wrap {
    flex-wrap: wrap;
    gap: 8px 10px;
}
.directory-filters--wrap > .form-input {
    flex: 1 1 180px;
    min-width: 140px;
    max-width: 280px;
}

/* ==========================================================================
   Public project detail (/projects/{slug}) — Phase A richness.
   Status pill, key-facts strip, FAQ accordion.
   ========================================================================== */

/* Computed status pill in the hero. Single source of truth replacing
   the bare "New launch" badge. Variants encode possession state +
   inventory state so a crawler-friendly status surfaces above the fold. */
.public-status-pill {
    display: inline-flex;
    align-items: center;
    padding: 4px 10px;
    border-radius: 999px;
    font-weight: 600;
    letter-spacing: 0.02em;
    line-height: 1.2;
    border: 1px solid var(--line);
}
.public-status-pill--ready              { background: #ecfdf5; color: #065f46; border-color: #6ee7b7; }
.public-status-pill--under-construction { background: #fff7ed; color: #9a3412; border-color: #fdba74; }
.public-status-pill--pre-launch         { background: #eef2ff; color: #3730a3; border-color: #a5b4fc; }
.public-status-pill--new-launch         { background: #fff4d6; color: #92400e; border-color: #fbbf24; }
.public-status-pill--sold-out           { background: #f3f4f6; color: #4b5563; border-color: #d1d5db; }
.public-status-pill--warn               { background: #fef3c7; color: #92400e; border-color: #f59e0b; }

/* Cache-source tag — small inline label next to a listing-row title
   when the underlying row is from listings_cache (DB.com brochure
   mirror) rather than a broker-posted listings_local row. Signals
   to the buyer that the listing isn't claimed by a Realty of India
   broker yet. */
.public-listing-source-tag {
    display: inline-block;
    margin-left: 6px;
    padding: 1px 6px;
    border-radius: 999px;
    background: color-mix(in oklab, var(--ink) 5%, var(--paper));
    color: var(--ink-3);
    font-weight: 500;
    font-size: 10px;
    border: 1px solid var(--line);
    vertical-align: middle;
}

/* ==========================================================================
   Builder hero card (/builders/{slug}).
   Tinted wrapper around the existing public-hero; adds an initials
   monogram chip when no logo_url is set so every brand reads as
   "branded" instead of a bare H1. Risk callout (insolvency / NCLT)
   surfaces below the name line inside the same card.
   ========================================================================== */

.public-builder-hero-card {
    margin: 4px 0 24px;
    padding: 22px 24px 20px;
    background: color-mix(in oklab, var(--accent, #1f6feb) 4%, var(--paper));
    border: 1px solid color-mix(in oklab, var(--accent, #1f6feb) 18%, var(--line));
    border-radius: 12px;
}
@media (max-width: 600px) {
    .public-builder-hero-card { padding: 18px 16px 16px; }
}

/* Monogram chip. Hidden by default — only shows when explicitly
   given the --show modifier (no logo branch) OR when the logo's
   onerror handler kicks in. Keeps the chip from double-rendering
   next to a working logo image. */
.public-hero-initials {
    display: none;
    width: 56px;
    height: 56px;
    border-radius: 12px;
    background: color-mix(in oklab, var(--accent, #1f6feb) 12%, var(--paper));
    color: var(--accent, #1f6feb);
    align-items: center;
    justify-content: center;
    font-size: 20px;
    font-weight: 700;
    flex-shrink: 0;
    letter-spacing: 0.02em;
    font-family: var(--font-serif, Georgia, serif);
}
.public-hero-initials--show {
    display: flex;
}
@media (max-width: 600px) {
    .public-hero-initials {
        width: 44px;
        height: 44px;
        font-size: 16px;
        border-radius: 10px;
    }
}

/* Risk callout — inset slightly so it reads as a sub-element of the
   hero rather than a hero pill, while still being the visual focus
   for buyers when present. */
.public-hero-risk {
    margin: 10px 0 4px;
}

/* Key-facts strip — visual tile row below the hero. Each tile carries
   one fact: label (small mono caps) + value (larger sans). Compact on
   wide screens, wraps cleanly on mobile. */
.public-keyfacts {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: 10px;
    margin: 18px 0 28px;
    padding: 14px;
    border: 1px solid var(--line);
    background: color-mix(in oklab, var(--ink) 3%, var(--paper));
    border-radius: 8px;
}
.public-keyfact {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}
.public-keyfact-label {
    color: var(--ink-3);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-size: 11px;
}
.public-keyfact-value {
    font-weight: 600;
    color: var(--ink);
    font-size: 14px;
    overflow-wrap: anywhere;
}
.public-keyfact--rera {
    grid-column: span 2;
}
@media (max-width: 480px) {
    .public-keyfact--rera { grid-column: span 1; }
}

/* FAQ accordion — native <details>/<summary> for zero-JS expansion.
   Below amenities, above active listings on the project page. */
.public-faq-accordion {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.public-faq-item {
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--paper);
    overflow: hidden;
}
.public-faq-item[open] {
    background: color-mix(in oklab, var(--ink) 2%, var(--paper));
}
.public-faq-question {
    cursor: pointer;
    padding: 12px 16px;
    font-weight: 600;
    color: var(--ink);
    list-style: none;
    position: relative;
    padding-right: 36px;
}
.public-faq-question::-webkit-details-marker { display: none; }
.public-faq-question::after {
    content: '+';
    position: absolute;
    right: 16px;
    top: 50%;
    transform: translateY(-50%);
    font-size: 18px;
    color: var(--ink-3);
    transition: transform 0.15s ease;
}
.public-faq-item[open] .public-faq-question::after {
    content: '−';
}
.public-faq-answer {
    padding: 0 16px 14px;
    color: var(--ink-2);
    line-height: 1.55;
}

/* ==========================================================================
   Phase B — project hero image, rich builder card, floor plans gallery,
   locality callout. All on /projects/{slug}.
   ========================================================================== */

/* Hero image above the H1. Lazy-loaded; max-height caps overly-tall
   uploads so the H1 stays in the viewport on standard screens. */
.public-hero-image {
    margin: 0 0 18px;
    border-radius: 10px;
    overflow: hidden;
    background: color-mix(in oklab, var(--ink) 5%, var(--paper));
}
.public-hero-image img {
    display: block;
    width: 100%;
    height: auto;
    max-height: 480px;
    object-fit: cover;
}

/* Rich builder card — logo on the left, name + description + links on
   the right. Stacks vertically on mobile. */
.public-builder-card {
    display: flex;
    align-items: flex-start;
    gap: 16px;
    padding: 16px;
    border: 1px solid var(--line);
    background: var(--paper);
    border-radius: 8px;
}
.public-builder-card-logo {
    flex: 0 0 auto;
    width: 88px;
    height: 88px;
    border-radius: 8px;
    overflow: hidden;
    background: color-mix(in oklab, var(--ink) 4%, var(--paper));
    display: flex;
    align-items: center;
    justify-content: center;
}
.public-builder-card-logo img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}
.public-builder-card-body { flex: 1 1 auto; min-width: 0; }
.public-builder-card-name {
    margin: 0 0 4px;
    font-size: 18px;
    font-weight: 600;
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}
.public-builder-card-name a {
    color: var(--ink);
    text-decoration: none;
}
.public-builder-card-name a:hover { text-decoration: underline; }
.public-builder-card-meta {
    color: var(--ink-3);
    margin: 0 0 8px;
}
.public-builder-card-desc {
    margin: 0 0 10px;
    color: var(--ink-2);
    line-height: 1.55;
}
.public-builder-card-links a {
    color: var(--accent, #1f6feb);
    text-decoration: none;
}
.public-builder-card-links a:hover { text-decoration: underline; }
@media (max-width: 560px) {
    .public-builder-card { flex-direction: column; }
    .public-builder-card-logo { width: 64px; height: 64px; }
}

/* Floor plans gallery — grid of thumbnail cards. Click opens the
   source URL in a new tab (no JS lightbox in v1). */
.public-floorplan-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
    gap: 12px;
}
.public-floorplan-card {
    display: flex;
    flex-direction: column;
    gap: 6px;
    text-decoration: none;
    color: inherit;
    border: 1px solid var(--line);
    border-radius: 8px;
    overflow: hidden;
    background: var(--paper);
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.public-floorplan-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px color-mix(in oklab, var(--ink) 10%, transparent);
}
.public-floorplan-thumb {
    width: 100%;
    aspect-ratio: 4 / 3;
    background: color-mix(in oklab, var(--ink) 4%, var(--paper));
    overflow: hidden;
}
.public-floorplan-thumb img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    display: block;
}
.public-floorplan-meta {
    padding: 6px 10px 10px;
    color: var(--ink-3);
}

/* Locality callout — soft tinted card. Anchors the geographic
   context + internal link to the locality hub. */
.public-locality-callout {
    padding: 14px 16px;
    background: color-mix(in oklab, var(--accent, #1f6feb) 5%, var(--paper));
    border-left: 3px solid var(--accent, #1f6feb);
    border-radius: 4px;
}
.public-locality-callout p { margin: 0; line-height: 1.55; }
.public-locality-callout p + p { margin-top: 6px; }
.public-locality-callout a {
    color: var(--accent, #1f6feb);
    text-decoration: none;
}
.public-locality-callout a:hover { text-decoration: underline; }

/* ==========================================================================
   Builder hub (/builders/{slug}) — Phase 2 richness.
   Credibility metrics grid + city coverage chips with project counts.
   Status pill, key-facts strip, and FAQ accordion reuse the project page's
   classes.
   ========================================================================== */

/* Credibility metrics grid — track record + RERA complaints + legal
   disputes. Each cell has a label, a hero number, and a one-line caption.
   --warn variant tints the cell amber for items the buyer should pay
   attention to (complaints / disputes counts > 0). */
.public-credibility-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 12px;
}
.public-credibility-cell {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 14px 16px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: color-mix(in oklab, var(--ink) 3%, var(--paper));
}
.public-credibility-cell--warn {
    background: #fffbeb;
    border-color: #fde68a;
}
.public-credibility-label {
    color: var(--ink-3);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-size: 11px;
}
.public-credibility-value {
    font-size: 24px;
    font-weight: 600;
    color: var(--ink);
    line-height: 1.1;
}
.public-credibility-cell--warn .public-credibility-value {
    color: #92400e;
}

/* City-coverage chips. Reuses .public-chip-row from amenities; this
   nested rule just lets the count be visually distinct from the city
   name within the chip. */
.public-chip strong {
    color: var(--ink-3);
    font-weight: 500;
    margin-left: 4px;
}

/* ==========================================================================
   Admin content enrichment hub (/admin/enrichment).
   Export form + packet display + import form + result panel.
   ========================================================================== */

.enrichment-form-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 10px;
}

.enrichment-form .form-actions {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}

/* Packet display — read-only textarea + copy button at top */
.enrichment-packet {
    margin-top: 16px;
    padding: 14px 16px;
    border: 1px solid var(--accent, #1f6feb);
    background: color-mix(in oklab, var(--accent, #1f6feb) 4%, var(--paper));
    border-radius: 8px;
}
.enrichment-packet-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 10px;
    flex-wrap: wrap;
    gap: 10px;
}
.enrichment-packet-textarea {
    width: 100%;
    font-size: 12px; /* fs-input-allow — packet textarea, follow-up: --fs-input-sm */
    line-height: 1.4;
    resize: vertical;
    background: var(--paper);
}

/* Import result panel — green when applied, neutral when dry-run */
.enrichment-result {
    margin-top: 16px;
    padding: 14px 16px;
    border: 1px solid var(--line);
    border-radius: 8px;
}
.enrichment-result--applied {
    border-color: #6ee7b7;
    background: #ecfdf5;
}
.enrichment-result--dryrun {
    border-color: var(--line);
    background: color-mix(in oklab, var(--ink) 4%, var(--paper));
}
.enrichment-stats {
    list-style: none;
    padding: 0;
    margin: 8px 0 12px;
    display: flex;
    flex-wrap: wrap;
    gap: 6px 18px;
    color: var(--ink-2);
}
.enrichment-stats li { white-space: nowrap; }
.enrichment-stats strong { color: var(--ink); }

/* ===== Admin queue surfaces — abuse, moderation, blocklist =====
 * Shared visual shell for /admin/abuse, /admin/moderation,
 * /admin/blocklist. The .moderation-* family was used by all three
 * but unstyled — browser defaults rendered a bare <article> list
 * with cramped buttons. */
.admin-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 2px;
    border-bottom: 1px solid var(--line);
    margin: 16px 0 22px;
}
.admin-tab {
    padding: 9px 16px;
    color: var(--ink-3);
    text-decoration: none;
    font-size: 13px;
    font-weight: 500;
    letter-spacing: 0.01em;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    transition: color 120ms, border-color 120ms;
}
.admin-tab:hover { color: var(--ink); }
.admin-tab--active {
    color: var(--ink);
    border-bottom-color: var(--saffron-deep);
    font-weight: 600;
}

.moderation-list {
    display: flex;
    flex-direction: column;
    gap: 14px;
}
.moderation-row {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: 10px;
    padding: 16px 18px;
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.moderation-row-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 10px;
    font-size: 12px;
    color: var(--ink-3);
    padding-bottom: 8px;
    border-bottom: 1px dashed var(--line);
}
.moderation-row-head a {
    color: var(--ink-2);
    text-decoration: none;
    font-weight: 500;
}
.moderation-row-head a:hover { color: var(--ink); text-decoration: underline; }
.moderation-row-body {
    font-size: 14px;
    color: var(--ink);
    background: var(--ivory-2);
    padding: 10px 12px;
    border-radius: 6px;
    white-space: pre-wrap;
    line-height: 1.5;
}
.moderation-row-reason {
    font-size: 12px;
    color: var(--ink-3);
}
.moderation-row-link {
    color: var(--saffron-deep);
    text-decoration: none;
    font-weight: 500;
}
.moderation-row-link:hover { text-decoration: underline; }
.moderation-row-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    padding-top: 4px;
}
.moderation-row-actions--stacked {
    flex-direction: column;
    align-items: stretch;
}
.moderation-row-actions-buttons {
    display: flex;
    gap: 8px;
    justify-content: flex-end;
}
.moderation-row-blacklist {
    border: 1px solid var(--line);
    border-radius: 6px;
    padding: 8px 10px;
    background: var(--ivory-2);
    display: flex;
    flex-wrap: wrap;
    gap: 6px 14px;
    align-items: center;
}
.moderation-row-blacklist-legend {
    font-size: 11px;
    color: var(--ink-3);
    width: 100%;
    margin-bottom: 4px;
}
.moderation-row-blacklist label {
    font-size: 12px;
    color: var(--ink-2);
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

/* ===== Admin abuse transcript — /admin/abuse/{report}/transcript ===== */
.abuse-report-card {
    background: var(--paper);
    border: 1px solid var(--line);
    border-left: 3px solid var(--saffron-deep);
    border-radius: 10px;
    padding: 16px 18px;
    margin: 20px 0 18px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}
.abuse-report-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 12px 18px;
}
.abuse-report-grid a {
    color: var(--ink);
    text-decoration: none;
    font-weight: 500;
}
.abuse-report-grid a:hover { text-decoration: underline; }
.abuse-report-label {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--ink-3);
    margin-bottom: 2px;
}
.abuse-report-body {
    font-size: 14px;
    color: var(--ink);
    background: var(--ivory-2);
    padding: 10px 12px;
    border-radius: 6px;
    white-space: pre-wrap;
    line-height: 1.5;
}
.abuse-report-notes {
    font-size: 12px;
    color: var(--ink-3);
    padding-top: 6px;
    border-top: 1px dashed var(--line);
}

.transcript-stream {
    display: flex;
    flex-direction: column;
    gap: 14px;
    margin-top: 12px;
}
.transcript-meta {
    align-self: center;
    font-size: 11px;
    color: var(--ink-3);
    background: var(--ivory-2);
    padding: 6px 12px;
    border-radius: 999px;
    display: flex;
    gap: 8px;
    align-items: center;
}
.transcript-meta-time { color: var(--ink-4); }
.transcript-msg {
    max-width: 78%;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: 10px;
    padding: 10px 14px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.transcript-msg--reporter {
    align-self: flex-start;
    border-left: 3px solid var(--saffron-deep);
}
.transcript-msg--reported {
    align-self: flex-end;
    border-right: 3px solid var(--ink-3);
}
.transcript-msg-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    font-size: 11px;
    color: var(--ink-3);
}
.transcript-msg-meta strong { color: var(--ink-2); font-weight: 600; }
.transcript-msg-time { color: var(--ink-4); margin-left: auto; }
.transcript-msg-body {
    font-size: 14px;
    color: var(--ink);
    line-height: 1.5;
    white-space: pre-wrap;
    word-break: break-word;
}
.transcript-side-pill {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    padding: 1px 6px;
    border-radius: 999px;
    background: var(--ivory-2);
    color: var(--ink-3);
    font-weight: 500;
}
.transcript-side-pill--reporter {
    background: var(--saffron-soft);
    color: var(--saffron-deep);
}
.transcript-side-pill--reported {
    background: var(--ivory-2);
    color: var(--ink-2);
}

@media (max-width: 640px) {
    .transcript-msg { max-width: 92%; }
}

/* Global flash banner container — renders session('status') /
 * session('error') uniformly across every layouts.app page. Matches
 * the standard page-inner width so the banner aligns with the content
 * column underneath. */
.page-flash-container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 16px 20px 0;
}
.page-flash-container .page-flash { margin-bottom: 0; }
@media (max-width: 720px) {
    .page-flash-container { padding: 12px 14px 0; }
}

/* ─────────────────────────────────────────────────────────────────
   Phase 9 — Feed Algo Console (read-only inspector) at /admin/feed-algo
   ───────────────────────────────────────────────────────────── */
.admin-feed-algo-head { margin-bottom: 18px; }
.admin-card--feed-algo { margin-top: 16px; }
.admin-card--feed-algo .admin-card-title {
  display: flex; align-items: baseline; gap: 10px; margin-bottom: 12px;
}
.admin-card-sub { color: var(--ink-3); font-weight: 400; }

.admin-feed-algo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 14px;
  margin: 0;
}
.admin-feed-algo-grid dt {
  color: var(--ink-3);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin: 0 0 3px;
}
.admin-feed-algo-grid dd {
  margin: 0;
  font-size: 18px;
  font-weight: 600;
  color: var(--ink);
}
.admin-state-pill {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 11px;
  font-family: var(--mono);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  background: var(--ivory-2);
  color: var(--ink-2);
}
.admin-state-pill--sparse          { background: rgba(217, 52, 43, 0.10); color: #b04a1a; }
.admin-state-pill--regional        { background: rgba(200, 84, 31, 0.12); color: var(--saffron-deep, #b04a1a); }
.admin-state-pill--scoped_fallback { background: rgba(34, 197, 94, 0.12); color: #166534; }
.admin-state-pill--city_active     { background: rgba(34, 197, 94, 0.18); color: #14532d; }

.admin-feed-algo-histogram {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.admin-feed-algo-histogram li {
  display: grid;
  grid-template-columns: 110px 1fr 80px;
  align-items: center;
  gap: 10px;
}
.admin-feed-algo-bar {
  height: 14px;
  background: var(--ivory-2);
  border-radius: 4px;
  overflow: hidden;
}
.admin-feed-algo-bar-fill { height: 100%; background: var(--saffron, #c8541f); }
.admin-feed-algo-bar-count { text-align: right; }

.admin-feed-algo-flags { width: 100%; border-collapse: collapse; }
.admin-feed-algo-flags th,
.admin-feed-algo-flags td {
  padding: 6px 10px;
  border-bottom: 1px solid var(--line);
  text-align: left;
  font-size: 13px;
}
.admin-flag-pill {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 4px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.04em;
}
.admin-flag-pill--on  { background: rgba(34, 197, 94, 0.15); color: #166534; }
.admin-flag-pill--off { background: var(--ivory-2);          color: var(--ink-3); }

.admin-feed-algo-class {
  margin: 14px 0 4px;
  color: var(--ink-3);
  letter-spacing: 0.04em;
}
.admin-feed-algo-consts {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
}
.admin-feed-algo-consts th,
.admin-feed-algo-consts td {
  padding: 6px 10px;
  border-bottom: 1px solid var(--line);
  text-align: left;
  font-size: 13px;
  vertical-align: top;
}
.admin-feed-algo-consts th:first-child,
.admin-feed-algo-consts td:first-child { width: 280px; }
.admin-feed-algo-const-value pre {
  margin: 0;
  font-family: var(--mono);
  font-size: 12px;
  white-space: pre-wrap;
  word-break: break-word;
  background: var(--ivory-2);
  padding: 6px 8px;
  border-radius: 4px;
  max-height: 280px;
  overflow-y: auto;
}

.admin-feed-algo-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.admin-feed-algo-table th,
.admin-feed-algo-table td {
  padding: 6px 10px;
  border-bottom: 1px solid var(--line);
  text-align: left;
  vertical-align: top;
}
.admin-feed-algo-table th {
  color: var(--ink-3);
  font-weight: 500;
  letter-spacing: 0.02em;
}

.admin-feed-algo-userform {
  display: flex;
  align-items: end;
  gap: 8px;
  margin-bottom: 12px;
}
.admin-feed-algo-userform input { max-width: 160px; }

/* ─────────────────────────────────────────────────────────────────
   Phase 9.2 — Tune-algo writeable form panel
   ───────────────────────────────────────────────────────────── */
.admin-card--feed-algo-tune {
  border-left: 3px solid var(--saffron, #c8541f);
}
.admin-feed-algo-tuneform { margin-top: 8px; }
.admin-feed-algo-tune-group {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}
.admin-feed-algo-tune-group:first-of-type {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}
.admin-feed-algo-tune-group > h3 {
  margin: 0 0 4px;
  color: var(--ink-3);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.admin-feed-algo-tune-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 12px;
  margin-top: 10px;
}
.admin-feed-algo-tune-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.admin-feed-algo-tune-field .form-label {
  margin: 0;
}
.admin-feed-algo-tune-field input {
  font-family: var(--mono);
}
.admin-feed-algo-tune-field.has-error input {
  border-color: #b04a1a;
}
.admin-feed-algo-tune-meta {
  color: var(--ink-3);
}
.admin-feed-algo-tune-help {
  color: var(--ink-3);
  font-size: 11px;
}
.admin-feed-algo-tune-actions {
  margin-top: 16px;
}
.admin-feed-algo-tune-reset {
  margin-top: 8px;
}

/* ── Site-wide footer (partials/footer.blade.php) ──
   Lives on every layouts.app page. Six-column SEO link grid collapses
   to accordion on mobile. Bottom strip stays visible on all viewports.
   Bottom padding for authed mobile clears the fixed <x-mobile-bottom-nav>. */

.site-footer {
  background: var(--paper, var(--surface-2, #fafafa));
  border-top: 1px solid var(--line, var(--line-2));
  margin-top: 48px;
  padding: 36px 20px 24px;
  color: var(--ink-2);
  font-size: 13px;
}
.site-footer-inner {
  max-width: 1280px;
  margin: 0 auto;
}
.site-footer-tagline {
  margin-bottom: 28px;
  padding-bottom: 22px;
  border-bottom: 1px dotted var(--line);
}
.site-footer-tagline-en {
  display: block;
  font-size: 18px;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 4px;
}
.site-footer-tagline-sub {
  display: block;
  color: var(--ink-3);
  font-size: 13px;
}
.site-footer-grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 28px;
}
.site-footer-col {
  min-width: 0;
}
.site-footer-col-title {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin: 0 0 12px;
}
.site-footer-col-title a {
  color: inherit;
  text-decoration: none;
}
.site-footer-col-title a:hover {
  color: var(--saffron-deep, var(--ink));
  text-decoration: underline;
}
.site-footer-col-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 7px;
}
.site-footer-col-list a {
  color: var(--ink-2);
  text-decoration: none;
  font-size: 13px;
  line-height: 1.35;
}
.site-footer-col-list a:hover {
  color: var(--saffron-deep, var(--ink));
  text-decoration: underline;
}
.site-footer-soon {
  color: var(--ink-4);
  font-size: 13px;
  font-style: italic;
}

/* Bottom strip — NAP + legal + social. Always visible. */
.site-footer-strip {
  margin-top: 32px;
  padding-top: 20px;
  border-top: 1px dotted var(--line);
  display: flex;
  flex-direction: column;
  gap: 8px;
  color: var(--ink-3);
  font-size: 12px;
  line-height: 1.5;
}
.site-footer-nap a,
.site-footer-legal-line a,
.site-footer-social a {
  color: var(--ink-2);
  text-decoration: none;
}
.site-footer-nap a:hover,
.site-footer-legal-line a:hover,
.site-footer-social a:hover {
  text-decoration: underline;
}
.site-footer-social {
  display: flex;
  gap: 10px;
  align-items: center;
  flex-wrap: wrap;
}

/* Mobile: collapse six columns to two, then one.
   On the smallest screens add bottom padding for authed users so the
   <x-mobile-bottom-nav> (fixed bottom, ~64px tall) doesn't overlap
   the legal strip. */
@media (max-width: 1024px) {
  .site-footer-grid {
    grid-template-columns: repeat(3, 1fr);
    gap: 24px;
  }
}
@media (max-width: 720px) {
  .site-footer-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 20px;
  }
}
@media (max-width: 480px) {
  .site-footer-grid {
    grid-template-columns: 1fr;
  }
  .site-footer {
    padding-bottom: 88px;
  }
}
/* Mobile: NAP + social rows have inline " · " text separators between
   each piece (entity name / address / email / phone). At <=700px these
   wrap mid-sentence and put dots at line starts. Stack each piece on
   its own line and hide the " · " separators. Desktop renders the
   original one-line format with dots in place. */
@media (max-width: 700px) {
  .site-footer-strip { gap: 16px; }
  .site-footer-nap > * { display: block; margin: 0; }
  .site-footer-nap > * + * { margin-top: 4px; }
  .site-footer-nap__addr { color: var(--ink-3); line-height: 1.5; }
  .site-footer-sep { display: none; }
  .site-footer-social { gap: 14px; }
  .site-footer-legal-line { line-height: 1.55; }
}

/* ── .prose typography (about, privacy, terms, disclaimer, contact)
   Light touch — fixes the gaps left by browser defaults: tighter list
   spacing, distinct h3 sizing, predictable margins between sections.
   Existing legal pages already shipped fine on browser defaults; this
   only polishes, doesn't override. */
.prose h2 {
  margin: 36px 0 12px;
  font-size: 22px;
  line-height: 1.3;
  letter-spacing: -0.005em;
  color: var(--ink);
}
.prose h3 {
  margin: 24px 0 8px;
  font-size: 17px;
  line-height: 1.35;
  color: var(--ink);
  letter-spacing: -0.005em;
  font-weight: 600;
}
.prose p {
  line-height: 1.65;
  margin: 0 0 14px;
}
.prose ul,
.prose ol {
  margin: 0 0 18px;
  padding-left: 22px;
}
.prose li {
  line-height: 1.55;
  margin-bottom: 8px;
}
.prose li > p {
  margin: 0 0 6px;
}
.prose strong {
  color: var(--ink);
  font-weight: 600;
}
.prose a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.prose a:hover {
  color: var(--saffron-deep);
}

/* About page — lead paragraphs are slightly larger to set the tone
   above the audience rows. */
.about-lead {
  font-size: 16px;
  line-height: 1.6;
  color: var(--ink-2);
}

/* About page CTA — promoted inline-text links to chip-style affordances
   so each audience row has a clear next step. Sits on its own line via
   .about-cta-row so the chip doesn't get lost in surrounding paragraph
   text. */
.about-cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: 8px 0 18px;
}
.about-cta {
  display: inline-flex;
  align-items: center;
  padding: 8px 14px;
  background: var(--surface);
  border: 1px solid var(--line-2);
  border-radius: 6px;
  color: var(--ink) !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 500;
  letter-spacing: -0.005em;
  transition: background-color 0.12s, border-color 0.12s, transform 0.12s;
}
.about-cta:hover {
  background: var(--surface-2);
  border-color: var(--ink-4);
  transform: translateY(-1px);
}

/* About page — investor block container. Subtle tint + left border to
   mark this section as a longer-read zone for partners + investors,
   without partitioning it visually from the rest of the page. */
.about-investor-block {
  margin: 24px -16px 8px;
  padding: 4px 20px 16px;
  background: var(--surface-2);
  border-left: 3px solid var(--saffron-deep);
  border-radius: 4px;
}
.about-investor-block h2 {
  margin-top: 18px;
}
@media (max-width: 600px) {
  .about-investor-block {
    margin-left: -10px;
    margin-right: -10px;
    padding-left: 14px;
    padding-right: 14px;
  }
}

/* ──────────────────────────────────────────────────────────────────────
   SRP map view — 2026-05-28 (Google Maps mode toggle, v1)
   List ↔ Map switch on locality SRPs. List stays canonical + indexed;
   map view is noindex,follow + lazy-loaded SDK + one Map instance per
   page lifetime. v2 split-pane is a chrome-layer follow-up.
   ────────────────────────────────────────────────────────────────────── */

/* Visually-hidden but accessible to assistive tech. Lifted verbatim
   from the Tailwind sr-only recipe. Used by the map's pin list mirror. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Segmented mode control above the results card grid. */
.ps-mode-toggle {
  display: inline-flex;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--paper);
  overflow: hidden;
}
.ps-mode-toggle-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 14px;
  border: 0;
  background: transparent;
  font: inherit;
  font-size: 12px;
  color: var(--ink-2);
  cursor: pointer;
  border-radius: 999px;
}
.ps-mode-toggle-btn.is-active {
  background: var(--ink);
  color: var(--paper);
}
.ps-mode-toggle-btn:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

/* Map view container — fills the results column slot in single-column
   layout. min-height keeps the canvas usable even on small viewports.
   position:relative anchors the absolutely-positioned skeleton + toolbar. */
.srp-map {
  position: relative;
  width: 100%;
  min-height: 70vh;
  border: 1px solid var(--line);
  border-radius: 12px;
  overflow: hidden;
  background: var(--ivory-2, #f5f3ee);
}

/* The Google Maps canvas. Fills the .srp-map box; Google attaches its
   tiles + markers here on initMap(). tabindex=0 lets keyboard users
   land focus on the map region; the .sr-only pin list provides an
   accessible mirror for marker navigation. */
.srp-map-canvas {
  position: absolute;
  inset: 0;
}
.srp-map-canvas:focus-visible {
  outline: 3px solid var(--ink);
  outline-offset: -3px;
}

/* Skeleton — gradient + locality label until the Google idle event
   flips mapReady. Sits above the canvas (z-index) but is removed via
   x-show once the SDK reports ready. */
.srp-map-skeleton {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, var(--ivory-2, #f5f3ee), var(--paper, #fff));
}
.srp-map-skeleton-pulse {
  position: absolute;
  inset: 12% 18%;
  border: 1px dashed var(--line);
  border-radius: 24px;
  animation: srp-map-skeleton-pulse 1.6s ease-in-out infinite;
}
@keyframes srp-map-skeleton-pulse {
  0%, 100% { opacity: 0.35; }
  50% { opacity: 0.7; }
}
@media (prefers-reduced-motion: reduce) {
  .srp-map-skeleton-pulse { animation: none; }
}
.srp-map-skeleton-label {
  position: relative;
  z-index: 1;
  color: var(--ink-3);
  letter-spacing: 0.04em;
}

/* Toolbar — close button (left) + pin summary (right). Sits above
   the canvas with a subtle gradient bg so labels stay readable
   over tile content. */
.srp-map-toolbar {
  position: absolute;
  top: 0; left: 0; right: 0;
  z-index: 3;
  display: flex;
  justify-content: space-between;
  align-items: center;
  /* Top + side safe-area: in mobile map mode .srp-map is fixed inset:0,
     so the toolbar's top edge IS the physical viewport top — without the
     inset the Back button + summary pill render under the notch / Dynamic
     Island (and under the side notch in landscape). The base 12px stays
     as the minimum padding on non-notched devices. */
  padding: calc(12px + var(--inset-top))
           calc(12px + var(--inset-right))
           12px
           calc(12px + var(--inset-left));
  pointer-events: none; /* let map gestures through except on buttons */
  /* color-mix so dark-mode users get a paper-tinted fade instead of a
     bright white smear over the map tiles (same pattern as the bottom
     pill's Rule 7 gradient). */
  background: linear-gradient(
    180deg,
    color-mix(in oklab, var(--paper) 85%, transparent) 0%,
    color-mix(in oklab, var(--paper) 0%, transparent) 100%
  );
}
.srp-map-toolbar > * {
  pointer-events: auto;
}
.srp-map-close {
  /* 44px tap floor — this is the primary desktop exit and the secondary
     mobile exit; it was ~33px (6px pad + 13px font). */
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  padding: 8px 14px;
  font-size: 13px;
}
.srp-map-summary {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--ink-2);
}
.srp-map-summary-missing {
  color: var(--ink-3);
  font-size: 11px;
  padding-left: 8px;
  border-left: 1px dotted var(--line);
}

/* Zillow-class price-bubble markers (Phase 1).
   Custom HTML content for AdvancedMarkerElement. Each marker
   renders as a rounded badge with a CSS-drawn triangle tail
   pointing down at the lat/lng. Cluster pins (count + locality)
   are larger and use the dark/ink palette; individual listing
   pins (Phase 2 — coming) will be smaller and paper-white with
   ink text.

   Custom transform anchors the bubble so the tip of the tail
   sits at the pin coordinate (not the centre of the bubble),
   matching Zillow's visual semantics. */
.srp-map-bubble {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px 6px;
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  border-radius: 14px;
  box-shadow: 0 4px 10px rgba(15, 15, 15, 0.18), 0 1px 2px rgba(15, 15, 15, 0.12);
  cursor: pointer;
  position: relative;
  /* AdvancedMarkerElement's default anchor is bottom-centre, so the
     bubble's bottom edge sits at the lat/lng. translateY(-6px) lifts
     the bubble up by the tail height so the tail TIP (not its base)
     lands at the actual coordinate. Don't add translateX — the
     horizontal centering is already handled by the marker anchor. */
  transform: translateY(-6px);
  transition: transform 140ms ease-out, box-shadow 140ms ease-out;
}
.srp-map-bubble::after {
  content: '';
  position: absolute;
  left: 50%;
  bottom: -6px;
  transform: translateX(-50%);
  width: 0;
  height: 0;
  border-left: 7px solid transparent;
  border-right: 7px solid transparent;
}
.srp-map-bubble:hover,
.srp-map-bubble.is-highlighted {
  /* Bubble lifts + scales on hover or when the matching card is hovered.
     The OverlayView wrapper handles xy positioning so we don't need to
     translateY here — just scale + shadow + raise above neighbours. */
  transform: scale(1.08) !important;
  box-shadow: 0 12px 28px rgba(15, 15, 15, 0.35), 0 2px 4px rgba(15, 15, 15, 0.15) !important;
  z-index: 10;
  transition: transform 140ms ease-out, box-shadow 140ms ease-out;
}

/* Hover-sync card wrapper — wraps each result card when the SRP is
   map-eligible. The hover state lifts the card a few pixels and adds
   a stronger shadow so the user can see which card the highlighted
   pin corresponds to (and vice versa). */
.ps-result-card-wrap {
  position: relative;
  transition: transform 140ms ease-out, box-shadow 140ms ease-out;
  border-radius: 10px;
  margin: 0 -4px;
}
.ps-result-card-wrap.is-highlighted {
  transform: translateY(-2px);
  box-shadow: 0 8px 24px rgba(15, 15, 15, 0.12), 0 2px 4px rgba(15, 15, 15, 0.06);
}
@media (prefers-reduced-motion: reduce) {
  .ps-result-card-wrap,
  .srp-map-bubble {
    transition: none;
  }
  .srp-map-bubble:hover,
  .srp-map-bubble.is-highlighted {
    transform: none !important;
  }
}

/* Phase 2 — cluster InfoWindow mini-card stack.
   Rendered inside Google's InfoWindow shell (which has its own
   padding + close button). Keep the content compact: a header row,
   3-5 stacked mini-cards, and a "more →" footer link. */
.srp-mini-cards {
  max-width: 280px;
  /* min-width 200 (was 240): Google's InfoWindow chrome adds ~20-40px
     padding + a close-X, so on a 320px iPhone SE a 240px floor could force
     the window to crowd the viewport edges. 200px still fits the price +
     2-line title comfortably while leaving breathing room at 320px. */
  min-width: 200px;
  font: 13px/1.4 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  color: var(--ink);
}
.srp-mini-cards-head {
  font-weight: 600;
  padding: 4px 6px 8px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 6px;
  color: var(--ink-2);
}
.srp-mini-cards-empty {
  padding: 8px 6px;
  color: var(--ink-3);
  font-style: italic;
}
.srp-mini-card {
  display: block;
  padding: 8px 6px;
  border-radius: 6px;
  text-decoration: none;
  color: inherit;
  border-bottom: 1px dotted var(--line);
  transition: background 100ms ease-out;
}
.srp-mini-card:last-of-type {
  border-bottom: 0;
}
.srp-mini-card:hover {
  background: var(--ivory-2, rgba(0, 0, 0, 0.03));
}
.srp-mini-card-price {
  font-weight: 700;
  color: var(--ink);
  font-size: 14px;
}
.srp-mini-card-title {
  color: var(--ink-2);
  font-size: 12px;
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.srp-mini-card-sub {
  color: var(--ink-3);
  font-size: 11px;
  margin-top: 2px;
}
.srp-mini-cards-more {
  display: block;
  padding: 8px 6px;
  margin-top: 4px;
  text-align: center;
  color: var(--ink);
  font-size: 12px;
  font-weight: 600;
  border-top: 1px solid var(--line);
  text-decoration: none;
  background: var(--ivory-2, rgba(0, 0, 0, 0.04));
  border-radius: 0 0 6px 6px;
}
.srp-mini-cards-more:hover {
  background: var(--ivory, rgba(0, 0, 0, 0.08));
}

/* Cluster InfoWindow is rendered inside Google's `.gm-style-iw` shell,
   which paints a hardcoded light background regardless of our theme.
   In dark mode our --ink tokens flip to LIGHT colors (designed for
   dark backgrounds), so the mini-card text becomes white-on-white →
   invisible (reported 2026-06-12: "Fonts are not visible on dark mode"
   on the Ahmedabad SRP map cluster popup).

   Re-pin the local palette to light-mode values inside the mini-cards
   so contrast holds against Google's light InfoWindow chrome. Same
   pattern used by .ph-persist / .ph-why--dark / .ph-final-cta /
   .ph-problem at L22950-22965 for the homepage hero slabs. */
[data-theme="dark"] .srp-mini-cards {
  --ink:        oklch(0.22 0.015 60);
  --ink-2:      oklch(0.32 0.012 60);
  --ink-3:      oklch(0.44 0.010 60);
  --paper:      oklch(0.995 0.004 85);
  --ivory:      oklch(0.985 0.008 85);
  --ivory-2:    oklch(0.965 0.012 85);
  --line:       oklch(0.90 0.012 80);
}
@media (prefers-color-scheme: dark) {
  html:not([data-theme="light"]):not([data-theme="dark"]) .srp-mini-cards {
    --ink:      oklch(0.22 0.015 60);
    --ink-2:    oklch(0.32 0.012 60);
    --ink-3:    oklch(0.44 0.010 60);
    --paper:    oklch(0.995 0.004 85);
    --ivory:    oklch(0.985 0.008 85);
    --ivory-2:  oklch(0.965 0.012 85);
    --line:     oklch(0.90 0.012 80);
  }
}

/* Cluster pin — dark ink background, count + locality name. */
.srp-map-bubble--cluster {
  background: var(--ink, #111);
  color: var(--paper, #fff);
}
.srp-map-bubble--cluster::after {
  border-top: 7px solid var(--ink, #111);
}
.srp-map-bubble-count {
  font-weight: 700;
  font-size: 13px;
}
.srp-map-bubble-label {
  font-weight: 500;
  opacity: 0.85;
  font-size: 11px;
}

/* Individual listing pin — paper background, ink text. Phase 2
   populates these per listing once per-listing coords are
   reliable; current rendering treats them as fallback when a
   single listing somehow ends up emitted as a non-cluster pin. */
.srp-map-bubble--listing {
  background: var(--paper, #fff);
  color: var(--ink, #111);
  border: 1px solid var(--line, rgba(15, 15, 15, 0.12));
}
.srp-map-bubble--listing::after {
  border-top: 7px solid var(--paper, #fff);
  filter: drop-shadow(0 1px 0 var(--line, rgba(15, 15, 15, 0.12)));
}

@media (prefers-reduced-motion: reduce) {
  .srp-map-bubble {
    transition: none;
  }
}

/* No-JS / AI-crawler fallback. Visible only when JS doesn't run, so
   crawlers see a structured nudge to the canonical list view. */
.srp-map-noscript {
  position: absolute;
  inset: 0;
  z-index: 4;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  text-align: center;
  color: var(--ink-3);
  background: var(--paper);
}

@media (max-width: 1000px) {
  .srp-map {
    min-height: 80vh;
    border-radius: 8px;
  }
  .ps-mode-toggle-btn {
    padding: 6px 14px;
    font-size: 13px;
  }
}

/* ── Phase 5 #1 — PDP mobile redesign ─────────────────────────────
   Ported from /preview/pages/pdp-v2 after sign-off (2026-05-29). Per
   brief_phase5_pdp.md + ergonomics rubric D1-D17. Mobile-only — desktop
   PDP layout is preserved as-is. Scoped under @media (max-width: 700px)
   so the rules win source-order against the equivalent base .pl-* /
   .listing-hero / .pl-sticky-cta-btn rules earlier in the file. */
@media (max-width: 700px) {
  /* 1. Anchor sub-nav hidden on phone (decision #2). Sticky tab strip
     eats 44px below an already-tight navbar without payoff at phone
     scale; seekers scroll naturally. */
  .pl-anchor-nav { display: none; }

  /* 2. Single full-bleed hero photo with aspect 4/3 (decision #1).
     Hide secondary tiles; force the lead tile to fill the 1-col grid.
     The desktop 16/8 aspect is too wide for phone — 4/3 keeps the
     hero readable above the title without dominating the viewport. */
  .pl-hero-a .listing-hero,
  .pl-hero-b .listing-hero,
  .pl-hero-c .listing-hero {
    aspect-ratio: 4 / 3;
    grid-template-columns: 1fr;
    grid-template-rows: 1fr;
  }
  .listing-hero-tile--top,
  .listing-hero-tile--bottom { display: none; }
  .listing-hero-tile--lead { grid-column: 1; grid-row: 1; }

  /* 3. (removed — was a redundant "View all N photos →" pill that
     overlapped with the existing .listing-hero-overlay pills
     "View all photos / Floor plans / Video tour" from listing.blade.php
     lines 371-389. The existing overlay is mobile-friendly already.) */

  /* 4. Right rail (broker card / EMI / Save / Share) is NOT sticky on
     phone (decision #3). It already stacks in document flow below the
     gallery via the .pl-hero-a 1fr collapse at <=900px; explicitly
     unstick the rail-inner so position:sticky doesn't fire halfway
     down the scroll. */
  .pl-hero-rail-inner { position: static; top: auto; }

  /* 5. Title goes fluid per D5 (clamp, no breakpoint jump). */
  .pl-hero-title { font-size: clamp(20px, 5vw, 28px); line-height: 1.2; }

  /* 6. Trust pills >=22px per D16. Bumped from 4px 10px padding so
     verification badges meet the brand-quality floor. */
  .pl-trust-pill { min-height: 22px; padding: 5px 10px; }

  /* 7. Sticky CTA buttons: 32-36px (audit finding) -> 48px per D3.
     Horizontal layout (icon + label inline) reads cleaner than the
     stacked icon-above-label of the desktop sticky bar. */
  .pl-sticky-cta-btn {
    min-height: 48px;
    flex-direction: row;
    padding: 10px 14px;
    gap: 6px;
    font-size: 14px;
    font-weight: 600;
    border-radius: 10px;
  }
  .pl-sticky-cta-label {
    font-size: 14px;
    text-transform: none;
    letter-spacing: 0;
  }

  /* 8. Lead-modal touch-target floor (decision #5). Full lead-modal
     redesign is Phase 5 #7 (Alpine vs legacy consolidation); for now
     enforce 48px on chips + 44px on close per D3. */
  .pl-intent-chip { min-height: 48px; padding: 12px 14px; }
  .pl-otp-sheet-close { width: 44px; height: 44px; }

  /* 9. Force-wrap long unbreakable runs so they don't force the rail
     wider than the viewport. RERA IDs contain "/" separators with no
     spaces (PR/GJ/AHMEDABAD/DASKROI/Ahmedabad Municipal Corporation/
     MAA16047/271025/311230) which browsers don't break by default;
     overflow-wrap:anywhere lets them break at any character. The EMI
     badge is inline-flex with " · " separators that need to wrap onto
     a second line when the price is wide. The broker-foot privacy
     line is normal prose but needs an explicit break-word in case a
     long broker name shows up. min-width:0 on the rail containers
     allows their children to shrink below intrinsic content width
     (the classic flex/grid overflow fix). */
  .pl-hero-rail, .pl-hero-rail-inner { min-width: 0; max-width: 100%; }
  .pl-hero-rera { overflow-wrap: anywhere; word-break: break-word; line-height: 1.5; }
  .pl-emi-badge { flex-wrap: wrap; overflow-wrap: break-word; }
  .pl-broker-foot { overflow-wrap: break-word; }
}

/* ── Phase 5 #2 — SRP mobile redesign ─────────────────────────────
   Ported from /preview/pages/srp-v2 after sign-off (2026-05-29). Per
   brief_phase5_srp.md + ergonomics rubric D3, D5, D7, D16. Mobile-only —
   desktop SRP layout (260px sidebar property card + sticky map column at
   1000px+) is preserved as-is. All rules scoped under
   @media (max-width: 700px) so they win source-order against the
   base .ps-* / .ps-card-* rules earlier in the file. */
@media (max-width: 700px) {
  /* 1. Save heart — 32x32 (audit gap) -> 44x44 per D3. Top-right of
     photo, backdrop-blur dark circle so the heart reads on both light
     and dark photos. */
  .ps-card-save {
    width: 44px; height: 44px;
    top: 10px; right: 10px;
    background: rgba(20, 18, 16, 0.65);
    color: #fff;
    backdrop-filter: blur(6px);
  }
  .ps-card-save svg { width: 18px; height: 18px; }
  .ps-card-save:hover,
  .ps-card-save.is-saved {
    background: var(--saffron-deep, #b07d3c);
    color: #fff;
  }
  .ps-card-save.is-saved svg { fill: #fff; }

  /* 2. Contact button — was 11px font / ~22px tall, right-aligned.
     Now full-width 44px tall, 15px font, ink fill so it reads as the
     card's primary action (D3). */
  .ps-card-cta-row {
    justify-content: stretch;
    margin-top: 12px;
  }
  .ps-card-contact {
    flex: 1;
    width: 100%;
    margin-left: 0;
    justify-content: center;
    min-height: 44px;
    padding: 12px 16px;
    background: var(--ink);
    color: var(--paper);
    border-color: var(--ink);
    font-size: 15px;
    letter-spacing: 0;
    border-radius: 8px;
  }
  .ps-card-contact:hover {
    background: color-mix(in oklab, var(--ink) 88%, transparent);
    color: var(--paper);
    border-color: var(--ink);
  }

  /* 3. Title fluid clamp per D5 (was static 14px). */
  .ps-card-title { font-size: clamp(14px, 4vw, 16px); line-height: 1.3; }

  /* 4. Price fluid clamp per D5 (was static 20px which is overkill
     at 360-414px viewports). */
  .ps-card-price { font-size: clamp(15px, 4.5vw, 18px); }

  /* 5. Trust pills >=22px per D16. The base .ps-trust-pill is a
     compact pill; bump the height floor on mobile so verification
     badges meet the brand-quality minimum. */
  .ps-card-trust .ps-trust-pill,
  .ps-trust-pill {
    min-height: 22px;
    padding: 4px 10px;
  }

  /* 6. Filter chip 36px (existing mobile rule) -> 40px per brief. */
  .ps-filter-chip,
  .ps-filter-chip-select {
    min-height: 40px;
    padding: 10px 14px;
  }

  /* 7. (removed 2026-05-29 — the .ps-mobile-map-btn chip was replaced
     by the .ps-mode-toggle segmented control when the SRP map feature
     shipped. See audit_mobile_srp_map_addendum.md. Toggle-specific
     rules live at the end of this @media block.) */

  /* 8. Load-more button font bump (height stays at .btn 48px). */
  .ps-load-more .btn { font-size: 15px; min-height: 48px; }

  /* 9. Card body breathing — bump padding slightly so the new larger
     contact button has room above it. */
  .ps-card-body { padding: 14px 14px 16px; gap: 8px; }

  /* 10. Card photo count pill — make it slightly larger and more
     legible per the brief's "photo-count badge top-left" pattern.
     The existing rule places it at bottom-right; keep that position
     for backwards compat with desktop, just bump the font + padding. */
  .ps-card-photo-count {
    padding: 4px 10px;
    font-size: 11px;
    backdrop-filter: blur(4px);
  }

  /* 11. Results H1 — bump from 17px to fluid clamp(18, 5vw, 24)
     per D5. */
  .ps-results-h1 { font-size: clamp(18px, 5vw, 24px); }

  /* 12. Word-wrap safety net for long monospace runs (locality with
     long suffixes, RERA IDs in stat tiles, etc.) so card content
     never forces the card wider than viewport. */
  .ps-card { min-width: 0; }
  .ps-card-body, .ps-card-title, .ps-card-locality { overflow-wrap: break-word; }

  /* 13. Phase 5 #2 addendum 2026-05-29 — SRP map feature shipped
     after the original Phase 2 audit. The new .ps-mode-toggle
     segmented control (List | Map) sits in .ps-results-head. The
     base styling is 5px 14px padding / 12px font → ~28px tall, below
     the 44px floor (D3). The toggle is the seeker's only route
     between modes; missed taps drop them out of map mode unexpectedly.

     Bump tap target + stack the head row vertically so the toggle
     gets its own full-width row (cramped inline with the count
     text at 360-414px). The toggle becomes a 2-button segmented
     full-width control like the PDP's sticky CTA bar. */
  .ps-results-head {
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
  }
  .ps-mode-toggle {
    align-self: stretch;
    justify-content: stretch;
  }
  .ps-mode-toggle-btn {
    flex: 1;
    justify-content: center;
    min-height: 44px;
    padding: 10px 16px;
    font-size: 14px;
  }
}


/* ── Phase 5 #2.5 — SRP mobile hygiene batch (D1+D2+D3) ──────────
   Three small fixes for surfaces that shipped after Phase 5 #2 SRP.
   See plan_phase5_srp_v3_mobile.md for the full plan + sequencing. */
@media (max-width: 700px) {
  /* D1 — Hover-sync visual neutralized on mobile.
     The .ps-result-card-wrap @mouseenter/@mouseleave Alpine handlers
     don't fire on touch, so .is-highlighted (transform + shadow) only
     ever applied when a desktop browser pointer-emulated touch — a
     non-state. Drop the visual entirely on phone so future Alpine /
     JS changes don't introduce spurious card-jump artifacts. */
  .ps-result-card-wrap.is-highlighted {
    transform: none;
    box-shadow: none;
  }

  /* D2 — Smart-label density on mobile (.ps-card-smart-label-row).
     The pill (e.g., "Possession Ready", "Under OC") adds a 6th
     vertical zone to the 1-col mobile card. Tighten the row's gap to
     the price below, and cap visible labels at 1 (highest priority,
     presenter-ordered). Desktop unchanged. */
  .ps-card-smart-label-row {
    margin-bottom: 4px;
    gap: 0;
  }
  .ps-card-smart-label-row > .ps-card-smart-label:nth-child(n+2) {
    display: none;
  }

  /* D3 — Supply↔demand bridge stacks vertically on mobile.
     Desktop is row-flex (icon · count + message · CTA). At 360-430px
     that wraps mid-sentence with the CTA orphan-right. Stack the
     icon + body on row 1, drop the CTA to its own full-width 44px
     button row 2 — visually a tap-reliable affordance even though the
     whole <a> is the clickable target. */
  .srp-bridge {
    flex-wrap: wrap;
    padding: 14px;
    gap: 10px 12px;
    text-decoration: none;
  }
  .srp-bridge-body {
    flex: 1 1 0;
    min-width: 0;
    display: inline-flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 4px 8px;
  }
  .srp-bridge-cta {
    flex: 1 1 100%;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 10px 16px;
    background: var(--paper);
    border: 1px solid var(--ink);
    border-radius: 8px;
    color: var(--ink);
    font-weight: 600;
    font-size: 14px;
    margin-top: 2px;
  }
}

/* ── Phase 5 #2.5 follow-up — SRP tab consistency + map mode toggle
      visibility (D-feedback-1 + D-feedback-2). User reported:
      "Tab sizes are inconsistent" + "Map toggle placement disturbed".

      Standardize ALL tab-shaped affordances on the SRP top chrome to
      the 44px floor on mobile so peer tabs, mode toggle, lean-budget
      trigger, and the More-filters chip all share one vertical rhythm.
      Filter strip chips stay at 40px (scrollable density floor — they
      are not always-visible primary affordances). */
@media (max-width: 700px) {
  /* Peer tabs (Properties / Buyers looking) — were 12px 20px 14px
     padding + 14px font ≈ ~48px tall. Tighten to 44px exact so they
     match the mode toggle's height. Slight padding bump for
     comfortable thumb-tap area. */
  .ps-tab {
    padding: 11px 18px;
    min-height: 44px;
    font-size: 14px;
  }

  /* Lean-top budget dropdown trigger — 44px to match the 44px mode
     toggle / peer tabs. Horizontal padding only; height is set by the
     normalization rule above (height:44px + padding-top/bottom:0), so
     keeping vertical padding here would over-tall it past its siblings. */
  .ps-lean-budget-trigger {
    min-height: 44px;
    padding: 0 14px;
    font-size: 12px;   /* match the sibling chip-selects (Bedrooms/Possession) */
  }

  /* Map-mode toggle visibility (the second feedback).
     Default behavior at <=999px (line 10178): in map mode the entire
     .ps-split-results column gets display:none — which ALSO hides
     the .ps-results-head row containing the List/Map toggle. The
     user can only flip back via the small "Back to list" button in
     the map's toolbar.

     Mobile fix: keep .ps-split-results displayed in map mode but
     hide only the cards list inside. The head stays visible and
     gets sticky positioning so the toggle is always one tap away
     while the user pans the map. The count text (redundant with
     the map's own pin summary) hides. */
  .ps-split--map-active .ps-split-results {
    display: flex;
    flex-direction: column;
  }
  .ps-split--map-active .ps-results-list {
    display: none;
  }
  .ps-split--map-active .ps-results-head {
    position: sticky;
    top: calc(var(--inset-top) + 8px);
    z-index: 5;
    background: var(--paper);
    padding-top: 8px;
    padding-bottom: 8px;
    margin-bottom: 0;
    border-bottom: 1px solid var(--line);
  }
  .ps-split--map-active .ps-results-head > span:first-child {
    display: none;
  }
}

/* ── Phase 5 #2.5 D4 — AI Search mobile port (signed off 2026-05-29)
   Three pieces of mobile-only chrome:
     1. .ps-filter-chip--ai — saffron-emphasized chip variant; renders
        as the FIRST chip in the mobile filter strip (see
        _search-filters.blade.php). Hidden on desktop; the existing
        .search-engine-ai-pill in the search row covers that case.
     2. .ai-search-grip — visual drag handle at top of the bottom-
        sheet. CSS-only swipe-down affordance; real gesture handler
        is a follow-up in ai-search.js.
     3. .ai-search-close 36 -> 44 — bump close X to the tap floor on
        mobile (desktop centered-dialog keeps 36, matches sheet head
        density). */
.ps-filter-chip--ai { display: none; }
.ai-search-grip {
  display: block;
  width: 36px;
  height: 4px;
  background: var(--line-2, var(--line));
  border-radius: 2px;
  margin: -8px auto 14px;
}
@media (min-width: 640px) {
  /* Centered dialog at tablet+ — no swipe gesture, hide the grip. */
  .ai-search-grip { display: none; }
}
@media (max-width: 700px) {
  /* AI Search pill in the filter strip — saffron gradient matching
     the desktop .search-engine-ai-pill, chip-shaped (40px) so it
     visually belongs alongside the other filter chips. */
  .ps-filter-chip--ai {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 40px;
    padding: 8px 14px;
    background: linear-gradient(135deg,
        color-mix(in oklab, var(--saffron-soft, #fde7c4) 80%, var(--paper)) 0%,
        color-mix(in oklab, #d8c4f5 30%, var(--paper)) 100%);
    border: 1px solid var(--saffron-deep, #b07d3c);
    border-radius: 999px;
    font-size: 13px;
    font-weight: 600;
    color: var(--ink);
    cursor: pointer;
    white-space: nowrap;
    flex-shrink: 0;
    font-family: inherit;
    text-decoration: none;
  }
  /* Hide the search-row AI pill on mobile so it doesn't double-
     render with the filter-strip chip above. The search-row pill
     stays on desktop where the search row is fully visible. */
  .search-engine-ai-pill { display: none; }
  /* Bump close X to 44 floor — was 36 inside the sheet. */
  .ai-search-close {
    width: 44px;
    height: 44px;
    top: 8px;
    right: 8px;
  }
}

/* ── Phase 5 #2.5 D5 — Map full-screen on mobile (rewrite 2026-05-29
      based on Claude Code peer audit). Seven material fixes:

        1. Breakpoint 700px -> 999px to match the desktop split's own
           collapse breakpoint and close the 701-999 "no map" dead zone.

        2. .srp-map z-index 5 -> 50. Was BELOW navbar (z:20), filter
           strip (z:25), mobile-bottom-nav (z:30) so chrome occluded
           the map top + bottom. Bumped above sticky chrome, below
           modals (drawer 1200+).

        3. .mobile-bottom-nav explicitly hidden in map mode so the
           Compose FAB row doesn't cover the lower 64px of map.

        4. Top safe-area: max(60px, env(...)) (always 60px on iOS) →
           calc(60px + var(--inset-top)) — additive.

        5. min-height 100vh -> 100dvh so iOS Safari URL bar collapse
           doesn't push the Back-to-list pill off-screen.

        6. Belt-and-braces selectors: target both body[data-srp-mode=
           "map"] AND .ps-split--map-active. First needs srp-map.js
           hydration; second is server-rendered via Alpine :class on
           .ps-split. Either alone is enough; both means no half-
           applied layout if JS hydration is slow or ad-blocked.

        7. Bottom pill gradient: rgba white -> color-mix(in oklab,
           var(--paper)...) so dark mode users don't get a white
           smear at the bottom. */

/* Sticky-bottom "Back to list" pill — desktop hidden by default. */
.srp-map-bottom { display: none; }
.srp-map-back {
  width: 100%;
  min-height: 48px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  background: var(--ink);
  color: var(--paper);
  border: 0;
  border-radius: 999px;
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  box-shadow: 0 4px 16px rgba(0,0,0,0.18);
}

/* AI Search RESTORED on mobile (2026-06-02): the prior blanket
   `@media (max-width:999px){ .ps-filter-chip--ai{display:none!important} }`
   hid the SRP's AI chip on all mobile, leaving mobile users with no
   natural-language entry. The chip's show rule (@max-width:700px, above)
   now stands, so the AI chip is back as the first chip in the mobile SRP
   filter strip — matching the new mobile-home AI bar. (Map mode still
   hides it via the dedicated map-mode rule below, where the strip is
   minimized.) */

@media (max-width: 999px) {

  /* ─ Rule 0 — Scroll-lock the document behind the full-screen map.
        Toggled by srp-map.js _setScrollLock() (mobile only). The map is
        fixed inset:0, but the results document underneath stays in flow;
        without this the body scrolls behind the map on edge overscroll
        or a touch starting on the fixed filter strip — and corrupts the
        scrollY that _restoreScroll() reads on exit. overscroll-behavior
        kills the scroll-chaining bounce at the map edges too. */
  body.srp-map-scroll-locked {
    overflow: hidden !important;
    overscroll-behavior: none;
  }

  /* ─ Rule 1 — Map fills viewport, z-index above sticky chrome.
        Belt-and-braces: body-attr AND .ps-split--map-active. */
  body[data-srp-mode="map"] .srp-map,
  .ps-split--map-active .srp-map {
    position: fixed !important;
    inset: 0 !important;
    z-index: 50 !important;
    min-height: 100dvh;
    max-height: none;
    border-radius: 0;
  }

  /* ─ Rule 2 — Bottom-nav (Compose FAB row) hidden in map mode so
        it doesn't cover the lower 64px of the map. */
  body[data-srp-mode="map"] .mobile-bottom-nav,
  .ps-split--map-active ~ * .mobile-bottom-nav,
  .ps-split--map-active .mobile-bottom-nav {
    display: none !important;
  }

  /* ─ Rule 3 — Segmented List/Map toggle hidden in map mode.
        Redundant with bottom pill + map's own × close. */
  body[data-srp-mode="map"] .ps-results-head,
  .ps-split--map-active .ps-results-head {
    display: none !important;
  }

  /* ─ Rule 4 — Filter strip viewport-anchored. Fixed (not sticky —
        sticky needs scroll trigger which doesn't fire in map mode).
        Top math is additive: navbar height + notch inset.
        Z-index above the fixed map, below modals. */
  body[data-srp-mode="map"] .ps-filter-strip,
  .ps-split--map-active .ps-filter-strip {
    position: fixed !important;
    top: calc(60px + var(--inset-top)) !important;
    left: 0 !important;
    right: 0 !important;
    margin: 0 !important;
    z-index: 51 !important;
    background: var(--paper);
    /* Side padding clears the notch when the device is in landscape
       (notch moves to a side edge). 16px base on portrait. */
    padding: 8px calc(16px + var(--inset-right))
             8px calc(16px + var(--inset-left));
  }

  /* ─ Rule 5a — Slim the pure-display active filter tokens (locality /
        budget / BHK ×-chips). These are dense status+remove tokens, not
        primary controls, so 32px is acceptable to claw back map real
        estate. They keep a generous tap area via the ×-hit region. */
  body[data-srp-mode="map"] .ps-filter-chip.is-active,
  .ps-split--map-active .ps-filter-chip.is-active {
    min-height: 32px !important;
    padding: 6px 10px !important;
    font-size: 12px !important;
  }

  /* ─ Rule 5b — Native <select> wrappers (Transaction / Possession /
        Sort / category sub-axis) and the More-filters button stay at the
        44px tap floor. Rule 6 hides almost everything else in map mode,
        so these are nearly the ONLY interactive filters left — slimming
        them to 32px (the old behavior) made the map's primary controls
        the hardest to hit. Trim padding/font for density but hold 44px. */
  body[data-srp-mode="map"] .ps-filter-chip-select,
  body[data-srp-mode="map"] .ps-filter-chip--more,
  .ps-split--map-active .ps-filter-chip-select,
  .ps-split--map-active .ps-filter-chip--more {
    min-height: 44px !important;
    padding: 6px 10px !important;
    font-size: 12px !important; /* fs-input-allow — SRP map-mode strip, Phase 5 SRP shipped */
  }
  /* The wrapper is inline-flex/align-items:center, so a 44px wrapper
     would leave the native <select> floating at its ~30px intrinsic
     height with dead space around it. Stretch the inner select to fill
     the wrapper so the full 44px is the tap target. */
  body[data-srp-mode="map"] .ps-filter-chip-select-input,
  .ps-split--map-active .ps-filter-chip-select-input {
    align-self: stretch;
    display: inline-flex;
    align-items: center;
  }

  /* ─ Rule 6 — Strip shows ONLY active filters + dropdown triggers
        + More-filters. Hide non-active regular chips, AI Search pill,
        Sort wrapper (.ps-filter-meta is the form, not a chip). */
  body[data-srp-mode="map"] .ps-filter-chip:not(.is-active),
  body[data-srp-mode="map"] .ps-filter-chip--ai,
  body[data-srp-mode="map"] .ps-filter-meta,
  .ps-split--map-active .ps-filter-chip:not(.is-active),
  .ps-split--map-active .ps-filter-chip--ai,
  .ps-split--map-active .ps-filter-meta {
    display: none !important;
  }

  /* ─ Rule 7 — Sticky-bottom Back-to-list pill inside .srp-map.
        Position: absolute anchors to the fixed map's bottom edge.
        Gradient uses color-mix so dark mode gets a paper-tinted
        fade instead of a bright white smear (same pattern
        .mobile-bottom-nav uses). */
  .srp-map-bottom {
    display: flex;
    position: absolute;
    left: 0; right: 0; bottom: 0;
    z-index: 52;
    /* Bottom honors the home indicator; left/right clear the side notch
       in landscape so the full-width pill doesn't tuck under it. */
    padding: 12px calc(16px + var(--inset-right))
             max(12px, var(--inset-bottom))
             calc(16px + var(--inset-left));
    background: linear-gradient(
      0deg,
      color-mix(in oklab, var(--paper) 92%, transparent) 0%,
      color-mix(in oklab, var(--paper) 0%, transparent) 100%
    );
    pointer-events: none;
  }
  .srp-map-bottom > * { pointer-events: auto; }

  /* ─ Rule 8 — Toolbar (top-left Back + pin summary) sizing fix.
        Reported from a live prod screenshot (Ahmedabad map mode): the
        toolbar text rendered at the inherited 16px body size because
        .srp-map-summary's `.small` class is NOT a global font-size
        utility — so "33 listings +2 without map location" wrapped to
        three lines and "← Back to list" to two, and both pills grew
        DOWNWARD past y:60 into the fixed filter strip (collision).

        Fix has three parts:
          a) Hide the redundant top-left Back button on mobile. The
             always-present bottom "← Back to list view" pill (Rule 7)
             is the canonical thumb-reachable exit here; two Back
             affordances stacked against the strip is what crowded the
             top. Desktop keeps the toolbar button (this is ≤999px only).
          b) Give the summary an explicit small font + nowrap so it
             stays a single ~28px line that clears the strip.
          c) Cap the "+N without map location" width with an ellipsis so
             a large missing-count can't blow the pill back out to full
             width and re-collide. */
  body[data-srp-mode="map"] .srp-map-close,
  .ps-split--map-active .srp-map-close {
    display: none !important;
  }
  body[data-srp-mode="map"] .srp-map-toolbar,
  .ps-split--map-active .srp-map-toolbar {
    /* Only the summary remains — right-align it and let the row be as
       short as the single line so it never reaches the strip at 60px. */
    justify-content: flex-end;
  }
  body[data-srp-mode="map"] .srp-map-summary,
  .ps-split--map-active .srp-map-summary {
    font-size: 12px;
    line-height: 1.3;
    white-space: nowrap;
    max-width: calc(100vw - 32px);
    overflow: hidden;
  }
  body[data-srp-mode="map"] .srp-map-summary-missing,
  .ps-split--map-active .srp-map-summary-missing {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
  }
}

/* ════════════════════════════════════════════════════════════════════
   HOME v4 sections — Persistent Profile + Sample Matches.

   Migrated verbatim from the inline <style> blocks in
   _home-v4-persistent-profile.blade.php + _home-v4-sample-matches.blade.php
   (the Phase-2 audit's flagged inline-style anti-pattern). Behaviour is
   identical; only the mobile section padding was trimmed (72px→52px on
   .ph-persist, 4.5rem→3rem on .ph-v4-matches) to reduce phone scroll.
   Tokens (--saffron / --fs-* / --cream / --charcoal / --terracotta etc.)
   resolve via tokens.css, now linked directly in the layout <head> before
   app.css (see the header comment at the top of this file).
   ════════════════════════════════════════════════════════════════════ */

/* ── Persistent Profile ───────────────────────────────────────────── */
.ph-persist {
  background: var(--charcoal);
  color: var(--cream);
  padding: 7.5rem 1.5rem;
  position: relative;
  overflow: hidden;
  border-radius: 18px;
}
@media (max-width: 880px) {
  .ph-persist { border-radius: 20px; }
}
.ph-persist::before {
  content: "";
  position: absolute;
  top: 0; right: 0;
  width: 600px;
  height: 600px;
  background: radial-gradient(circle, oklch(0.55 0.14 35 / 0.22), transparent 60%);
  transform: translate(30%, -20%);
  pointer-events: none;
}
.ph-persist-inner {
  max-width: 1180px;
  margin: 0 auto;
  position: relative;
  z-index: 2;
}
.ph-persist-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 5rem;
  align-items: center;
}
@media (max-width: 980px) {
  /* Mobile: 4.5rem→3.25rem (52px) top/bottom padding to reduce scroll. */
  .ph-persist { padding: 3.25rem 1.25rem; }
  .ph-persist-grid { grid-template-columns: 1fr; gap: 3rem; }
}
.ph-persist-eyebrow {
  font-size: var(--fs-xs);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--saffron);
  font-weight: 700;
  margin: 0 0 1.5rem;
  display: flex;
  align-items: center;
  gap: 0.75rem;
}
.ph-persist-eyebrow::before {
  content: "";
  width: 1.8rem;
  height: 2px;
  background: var(--saffron);
}
.ph-persist-title {
  font-size: clamp(2rem, 4.6vw, 3.4rem);
  line-height: 1.08;
  margin: 0 0 1rem;
  font-weight: 300;
  letter-spacing: -0.025em;
  color: var(--cream);
}
.ph-persist-title em {
  font-style: italic;
  color: var(--saffron);
  font-weight: 400;
}
.ph-persist-sub {
  font-size: var(--fs-md);
  color: oklch(0.97 0.022 80 / 0.85);
  margin: 0 0 1.75rem;
  font-weight: 300;
}
.ph-persist-body {
  font-size: var(--fs-base);
  line-height: var(--lh-body);
  color: oklch(0.97 0.022 80 / 0.88);
  margin: 0 0 1rem;
}
.ph-persist-vs {
  margin-top: 2rem;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1px;
  background: oklch(0.97 0.022 80 / 0.12);
  border-radius: 14px;
  overflow: hidden;
  border: 1px solid oklch(0.97 0.022 80 / 0.12);
}
@media (max-width: 540px) {
  .ph-persist-vs { grid-template-columns: 1fr; }
}
.ph-persist-vs-cell {
  background: oklch(0.18 0.010 60 / 0.50);
  padding: 1.4rem;
}
.ph-persist-vs-label {
  font-size: var(--fs-xs);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: oklch(0.97 0.022 80 / 0.72);
  margin: 0 0 0.6rem;
  font-weight: 700;
}
.ph-persist-vs-text {
  font-size: var(--fs-base);
  line-height: 1.4;
  color: var(--cream);
}
.ph-persist-vs-cell--ours .ph-persist-vs-label { color: var(--saffron); }
.ph-persist-vs-cell--ours .ph-persist-vs-text {
  font-style: normal;
  font-weight: 500;
  font-family: var(--sans);
}
.ph-persist-viz { padding: 1rem 0; }
.ph-persist-timeline {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
}
.ph-persist-tl-item {
  display: flex;
  gap: 1.1rem;
  align-items: flex-start;
  padding: 1.1rem 1.25rem;
  background: oklch(0.97 0.022 80 / 0.06);
  border: 1px solid oklch(0.97 0.022 80 / 0.12);
  border-radius: 14px;
  opacity: 0;
  transform: translateY(14px);
  transition:
    opacity 520ms cubic-bezier(0.2, 0.7, 0.2, 1),
    transform 520ms cubic-bezier(0.2, 0.7, 0.2, 1);
}
.ph-persist-timeline.is-visible .ph-persist-tl-item {
  opacity: 1;
  transform: translateY(0);
}
.ph-persist-timeline.is-visible .ph-persist-tl-item:nth-child(1) { transition-delay:   0ms; }
.ph-persist-timeline.is-visible .ph-persist-tl-item:nth-child(2) { transition-delay: 220ms; }
.ph-persist-timeline.is-visible .ph-persist-tl-item:nth-child(3) { transition-delay: 440ms; }
.ph-persist-timeline.is-visible .ph-persist-tl-item:nth-child(4) { transition-delay: 720ms; }
.ph-persist-tl-day {
  transform: translateX(-6px);
  transition: transform 520ms cubic-bezier(0.2, 0.7, 0.2, 1);
}
.ph-persist-timeline.is-visible .ph-persist-tl-item:nth-child(1) .ph-persist-tl-day { transition-delay:  60ms; }
.ph-persist-timeline.is-visible .ph-persist-tl-item:nth-child(2) .ph-persist-tl-day { transition-delay: 280ms; }
.ph-persist-timeline.is-visible .ph-persist-tl-item:nth-child(3) .ph-persist-tl-day { transition-delay: 500ms; }
.ph-persist-timeline.is-visible .ph-persist-tl-item:nth-child(4) .ph-persist-tl-day { transition-delay: 780ms; }
.ph-persist-timeline.is-visible .ph-persist-tl-item .ph-persist-tl-day { transform: translateX(0); }
.ph-persist-tl-item--matched {
  background: linear-gradient(135deg, oklch(0.55 0.14 35 / 0.28), oklch(0.68 0.16 55 / 0.12));
  border-color: oklch(0.65 0.13 50 / 0.5);
}
.ph-persist-timeline.is-visible .ph-persist-tl-item--matched {
  animation: roi-persist-match-glow 1600ms ease-out 920ms 1;
}
@keyframes roi-persist-match-glow {
  0%   { box-shadow: 0 0 0 0 oklch(0.65 0.13 50 / 0); }
  40%  { box-shadow: 0 0 0 14px oklch(0.65 0.13 50 / 0.18); }
  100% { box-shadow: 0 0 0 22px oklch(0.65 0.13 50 / 0); }
}
@media (prefers-reduced-motion: reduce) {
  .ph-persist-tl-item,
  .ph-persist-tl-day {
    opacity: 1;
    transform: none;
    transition: none;
  }
  .ph-persist-timeline.is-visible .ph-persist-tl-item--matched {
    animation: none;
  }
}
.ph-persist-tl-day {
  font-size: var(--fs-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--saffron);
  width: 4rem;
  flex-shrink: 0;
  padding-top: 0.15rem;
  font-weight: 600;
}
.ph-persist-tl-content { flex: 1; }
.ph-persist-tl-title {
  font-size: var(--fs-sm);
  color: var(--cream);
  margin-bottom: 0.2rem;
  font-weight: 600;
}
.ph-persist-tl-sub {
  font-size: var(--fs-xs);
  color: oklch(0.97 0.022 80 / 0.72);
  font-weight: 400;
}
.ph-persist-tl-item--matched .ph-persist-tl-title {
  font-size: var(--fs-md);
  font-weight: 500;
}
.ph-persist-tl-item--matched .ph-persist-tl-title em {
  font-style: italic;
  color: var(--saffron);
}

/* ── Sample Matches ───────────────────────────────────────────────── */
.ph-v4-matches {
  padding: 7rem 1.5rem;
  background: var(--ivory);
}
.ph-v4-matches-inner { max-width: 1180px; margin: 0 auto; }
.ph-v4-matches-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  margin-bottom: 3rem;
  gap: 2rem;
}
@media (max-width: 720px) {
  /* Mobile: 4.5rem→3rem top/bottom padding to reduce scroll. */
  .ph-v4-matches { padding: 3rem 1.25rem; }
  .ph-v4-matches-head { flex-direction: column; align-items: flex-start; }
}
.ph-v4-matches-eyebrow {
  font-size: var(--fs-xs);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink);
  font-weight: 700;
  margin: 0 0 1.25rem;
  display: flex;
  align-items: center;
  gap: 0.75rem;
}
.ph-v4-matches-eyebrow::before {
  content: "";
  width: 1.8rem;
  height: 2px;
  background: var(--terracotta);
}
.ph-v4-matches-title {
  font-size: clamp(1.8rem, 4.4vw, 2.8rem);
  line-height: 1.05;
  letter-spacing: -0.025em;
  color: var(--ink);
  font-weight: 300;
  margin: 0;
}
.ph-v4-matches-title em {
  font-style: italic;
  color: var(--terracotta-deep);
  font-weight: 400;
}
.ph-v4-matches-cta {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
  padding: 0.75rem 1.25rem;
  border: 1px solid var(--line-2);
  border-radius: 999px;
  background: var(--paper);
  white-space: nowrap;
}
.ph-v4-matches-cta:hover { color: var(--terracotta-deep); border-color: var(--terracotta); }
.ph-v4-matches-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.75rem;
}
@media (max-width: 980px) { .ph-v4-matches-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px) { .ph-v4-matches-grid { grid-template-columns: 1fr; } }
.ph-v4-match-card {
  background: var(--paper);
  border-radius: 18px;
  overflow: hidden;
  border: 1px solid var(--line);
  transition: transform 200ms ease, box-shadow 200ms ease, border-color 200ms ease;
  position: relative;
}
.ph-v4-match-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 24px 44px -18px oklch(0.22 0.012 60 / 0.18);
  border-color: var(--line-2);
}
.ph-v4-match-image {
  aspect-ratio: 4 / 3;
  background: linear-gradient(135deg, var(--terracotta), var(--terracotta-deep));
  position: relative;
  overflow: hidden;
}
.ph-v4-match-image--moss {
  background: linear-gradient(135deg, var(--moss), oklch(0.30 0.07 145));
}
.ph-v4-match-image--saffron {
  background: linear-gradient(135deg, var(--saffron), oklch(0.48 0.17 48));
}
.ph-v4-match-image svg {
  position: absolute;
  bottom: 1.1rem;
  left: 1.1rem;
  width: 80px;
  height: auto;
  opacity: 0.7;
}
.ph-v4-match-score {
  position: absolute;
  top: 1rem;
  right: 1rem;
  background: var(--cream);
  color: var(--ink);
  padding: 0.45rem 0.85rem;
  border-radius: 999px;
  font-size: var(--fs-sm);
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 0.35rem;
  box-shadow: 0 6px 14px -3px oklch(0.22 0.012 60 / 0.24);
}
.ph-v4-match-score-star { color: var(--terracotta); font-size: 0.85em; }
.ph-v4-match-body { padding: 1.4rem 1.4rem 1.5rem; }
.ph-v4-match-locality {
  font-size: var(--fs-xs);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink);
  margin: 0 0 0.6rem;
  font-weight: 700;
}
.ph-v4-match-title {
  font-size: var(--fs-lg);
  line-height: 1.2;
  color: var(--ink);
  margin: 0 0 0.9rem;
  font-weight: 500;
  letter-spacing: -0.015em;
}
.ph-v4-match-specs {
  display: flex;
  gap: 0.85rem;
  flex-wrap: wrap;
  font-size: var(--fs-sm);
  color: var(--ink-2);
  margin-bottom: 1.1rem;
  padding-bottom: 1.1rem;
  border-bottom: 1px solid var(--line);
  font-weight: 500;
}
.ph-v4-match-sep { color: var(--ink-4); }
.ph-v4-match-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.ph-v4-match-price {
  font-size: var(--fs-lg);
  font-weight: 600;
  color: var(--ink);
  letter-spacing: -0.01em;
}
.ph-v4-match-price small {
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--ink-3);
  font-style: italic;
  margin-left: 0.1rem;
}
.ph-v4-match-broker {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  font-size: var(--fs-sm);
  color: var(--ink-2);
  font-weight: 600;
}
.ph-v4-match-mark {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  color: var(--paper);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 10px;
  font-weight: 700;
}
.ph-v4-match-mark--roi { background: var(--moss); }
.ph-v4-match-mark--rera { background: var(--moss); }
.ph-v4-match-mark--owner { background: var(--terracotta); }

/* ════════════════════════════════════════════════════════════════════
   BELOW-HERO MOBILE HYGIENE (Phase 5 home, section-by-section)

   Direct-ship hygiene (not a redesign), from the below-hero audit:
   trim heavy mobile padding that eats scroll, fix the demand-carousel
   edge-bleed on narrow phones, and bump sub-44px tap targets on the
   <details> summaries + secondary CTAs to the D3 floor. Desktop is
   untouched (all @max-width). FAQ summary 48px floor already shipped in
   the earlier HOME LEAN block. */
@media (max-width: 700px) {
  /* Problem ("why ROI exists") — trim 64px → 40px top/bottom (the 880px
     rule kept 64px down to phones; this is the true-mobile reduction). */
  .ph-problem { padding: 40px 18px; }

  /* Final CTA — 44px → 28px top/bottom (88px total wasted a chunk of the
     viewport on a CTA), and shrink the serif h2 so it doesn't wrap hard. */
  .ph-final-cta { padding: 28px 18px; }
  .ph-final-cta-h2 { font-size: 26px; }

  /* Demand carousel — the -22px edge-bleed (desktop gutter alignment)
     overshoots on a 390px phone, pushing edge cards off-screen. Pull the
     bleed in to the mobile page gutter (16px) so cards sit inside the
     viewport and scroll cleanly. */
  .ph-demand-scroll {
    margin: 0 -16px;
    padding-left: 16px;
    padding-right: 16px;
  }

  /* Broker tier "+ N more features" <details> summary — 4px pad (~16px
     tall) → 44px tap floor. */
  .ph-broker-tier-more > summary {
    min-height: 44px;
    padding: 12px 0;
    display: inline-flex;
    align-items: center;
  }

  /* Owners/Buyers secondary CTAs ("Or, talk to a broker first →") — the
     partial's inline 4px padding is ~16px tall; bump to the 44px floor.
     Double-class for specificity over the partial's inline <style>. */
  .ph-owner-buyer-cta.ph-owner-buyer-cta-secondary,
  .ph-owner-buyer-cta-secondary {
    min-height: 44px;
    padding: 10px 0;
    display: inline-flex;
    align-items: center;
  }

  /* Section head — base is flex row + justify-between [title | control].
     On mobile that crushed the title into a one-word-per-line column AND
     pushed the side control (e.g. "See all 13 buyers") off the right edge
     (reported on the buyer-demand band in Noida). Stack to a column so the
     title gets full width and the control drops below it. Covers every
     .ph-section-head user (demand band, etc.); short-title sections that
     already looked fine are unaffected (column of one line). */
  .ph-section-head {
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
  }
  .ph-demand-head-controls .ph-section-cta { white-space: nowrap; }

  /* Peer tabs ("I'm looking for property / buyers") — two flex:1 tabs
     shared a row, so the 4-word label wrapped one-word-per-line in each
     ~half-width pill. Stack them full-width on mobile so each label sits
     on one line (icon + count inline). */
  .ph-hero-tabs { flex-direction: column; }
  .ph-hero-tab {
    flex: none;                 /* override the earlier flex:1 (row layout) */
    width: 100%;
    justify-content: flex-start;
  }
  .ph-hero-tab-label { white-space: nowrap; }
}

/* ============================================================
   Segmented Pill-Nav (.spnav-*) — the audience-tuned header rail
   that replaces the legacy flat .navbar-tabs (see partials/_nav-pills).
   A curated rail of FOUR pills + More▾, set in a soft inset track.
   Active pill carries the saffron underline + an Instrument-Serif
   italic label accent so the brand voice lives in the nav itself.

   Uses the global --ink/--saffron/--ivory tokens, so it inherits the
   dark-theme cascade automatically. Scoped under .spnav — it does NOT
   touch the live .navtab rules until Phase B promotion.
   ============================================================ */
.spnav {
  display: flex;
  align-items: center;
  gap: 2px;
  margin-left: 18px;
  padding: 3px;
  border-radius: 12px;
  background: color-mix(in oklab, var(--ink) 4%, transparent);
  border: 1px solid color-mix(in oklab, var(--ink) 7%, transparent);
}
.spnav-pill {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 36px;
  padding: 0 14px;
  border-radius: 8px;
  font-size: 13px;
  font-weight: 600;
  line-height: 1;
  color: var(--ink-2);
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  border: 0;
  background: transparent;
  font-family: inherit;
  transition: color .14s ease, background .14s ease;
}
.spnav-pill:hover { color: var(--ink); background: color-mix(in oklab, var(--ink) 6%, transparent); }
.spnav-pill--active {
  color: var(--ink);
  background: color-mix(in oklab, var(--saffron) 14%, transparent);
}
/* Saffron underline on the active pill — the signature accent. */
.spnav-pill--active::after {
  content: "";
  position: absolute;
  left: 14px;
  right: 14px;
  bottom: 3px;
  height: 2px;
  border-radius: 2px;
  background: var(--saffron);
}
/* Instrument-Serif italic accent on the active pill's label. */
.spnav-pill--active .spnav-pill-label,
.spnav-pill--active:not(:has(.spnav-pill-label)) {
  font-family: 'Instrument Serif', Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: 16px;
  color: var(--saffron-deep, #b07d3c);
}
.spnav-badge {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 500;
  padding: 2px 6px;
  border-radius: 999px;
  line-height: 1.2;
  letter-spacing: 0.02em;
  background: var(--ivory-2);
  color: var(--ink-3);
}
.spnav-pill--active .spnav-badge { background: var(--paper); color: var(--ink-2); }
.spnav-badge--hot { background: var(--saffron); color: var(--ink); font-weight: 700; }

/* More▾ overflow — native <details>, mirrors the legacy .navtab-more. */
.spnav-more { position: relative; }
.spnav-more > summary { list-style: none; cursor: pointer; user-select: none; }
.spnav-more > summary::-webkit-details-marker { display: none; }
.spnav-more-caret { font-size: 10px; color: var(--ink-3); margin-left: 4px; }
.spnav-more[open] > .spnav-more-summary {
  color: var(--ink);
  background: color-mix(in oklab, var(--ink) 6%, transparent);
}
.spnav-more-menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 20;
  min-width: 210px;
  padding: 6px;
  background: var(--paper);
  border: 1px solid color-mix(in oklab, var(--ink) 12%, transparent);
  border-radius: 10px;
  box-shadow: 0 6px 18px rgba(0,0,0,0.08);
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.spnav-more-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 8px 12px;
  border-radius: 6px;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-2);
  text-decoration: none;
}
.spnav-more-item:hover,
.spnav-more-item.is-active {
  color: var(--ink);
  background: color-mix(in oklab, var(--saffron) 12%, transparent);
}

/* Mobile — the rail is a <nav> inside .navbar-inner, so it is already
   hidden at <=800px by the global `.navbar-inner nav { display:none
   !important }` rule (the same boundary at which the bottom-nav appears,
   so there is no dead zone). Navigation on small screens is owned by the
   <x-mobile-bottom-nav> (authed) + the guest overflow "···" menu. No
   separate hide rule needed for .spnav — documented here so the cascade
   isn't a mystery. */

/* ✨ AI Search trigger — right-cluster icon button, sized as a sibling of
   the notification bell / city selector. Dispatches the global
   `open-ai-search` event (see <x-ai-search-sheet>). This is NOT a <nav>,
   so the global mobile nav-hide does NOT apply — it needs its own hide
   below. Mobile reaches AI search via the SRP search bar. */
.nav-ai-trigger {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  flex: none;
  border-radius: 9px;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--saffron-deep, #b07d3c);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}
.nav-ai-trigger:hover {
  background: color-mix(in oklab, var(--saffron) 12%, transparent);
  border-color: color-mix(in oklab, var(--saffron) 40%, transparent);
  transform: translateY(-0.5px);
}
/* 800px to match the navbar collapse — folds away with the rest of the
   guest/right cluster so there is no 701-800 overflow band. */
@media (max-width: 800px) {
  .nav-ai-trigger { display: none; }
}

/* ── Public company page (/companies/{slug}) ──────────────────────────
   Harmonised with .broker-card + design tokens. Office is presented as a
   ranking asset: hero, stats, styled member grid. Mobile-aware. */
.company-page { max-width: 920px; }

.company-hero {
  display: flex;
  align-items: center;
  gap: 18px;
  margin: 8px 0 18px;
}
.company-hero__logo {
  width: 96px;
  height: 96px;
  flex-shrink: 0;
  border-radius: 16px;
  border: 1px solid var(--line);
  background: var(--paper-2);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.company-hero__logo img { width: 100%; height: 100%; object-fit: contain; padding: 8px; }
.company-hero__logo-fallback {
  font-family: var(--serif, Georgia, serif);
  font-size: 44px;
  color: var(--ink-3);
}
.company-hero__body { min-width: 0; }
.company-hero__eyebrow {
  font-size: var(--fs-xs, 12px);
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.company-hero__name {
  font-family: var(--serif, Georgia, serif);
  font-size: clamp(1.6rem, 5vw, 2.4rem);
  line-height: 1.1;
  margin: 4px 0 6px;
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.company-hero__meta { color: var(--ink-3); display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.company-hero__meta a { color: var(--ink-2); text-decoration: none; }
.company-hero__meta a:hover { text-decoration: underline; }

.company-banner {
  border-radius: 12px;
  padding: 12px 16px;
  font-size: var(--fs-sm, 14px);
  margin-bottom: 18px;
  border: 1px solid var(--line);
}
.company-banner--verified {
  background: color-mix(in oklch, var(--green) 12%, var(--paper));
  border-color: color-mix(in oklch, var(--green) 35%, var(--line));
  color: var(--ink);
}
.company-banner--dormant { background: var(--paper-2); color: var(--ink-2); }

.company-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 24px;
}
.company-stat {
  flex: 1 1 120px;
  min-width: 110px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--paper);
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.company-stat__num {
  font-family: var(--serif, Georgia, serif);
  font-size: clamp(1.4rem, 4vw, 1.9rem);
  line-height: 1;
  color: var(--ink);
}
.company-stat__label { font-size: var(--fs-xs, 12px); color: var(--ink-3); text-transform: uppercase; letter-spacing: 0.03em; }

.company-section-title {
  font-family: var(--serif, Georgia, serif);
  font-size: clamp(1.2rem, 3vw, 1.5rem);
  margin: 0 0 12px;
}
.company-about { margin-bottom: 28px; }
.company-about__body { color: var(--ink-2); line-height: 1.6; font-size: var(--fs-base, 15px); }

.company-members__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 12px;
}
.company-member {
  display: flex;
  gap: 12px;
  align-items: center;
  padding: 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--paper);
  text-decoration: none;
  color: inherit;
  transition: border-color 0.15s ease, transform 0.15s ease;
}
.company-member:hover { border-color: color-mix(in oklch, var(--accent) 40%, var(--line)); transform: translateY(-1px); }
.company-member__avatar {
  width: 44px;
  height: 44px;
  flex-shrink: 0;
  border-radius: 50%;
  overflow: hidden;
  background: var(--paper-2);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.06);
}
.company-member__avatar img { width: 100%; height: 100%; object-fit: cover; }
.company-member__avatar span { font-family: var(--serif, Georgia, serif); font-size: 18px; color: var(--ink-3); }
.company-member__body { min-width: 0; }
.company-member__name {
  font-weight: 600;
  font-size: var(--fs-sm, 14px);
  color: var(--ink);
  display: flex;
  align-items: center;
  gap: 6px;
}
.company-member__meta { font-size: var(--fs-xs, 12px); color: var(--ink-3); margin-top: 2px; }
.company-member__stat { font-size: 11px; color: var(--ink-4); margin-top: 2px; }

@media (max-width: 560px) {
  .company-hero { gap: 14px; }
  .company-hero__logo { width: 72px; height: 72px; border-radius: 14px; }
  .company-hero__logo-fallback { font-size: 32px; }
  .company-members__grid { grid-template-columns: 1fr; }
}

/* ── Company page — D0 enrichment (Enquire, coverage, listings, branches) ── */
.company-enquire { margin: 4px 0 20px; }

.company-coverage { margin-bottom: 28px; }
.company-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.company-chip {
  display: inline-flex;
  align-items: center;
  padding: 6px 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--paper);
  font-size: var(--fs-sm, 13px);
  color: var(--ink-2);
}

.company-listings { margin-bottom: 28px; }
.company-listings__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 12px;
}
.company-listing {
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--paper);
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  display: flex;
  flex-direction: column;
  transition: border-color 0.15s ease, transform 0.15s ease;
}
.company-listing:hover { border-color: color-mix(in oklch, var(--accent) 40%, var(--line)); transform: translateY(-1px); }
.company-listing__media {
  aspect-ratio: 16 / 10;
  background: var(--paper-2);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.company-listing__media img { width: 100%; height: 100%; object-fit: cover; }
.company-listing__media-fallback { font-size: 28px; opacity: 0.5; }
.company-listing__body { padding: 12px; display: flex; flex-direction: column; gap: 3px; }
.company-listing__title { font-weight: 600; font-size: var(--fs-sm, 14px); color: var(--ink); line-height: 1.3; }
.company-listing__meta { font-size: var(--fs-xs, 12px); color: var(--ink-3); }
.company-listing__price { font-family: var(--serif, Georgia, serif); font-size: var(--fs-lg, 17px); color: var(--ink); margin-top: 2px; }

.company-branches { margin-bottom: 28px; }
.company-branches__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.company-branch {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--paper);
}
.company-branch__city { font-weight: 600; color: var(--ink); }
.company-branch__addr { color: var(--ink-3); }

@media (max-width: 560px) {
  .company-listings__grid { grid-template-columns: 1fr 1fr; }
}

/* D1 — coverage chips are now links (company×locality pages) */
a.company-chip { text-decoration: none; transition: border-color 0.15s ease, color 0.15s ease; }
a.company-chip:hover { border-color: color-mix(in oklch, var(--accent) 45%, var(--line)); color: var(--ink); }

/* ==========================================================================
   CRM Phase 3 — manager accountability cockpit (/my/office/team).
   ========================================================================== */

/* Untouched strip — the manager's first glance; clickable into the
   needs-response inbox filter. Amber to signal "act on this". */
.team-untouched-strip {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 14px 18px;
    border: 1px solid #f59e0b;
    background: #fffbeb;
    border-radius: 10px;
    text-decoration: none;
    color: #92400e;
    transition: background 0.15s ease;
}
.team-untouched-strip:hover { background: #fef3c7; }
.team-untouched-count {
    font-size: 28px;
    font-weight: 700;
    line-height: 1;
    flex: 0 0 auto;
}
.team-untouched-label { line-height: 1.4; }
.team-all-clear { color: #065f46; }

/* Scorecard table — numeric columns right-aligned; alert rows tinted. */
.team-table-wrap { overflow-x: auto; }
.team-table th.num, .team-table td.num { text-align: right; white-space: nowrap; }
.team-table .team-agent-link { color: var(--ink); text-decoration: none; font-weight: 600; }
.team-table .team-agent-link:hover { text-decoration: underline; }
.team-row--alert { background: color-mix(in oklab, #f59e0b 6%, var(--paper)); }
.team-cell-alert { color: #b45309; font-weight: 700; }
.team-cell-ok { color: var(--ink-3); }

/* Inbox header → bulk-upload link (discreet, beside Add lead). */
.leads-bulk-upload-link {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  margin-left: 8px;
  color: var(--ink-2);
  text-decoration: none;
  white-space: nowrap;
}
.leads-bulk-upload-link:hover { color: var(--ink); text-decoration: underline; }

/* ── Cold-lead bulk upload (Phase 5) ───────────────────────────────── */
.cold-upload-dpdp {
  border: 1px solid color-mix(in oklab, #b45309 30%, var(--line));
  background: color-mix(in oklab, #f59e0b 8%, var(--paper));
  border-radius: 8px;
  padding: 12px 14px;
  margin: 14px 0;
  font-size: 14px;
  color: var(--ink-2);
}
.cold-upload-dpdp strong { color: #b45309; }
.cold-required { color: #b91c1c; }
.cold-upload-form { display: flex; flex-direction: column; gap: 6px; max-width: 520px; }
.cold-upload-form .btn { margin-top: 12px; align-self: flex-start; }
.cold-upload-counts {
  display: flex; flex-wrap: wrap; gap: 10px; margin: 8px 0 4px;
}
.cold-count {
  display: flex; flex-direction: column; align-items: center;
  min-width: 84px; padding: 10px 14px; border-radius: 8px;
  border: 1px solid var(--line); background: var(--ivory-2);
}
.cold-count-n { font-size: 22px; font-weight: 700; line-height: 1; }
.cold-count-l { font-size: 11px; font-family: var(--mono); color: var(--ink-3); margin-top: 4px; }
.cold-count--new { border-color: color-mix(in oklab, #059669 35%, var(--line)); }
.cold-count--new .cold-count-n { color: #059669; }
.cold-count--dup .cold-count-n { color: var(--ink-3); }
.cold-count--sup .cold-count-n { color: #b45309; }
.cold-count--inv .cold-count-n { color: #b91c1c; }
.cold-batch--archived { opacity: 0.55; }

/* Per-agent open-pipeline stage distribution (cockpit scorecard).
   A thin segmented bar (segment width ∝ stage count) + a compact caption.
   Stage palette reads as a warming progression: new (grey) → contacted
   (blue) → qualifying (amber) → negotiating (green). */
.team-stagebar {
    display: flex;
    align-items: stretch;
    gap: 2px;
    height: 5px;
    margin: 6px 0 4px;
    max-width: 220px;
    border-radius: 3px;
    overflow: hidden;
}
.team-stageseg { display: block; min-width: 4px; border-radius: 2px; }
/* Open-pipeline stage colours — a warming progression interested → meeting
   scheduled → meeting done → negotiating (grey-blue → blue → amber → green). */
.team-stageseg--interested { background: color-mix(in oklab, #2563eb 55%, transparent); }
.team-stageseg--meeting_scheduled { background: #2563eb; }
.team-stageseg--meeting_done { background: #d97706; }
.team-stageseg--negotiating { background: #059669; }
.team-stagecaption { display: flex; flex-wrap: wrap; gap: 4px 10px; color: var(--ink-3); }
.team-stagecaption-item { white-space: nowrap; }
.team-stageseg--interested-fg { color: #2563eb; }
.team-stageseg--meeting_scheduled-fg { color: #2563eb; }
.team-stageseg--meeting_done-fg { color: #b45309; }
.team-stageseg--negotiating-fg { color: #059669; }

/* Leaderboard — compact ordered list. */
.team-leaderboard { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 6px; }
.team-leader-row {
    display: flex;
    align-items: baseline;
    gap: 12px;
    padding: 8px 12px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--paper);
}
.team-leader-rank {
    flex: 0 0 auto;
    width: 22px;
    height: 22px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 999px;
    background: color-mix(in oklab, var(--ink) 8%, var(--paper));
    color: var(--ink-2);
    font-size: 12px;
    font-weight: 700;
}
.team-leader-name { flex: 1 1 auto; font-weight: 600; color: var(--ink); }
.team-leader-stat { color: var(--ink-3); }

/* Feed — reuses .lead-timeline; the team variant just caps height
   and scrolls so a busy firm's feed doesn't run the page forever. */
.team-feed { max-height: 560px; overflow-y: auto; }

/* ── Listing Completion Chip (Phase 1) ────────────────────────────
   Visible on broker dashboard listing cards + Compose Step 3 header.
   Hover surfaces "fill these to climb fastest: ..." tooltip via
   the native title attribute.
   Driven by App\Domain\Listings\ListingCompletionScorer →
   listings_local.quality_score. */
.lcc {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 4px 10px;
  border-radius: 999px;
  background: var(--paper-2, #f7f4ee);
  border: 1px solid var(--line, rgba(0,0,0,0.08));
  font-size: 12px;
  line-height: 1;
  cursor: help;
}
.lcc--md { padding: 6px 12px; font-size: 13px; }
.lcc-bar {
  position: relative;
  display: inline-block;
  width: 56px;
  height: 6px;
  border-radius: 3px;
  background: color-mix(in oklab, var(--ink, #333) 8%, transparent);
  overflow: hidden;
}
.lcc--md .lcc-bar { width: 80px; height: 7px; }
.lcc-bar-fill {
  position: absolute;
  inset: 0 auto 0 0;
  border-radius: 3px;
  transition: width 200ms ease;
}
.lcc-label { color: var(--ink-2, #444); font-weight: 500; white-space: nowrap; }

/* Colour bands mirror the score's natural gradient: 90+ thorough,
   70-89 well-filled, 40-69 modest, < 40 bare-publish please-enrich. */
.lcc--red .lcc-bar-fill { background: var(--red, #c83a3a); }
.lcc--red .lcc-label { color: var(--red, #c83a3a); }
.lcc--amber .lcc-bar-fill { background: var(--saffron-deep, #d8a35e); }
.lcc--amber .lcc-label { color: var(--saffron-deep, #d8a35e); }
.lcc--lime .lcc-bar-fill { background: #6b9b3a; }
.lcc--lime .lcc-label { color: #5a8530; }
.lcc--green .lcc-bar-fill { background: var(--green, #2c7a3e); }
.lcc--green .lcc-label { color: var(--green, #2c7a3e); }

/* Tiny vertical spacer when the chip lives inside the listings-index
   .dir-ident-body (under the title + motivation sub-text). */
.dir-ident-completion { margin-top: 6px; }

/* Compose Listing Step 3 completion banner — sits between the
   step-progress hint and the first Step 3 fieldset on edit only. */
.wizard-completion-banner {
  margin: 8px 0 20px;
  padding: 12px 16px;
  background: var(--paper-2, #f7f4ee);
  border: 1px solid var(--line, rgba(0,0,0,0.08));
  border-radius: 10px;
}
.wizard-completion-banner-head {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
.wizard-completion-banner-label { color: var(--ink-3, #777); font-size: 12px; }
.wizard-completion-banner-missing {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px dashed var(--line, rgba(0,0,0,0.08));
  font-size: 13px;
}
.wizard-completion-banner-missing ul {
  margin: 4px 0 0 18px;
  padding: 0;
}
.wizard-completion-banner-missing li {
  line-height: 1.6;
  color: var(--ink-2, #444);
}
.wizard-completion-banner-missing li .mono {
  color: var(--ink-3, #777);
  margin-left: 4px;
}

/* ── Pricing page + self-serve office plan cards ──────────────────────── */
.pricing-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 18px;
  margin-top: 8px;
}
.pricing-col {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 22px;
  border: 1px solid var(--hairline, #e6e2da);
  border-radius: 16px;
  background: var(--surface-1, #fff);
}
.pricing-col--featured {
  border-color: var(--saffron-deep, #b86a1a);
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.06);
}
.pricing-col-title {
  font-size: 1.25rem;
  margin: 0;
}
.pricing-col-sub {
  color: var(--ink-3, #777);
  margin: 2px 0 0;
}
.pricing-features {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.pricing-features li {
  padding-left: 18px;
  position: relative;
  color: var(--ink-2, #555);
}
.pricing-features li::before {
  content: "✓";
  position: absolute;
  left: 0;
  color: var(--saffron-deep, #b86a1a);
}
.pricing-plans {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.pricing-plan-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 8px 0;
  border-bottom: 1px solid var(--hairline, #efeae1);
}
.pricing-plan-label {
  font-weight: 600;
}
.pricing-plan-price {
  font-variant-numeric: tabular-nums;
}
.pricing-cta {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.pricing-plans-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 14px;
}
.pricing-plan-card {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 18px;
  border: 1px solid var(--hairline, #e6e2da);
  border-radius: 14px;
  background: var(--surface-1, #fff);
}
.pricing-plan-card-head {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.image-upload-preview {
  display: flex;
  align-items: center;
}

/* D5 iOS-zoom override RETIRED 2026-06-04 — replaced by --fs-input token in tokens.css. See brief_realtyx_fs_input_migration.md. */

/* ── Phase 5 #2.5 RealtyX D6 — public blog detail rules (2026-05-29)
   Until now the public blog page rendered with zero dedicated CSS:
   every long token (URL, transliterated locality, lengthy headline)
   silently overflowed under the page-edge `html, body { overflow-x:
   clip }` guard, hiding text from users with no scroll affordance.
   Markup classes (.blog-article-head/-title/-meta/-author/-hero/
   -body/-actions) exist at pages/blog/public-show.blade.php since
   the public-show page shipped. Pattern below mirrors the
   .public-post-* family at line 20720+ — reading-shell layout,
   author meta line, full-bleed hero, prose body, share actions. */
.blog-article-head {
  margin: 0 0 18px;
  /* No-crop reflex D2 — head sits inside the page-shell; allow text
     to shrink rather than push past the container. */
  min-width: 0;
}
.blog-article-title {
  font-family: var(--serif);
  font-size: clamp(24px, 4vw, 36px);
  line-height: 1.2;
  font-weight: 500;
  letter-spacing: -0.01em;
  margin: 0 0 12px;
  color: var(--ink);
  /* D7 — long unbroken tokens (URLs in title, etc.) break inside
     the word rather than push the container. */
  overflow-wrap: anywhere;
}
.blog-article-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  row-gap: 6px;
  column-gap: 8px;
  color: var(--ink-3);
  font-size: 12px;
}
.blog-article-author {
  color: var(--ink-2);
  text-decoration: none;
  font-weight: 500;
  /* No-crop reflex D2 — long broker name shrinks + ellipsis. */
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.blog-article-author:hover { color: var(--ink); text-decoration: underline; }
.blog-article-hero {
  /* D9 — fluid hero image with explicit aspect-ratio + width/height
     attrs in markup. Eliminates CLS during the first paint. */
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  height: auto;
  object-fit: cover;
  object-position: 50% 30%;
  border-radius: 10px;
  margin: 18px 0 22px;
  background: var(--ivory-2);
}
.blog-article-body {
  font-size: 16px;
  line-height: 1.65;
  color: var(--ink);
  /* No-crop reflex D7 — body prose can contain user-pasted URLs,
     transliterated names, etc. that lack natural break points. */
  overflow-wrap: anywhere;
  word-break: break-word;
}
.blog-article-body p { margin: 0 0 14px; }
.blog-article-body h2 {
  font-family: var(--serif);
  font-size: 22px;
  font-weight: 500;
  margin: 24px 0 12px;
  letter-spacing: -0.01em;
}
.blog-article-body h3 {
  font-size: 17px;
  font-weight: 600;
  margin: 20px 0 10px;
  letter-spacing: -0.005em;
}
.blog-article-body a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.blog-article-body a:hover { color: var(--saffron-deep); }
.blog-article-body ul,
.blog-article-body ol { margin: 0 0 16px; padding-left: 22px; }
.blog-article-body li { margin-bottom: 6px; }
.blog-article-body img {
  /* D9 reflex — every inline body image gets the same no-CLS
     treatment, in case markdown content hasn't supplied attrs. */
  max-width: 100%;
  height: auto;
  border-radius: 6px;
  margin: 12px 0;
}
.blog-article-actions {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  row-gap: 8px;
  margin: 24px 0 0;
  padding-top: 16px;
  border-top: 1px solid var(--line);
}

/* ── Phase 5 #2.5 RealtyX D8 — admin-table responsive wrap (2026-05-29)
   Mirrors the existing .settings-table-wrap pattern (single rule:
   overflow-x: auto). Markup-side: wrap <table class="admin-table">
   in <div class="admin-table-wrap"> in admin views — separate sweep
   tracked as a follow-up; the rule ships now so it's available the
   moment any single view is migrated. */
.admin-table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
@media (max-width: 800px) {
  /* Fallback for un-wrapped tables — the admin-table itself becomes
     a horizontally scrollable block on small viewports so the data
     stays reachable even before the markup-wrap sweep lands. Loses
     some <table> layout semantics (column alignment across the
     entire grid) but provides scroll access to data that would
     otherwise be silently clipped by the page-edge overflow-x:clip. */
  .admin-table-wrap > .admin-table { min-width: 640px; }
  .admin-table:not(.admin-table-wrap > *) {
    display: block;
    overflow-x: auto;
    white-space: nowrap;
  }
}

/* ── CRM Phase 2.5 — lead-routing dashboard ───────────────────────────── */
.routing-list { display: flex; flex-direction: column; gap: 12px; }
.routing-row {
    border: 1px solid var(--hairline, #e6e1d8);
    border-radius: 10px;
    padding: 14px 16px;
    background: var(--surface, #fff);
}
.routing-row--on { border-color: var(--saffron, #d98324); }
.routing-row-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.routing-row-label { font-weight: 600; }
.routing-row-muted { color: var(--ink-soft, #8a8276); }
.routing-row-controls { display: flex; flex-wrap: wrap; gap: 14px; margin-bottom: 10px; }
.routing-field { display: flex; flex-direction: column; gap: 4px; min-width: 200px; }
.routing-field-label { color: var(--ink-soft, #8a8276); }
.routing-agents {
    display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
    border: none; padding: 0; margin: 0 0 10px;
}
.routing-agent-chip {
    display: inline-flex; align-items: center; gap: 6px;
    border: 1px solid var(--hairline, #e6e1d8); border-radius: 999px;
    padding: 5px 12px; font-size: 0.9rem; cursor: pointer;
    min-height: 40px;
}
.routing-agent-chip--paused { opacity: 0.6; }
.routing-row-actions { display: flex; gap: 10px; align-items: center; }
.routing-rm-form { display: none; }

/* ── CRM Phase 8 — automations dashboard ──────────────────────────────── */
.automation-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px;
  padding: 12px 14px;
  border: 1px solid var(--line, #e7e2d8);
  border-radius: 10px;
  background: var(--paper, #fff);
}
.automation-row-main { min-width: 0; }
.automation-row-name { font-weight: 600; color: var(--ink, #2b2b2b); }
.automation-badge {
  display: inline-block;
  margin-left: 6px;
  font-size: 10px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-soft, #8a8276);
  border: 1px solid var(--line, #e7e2d8);
  border-radius: 4px;
  padding: 0 5px;
}
.automation-row-detail { color: var(--ink-soft, #8a8276); margin-top: 3px; }
.automation-row-preview { margin-top: 6px; color: var(--ink-soft, #8a8276); }
.automation-preview-btn {
  border: 0;
  background: none;
  color: var(--saffron, #d98324);
  cursor: pointer;
  padding: 0;
  font: inherit;
  text-decoration: underline;
}
.automation-row-actions { display: flex; gap: 8px; align-items: center; flex-shrink: 0; }
.automation-presets {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 12px;
}
.automation-preset {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 14px;
  border: 1px solid var(--line, #e7e2d8);
  border-radius: 10px;
  background: var(--ivory-2, #faf7f1);
}
.automation-preset-label { font-weight: 600; color: var(--ink, #2b2b2b); }
.automation-preset-desc { color: var(--ink-soft, #8a8276); margin-top: 3px; }

/* ── CRM Phase 10 — funnel analytics (CSS bars, no chart lib) ─────────── */
.analytics-periods {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 4px 0 18px;
}
.analytics-headline { color: var(--ink-soft, #8a8276); }
.analytics-headline strong { color: var(--ink, #2b2b2b); }
.analytics-bars {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.analytics-bar-row {
  display: grid;
  grid-template-columns: 140px 1fr auto;
  align-items: center;
  gap: 10px;
}
.analytics-bar-label {
  font-size: 13px;
  color: var(--ink, #2b2b2b);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.analytics-bar-track {
  display: block;
  height: 18px;
  background: var(--ivory-2, #faf7f1);
  border-radius: 4px;
  overflow: hidden;
}
.analytics-bar-fill {
  display: block;
  height: 100%;
  border-radius: 4px;
  min-width: 2px;
  transition: width 200ms ease;
}
.analytics-bar-fill--stage { background: var(--saffron, #d98324); }
.analytics-bar-fill--resp  { background: #2563eb; }
.analytics-bar-fill--lost  { background: #b45309; }
.analytics-bar-value {
  font-size: 12px;
  color: var(--ink-2, #555);
  white-space: nowrap;
}
.analytics-bar-n { color: var(--ink-4, #aaa); }
.analytics-bar-row--lost .analytics-bar-label { color: var(--ink-soft, #8a8276); }
@media (max-width: 640px) {
  .analytics-bar-row { grid-template-columns: 96px 1fr auto; gap: 6px; }
  .analytics-bar-label { font-size: 12px; }
}

/* ── CRM Phase 2.5 — bulk lead transfer (inbox) ───────────────────────── */
/* The card grid reserves a 0-width gutter by default; in bulk mode flip it
   to a real column so the checkbox sits LEFT of the card body instead of
   overlapping the client name. */
.leads-grid[data-bulk] .lead-card { grid-template-columns: 28px 1fr; }
.leads-grid[data-bulk] .lead-card-gutter {
  width: auto;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding-top: 2px;
}
.lead-card-gutter .lead-bulk-check { width: 18px; height: 18px; cursor: pointer; }
.lead-bulk-bar {
    position: sticky; bottom: 0; z-index: 20;
    display: flex; flex-wrap: wrap; align-items: center; gap: 12px;
    margin-top: 12px; padding: 12px 16px;
    background: var(--surface, #fff);
    border: 1px solid var(--saffron, #d98324); border-radius: 10px;
    box-shadow: 0 -2px 12px rgba(0,0,0,0.06);
}
.lead-bulk-bar[hidden] { display: none; }
.lead-bulk-field { display: inline-flex; align-items: center; gap: 8px; }
.lead-bulk-count { font-weight: 600; }

/* ── CRM Phase 2.5 — leads Table view ─────────────────────────────────── */
.leads-table-wrap { overflow-x: auto; border: 1px solid var(--line); border-radius: 12px; background: var(--paper); }
.leads-table { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
.leads-table thead th {
  text-align: left; padding: 10px 12px; font-weight: 600;
  color: var(--ink-soft, #6b6357); border-bottom: 1px solid var(--line);
  white-space: nowrap; position: sticky; top: 0; background: var(--ivory-2, #faf7f1);
}
.leads-table thead th.num, .leads-table td.num { text-align: right; }
/* Table rows carry data-* hooks only — never the .lead-card grid styling
   (which would set display:grid on a <tr> and collapse the whole table). */
.leads-table tbody tr { border-bottom: 1px solid var(--line); }
.leads-table tbody tr:hover { background: var(--ivory-2, #faf7f1); }
/* Defensive: if a .lead-card class ever lands on a table row again, don't let
   its grid/border/padding break the table layout. */
.leads-table tbody tr.lead-card { display: table-row; padding: 0; border-radius: 0; }
.leads-table td { padding: 9px 12px; vertical-align: middle; }
.leads-table-check { width: 36px; text-align: center; }
.leads-table-check .lead-bulk-check, .leads-table-check .lead-bulk-all { width: 17px; height: 17px; cursor: pointer; }
.leads-table-name { font-weight: 600; color: var(--ink); text-decoration: none; }
.leads-table-name:hover { text-decoration: underline; }
.lead-stage-chip { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: 0.78rem; background: var(--ivory-2,#f0ebe1); }
.lead-sla-pill { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: 0.75rem; }
.lead-sla--overdue { background: #fbe9e7; color: #b3261e; }
.lead-sla--due { background: #fff4e0; color: #a4650d; }
.lead-sla--ok { background: #e8f5e9; color: #2e7d32; }
/* Bulk bar: "select all matching filter" link */
.lead-bulk-selectall { background: none; border: none; color: var(--saffron, #d98324); cursor: pointer; text-decoration: underline; padding: 0; }

/* ════════════════════════════════════════════════════════════════
   Intros Dashboard — broker chat-room inbox at /intros/dashboard.
   Mirrors /preview/pages/matches-mobile-mock Frame 4. Mobile-first
   layout; desktop just gets a max-width container.
   See project_intros_dashboard memory.
   ════════════════════════════════════════════════════════════════ */
.intros-dashboard-wrap {
  max-width: 720px;
  margin: 0 auto;
  padding: 0;
}
.intros-dashboard {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 0;
  overflow: hidden;
}
@media (min-width: 720px) {
  .intros-dashboard-wrap { padding: 24px 16px; }
  .intros-dashboard { border-radius: 14px; }
}

.intros-dashboard-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 14px;
  background: color-mix(in oklab, var(--ivory, #f5efe2) 88%, transparent);
  border-bottom: 1px solid var(--line);
}
.intros-dashboard-titlewrap {
  display: inline-flex; align-items: center; gap: 6px;
}
.intros-dashboard-back {
  min-width: var(--tap); min-height: var(--tap);
  display: inline-flex; align-items: center; justify-content: center;
  font: 600 18px/1 var(--sans);
  color: var(--ink-2);
  text-decoration: none;
  border-radius: 999px;
}
.intros-dashboard-back:hover { background: var(--ivory-2, #efe8db); color: var(--ink); }
.intros-dashboard-title {
  font: 700 16px/1 var(--sans);
  color: var(--ink);
  margin: 0;
}
.intros-dashboard-summary {
  font: 500 12px/1 var(--sans);
  color: var(--ink-3);
}
.intros-dashboard-summary-sep { margin: 0 4px; color: var(--line-2, #d8d2c2); }

.intros-dashboard-pollhint {
  padding: 8px 14px;
  background: color-mix(in oklab, var(--saffron, #c8541f) 8%, var(--paper));
  border-bottom: 1px solid var(--line);
  font: 11px/1.3 var(--sans);
  color: var(--ink-3);
  text-align: center;
}
.intros-dashboard-pollhint-dot {
  display: inline-block;
  width: 6px; height: 6px;
  background: var(--saffron, #c8541f);
  border-radius: 50%;
  margin-right: 6px;
  vertical-align: middle;
}

.intros-dashboard-tabs {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 2px;
  background: var(--ivory-2, #efe8db);
  border-bottom: 1px solid var(--line);
  padding: 2px;
}
.intros-dashboard-tab {
  min-height: var(--tap);
  min-width: var(--tap);
  display: inline-flex; align-items: center; justify-content: center;
  gap: 4px;
  background: transparent; border: 0;
  font: 600 12px/1 var(--sans); color: var(--ink-3);
  cursor: pointer;
}
.intros-dashboard-tab--active {
  background: var(--paper); color: var(--ink);
  border-radius: 8px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
}
.intros-dashboard-tab-count {
  font: 500 11px/1 var(--sans); color: var(--ink-3);
}
.intros-dashboard-tab--active .intros-dashboard-tab-count { color: var(--saffron-deep, #b04a1a); }

.intros-dashboard-panel { display: block; }

.intros-dashboard-sub {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--paper);
  border-bottom: 1px solid var(--line);
  padding: 10px 14px 6px;
  font: 600 11px/1 var(--sans);
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--ink-3);
}

.intros-dashboard-row {
  display: grid;
  grid-template-columns: 40px 1fr auto;
  gap: 10px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--line);
  align-items: start;
  min-height: 72px;
  color: inherit;
  text-decoration: none;
}
.intros-dashboard-row--link { transition: background-color 100ms ease; }
.intros-dashboard-row--link:hover { background: var(--ivory-2, #efe8db); }
.intros-dashboard-row--muted { opacity: 0.72; }
.intros-dashboard-avatar {
  width: 40px; height: 40px;
  border-radius: 50%;
  background: var(--ivory-2, #efe8db);
  display: inline-flex; align-items: center; justify-content: center;
  font: 600 13px/1 var(--sans); color: var(--ink-2);
}
.intros-dashboard-rowbody { min-width: 0; }
.intros-dashboard-name {
  font: 600 14px/1.2 var(--sans); color: var(--ink);
  display: flex; align-items: center; gap: 4px;
}
.intros-dashboard-verified { color: var(--saffron-deep, #b04a1a); font-size: 10px; }
.intros-dashboard-context {
  font: 12px/1.3 var(--sans); color: var(--ink-3);
  margin-top: 2px;
}
.intros-dashboard-note {
  font: italic 12px/1.3 var(--sans); color: var(--ink-2);
  margin-top: 4px;
}
.intros-dashboard-last {
  font: 12px/1.3 var(--sans); color: var(--ink-2);
  margin-top: 2px;
  max-width: 200px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.intros-dashboard-deal {
  display: inline-flex; align-items: center; gap: 4px;
  background: color-mix(in oklab, var(--moss, #2f6b3b) 14%, var(--paper));
  color: var(--moss, #2f6b3b);
  font: 600 10px/1 var(--sans);
  letter-spacing: 0.02em;
  padding: 4px 8px;
  border-radius: 999px;
  margin-top: 6px;
}
.intros-dashboard-actions {
  display: flex; flex-direction: column; gap: 4px;
  align-items: stretch;
}
.intros-dashboard-actionform { margin: 0; }
.intros-dashboard-accept {
  width: 100%;
  min-height: var(--tap);
  min-width: var(--tap);
  padding: 0 14px;
  background: var(--ink); color: var(--paper);
  border: 0; border-radius: 999px;
  font: 600 13px/1 var(--sans);
  cursor: pointer;
}
.intros-dashboard-decline {
  width: 100%;
  min-height: var(--tap);
  min-width: var(--tap);
  padding: 0 14px;
  background: transparent; color: var(--ink-3);
  border: 1px solid var(--line); border-radius: 999px;
  font: 500 13px/1 var(--sans);
  cursor: pointer;
}
.intros-dashboard-meta {
  display: flex; flex-direction: column;
  align-items: flex-end; gap: 6px;
}
.intros-dashboard-waiting {
  font: 500 11px/1 var(--sans);
  color: var(--saffron-deep, #b04a1a);
  padding: 6px 10px;
  background: var(--ivory-2, #efe8db);
  border-radius: 999px;
}
.intros-dashboard-time { font: 11px/1 var(--sans); color: var(--ink-3); }
.intros-dashboard-unread {
  background: var(--saffron, #c8541f); color: var(--paper);
  font: 600 10px/1 var(--sans);
  padding: 3px 7px; border-radius: 999px;
}

.intros-dashboard-empty {
  padding: 24px 14px;
  text-align: center;
  color: var(--ink-3);
  font: 13px/1.5 var(--sans);
}
.intros-dashboard-empty-icon {
  font-size: 32px; margin-bottom: 8px; opacity: 0.4;
}

/* ════════════════════════════════════════════════════════════════
   /matches mobile polish — Phase B of the Intros Dashboard PR.
   Locked design 2026-06-07 after user reviewed the live mobile
   state. Three intents folded together:

     1. KPI strip collapses to single-wide "Hot today" — the other
        three tiles (Pipeline, Deals this week, Intros waiting) are
        either covered elsewhere on mobile (Intros lives on the
        filter-strip pill now) or are dashboard-level context that
        the broker is checking matches doesn't need at-a-glance.
     2. Pre-feed chrome (Daily Digest banner, "Smart Matches"
        eyebrow, "N matches for you" h1, "How does this work?"
        link) is hidden so the broker sees the filter strip + first
        match within one scroll instead of ~6 viewports.
     3. Pair-card restacks into a tight single-column with the
        score ring pinned to the top-right corner, inline budget/
        type/config data, kept attribution, hidden labels, and a
        full-width 48 px primary CTA. Frame 1 shape from the
        preview matches-mobile-mock.

   Desktop is untouched — every rule lives inside
   @media (max-width: 800px).
   ════════════════════════════════════════════════════════════════ */
@media (max-width: 800px) {

  /* ── 1. KPI strip — SINGLE-WIDE "Hot today" only per the locked
        Frame 1 preview. User direction: drop Pipeline back, keep
        only the Hot today tile. The :nth-child(2) selector picks
        the Hot today position; everything else (Pipeline, Deals
        this week, Intros waiting) hides on mobile. */
  .dash-kpis { grid-template-columns: 1fr; gap: 8px; }
  .dash-kpi:not(:nth-child(2)) { display: none; }

  /* ── 2. Pre-feed chrome — preview locks ZERO digest banner,
        ZERO h1, ZERO "How does this work?" affordance, ZERO
        floating "?" glyph button. Clean above-the-fold: KPI →
        filter strip → buckets. Nothing else. */
  .digest-banner { display: none; }
  .matches-main-head .eyebrow { display: none; }
  .matches-main-head .page-h1 { display: none; }
  .matches-main-head .matches-sort-line { display: none; }

  /* Collapse the now-empty main-head margin so the filter strip
     sits flush against the KPI tile. */
  .matches-main-head { margin-bottom: 0; }

  /* ── 3. Pair-card v3 — Frame 1 mobile DOM. The desktop
        `.match-pair-grid` hides entirely on mobile; the
        `.match-pair-mobile` block in pair.blade.php takes over
        with a totally different shape: avatar + name + 1-line
        meta, listing card-within-card (thumbnail + title +
        locality + price), inline ✓/✗ reasons, action row with
        Request-intro CTA + Save/👍/👎/bulk icon row. Matches
        /preview/pages/matches-mobile-mock Frame 1. */
  .match-pair-grid { display: none; }

  .match-pair {
    position: relative;
    padding: 12px;
    margin-bottom: 12px;
    border: 1px solid var(--line);
    border-radius: 14px;
    background: var(--paper);
  }
  .match-pair-mobile {
    display: flex;
    flex-direction: column;
    gap: 10px;
  }

  /* Score corner pill — top-right of the pair card. Two bands:
     hot (90+) gets the saffron brand pill; everything else gets
     the dark ink pill so the number always pops with strong
     contrast against the white card. The earlier gray "possible"
     band washed out the score against the buyer row. */
  .match-pair-mobile-score {
    position: absolute;
    top: 10px; right: 10px;
    z-index: 2;
    min-width: 44px;
    padding: 6px 10px;
    border-radius: 999px;
    font: 700 14px/1 var(--sans);
    text-align: center;
    background: var(--saffron, #c8541f);
    color: var(--paper);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.10);
  }
  .match-pair-mobile-score--strong,
  .match-pair-mobile-score--possible {
    background: var(--ink);
    color: var(--paper);
  }

  /* Buyer row — clean, NO card background per Frame 1. The "your
     buyer" cue lives in a subtle saffron-deep tint on the AVATAR
     border (when broker owns), not in a heavy card-tint anymore. */
  .match-pair-mobile-buyer {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 0;
    background: transparent;
    padding-right: 64px; /* leave room for the score pill */
  }
  /* Avatar: ivory background + dark initials per the Frame 1
     preview. The owner-side variant adds a saffron ring to
     differentiate without bringing back the heavy card-tint. */
  .match-pair-mobile-avatar {
    width: 44px; height: 44px;
    flex-shrink: 0;
    border-radius: 50%;
    background: var(--ivory-2, #efe8db);
    color: var(--ink-2);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font: 600 13px/1 var(--sans);
    letter-spacing: 0.02em;
    border: 1px solid var(--line);
  }
  .match-pair-mobile-buyer--mine .match-pair-mobile-avatar {
    border-color: var(--saffron, #c8541f);
    box-shadow: 0 0 0 2px color-mix(in oklab, var(--saffron, #c8541f) 18%, transparent);
  }
  .match-pair-mobile-buyer-ident { min-width: 0; flex: 1 1 auto; }
  .match-pair-mobile-buyer-name {
    font: 600 14px/1.25 var(--sans);
    color: var(--ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .match-pair-mobile-buyer-meta {
    font: 12px/1.3 var(--sans);
    color: var(--ink-3);
    margin-top: 2px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  /* Listing card-within-card — thumbnail + title + locality + price. */
  .match-pair-mobile-listing {
    display: flex;
    align-items: stretch;
    gap: 10px;
    padding: 10px;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: 10px;
    text-decoration: none;
    color: inherit;
  }
  .match-pair-mobile-listing--mine {
    border-color: color-mix(in oklab, var(--saffron, #c8541f) 30%, var(--line));
    background: color-mix(in oklab, var(--saffron, #c8541f) 6%, var(--paper));
  }
  .match-pair-mobile-listing-thumb {
    width: 64px; height: 64px;
    flex-shrink: 0;
    border-radius: 8px;
    background: var(--ivory-2, #efe8db);
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .match-pair-mobile-listing-thumb img {
    width: 100%; height: 100%;
    object-fit: cover;
    display: block;
  }
  .match-pair-mobile-listing-meta { min-width: 0; flex: 1 1 auto; display: flex; flex-direction: column; justify-content: center; }
  .match-pair-mobile-listing-titlerow {
    display: flex;
    align-items: center;
    gap: 6px;
  }
  .match-pair-mobile-listing-title {
    font: 600 13px/1.3 var(--sans);
    color: var(--ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    flex: 1 1 auto;
    min-width: 0;
  }
  .match-pair-mobile-listing-tag {
    font: 600 10px/1 var(--sans);
    color: var(--ink-3);
    padding: 3px 6px;
    background: var(--ivory-2, #efe8db);
    border-radius: 4px;
    flex-shrink: 0;
  }
  .match-pair-mobile-listing-locality {
    font: 12px/1.3 var(--sans);
    color: var(--ink-3);
    margin-top: 2px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .match-pair-mobile-listing-price {
    font: 700 13px/1 var(--sans);
    color: var(--saffron-deep, #b04a1a);
    margin-top: 4px;
  }

  /* Reasons inline — dot-separated text chips, no backgrounds. */
  .match-pair-mobile-reasons {
    font: 11px/1.4 var(--sans);
    color: var(--ink-3);
    margin: 2px 0;
  }
  .match-pair-mobile-reason--ok { color: var(--moss, #2f6b3b); font-weight: 600; }
  .match-pair-mobile-reason--miss { color: var(--ink-3); }
  .match-pair-mobile-reason-sep {
    color: var(--line-2, #d8d2c2);
    margin: 0 4px;
  }

  /* Action row — SINGLE horizontal row per Frame 1:
     [Request intro flexible-width] [Save 48px] [👍 48px]. The CTA
     flex-grows to fill remaining space after the two 48 px icon
     buttons claim their sizes. */
  .match-pair-mobile-actions {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 8px;
    margin-top: 2px;
  }
  .match-pair-mobile-cta {
    flex: 1 1 auto;
    min-height: var(--tap);
    min-width: var(--tap);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0 14px;
    background: var(--ink);
    color: var(--paper);
    border: 0;
    border-radius: 999px;
    font: 600 14px/1 var(--sans);
    text-decoration: none;
    cursor: pointer;
  }
  .match-pair-mobile-cta--secondary {
    background: transparent;
    color: var(--ink-2);
    border: 1px solid var(--line);
  }
  .match-pair-mobile-status {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: var(--tap);
    padding: 0 14px;
    background: var(--ivory-2, #efe8db);
    color: var(--ink-3);
    border-radius: 999px;
    font: 500 12px/1 var(--sans);
  }
  .match-pair-mobile-status--won {
    background: color-mix(in oklab, var(--moss, #2f6b3b) 14%, var(--paper));
    color: var(--moss, #2f6b3b);
    font-weight: 600;
  }
  .match-pair-mobile-hint {
    font: 12px/1.4 var(--sans);
    color: var(--ink-3);
    padding: 8px;
    text-align: center;
  }

  /* Icon row: Save + 👍 inline, sitting on the right of the CTA
     within the same flex row. Each 48 px. Drops 👎 and bulk-check
     for mobile per the locked Frame 1 design. */
  .match-pair-mobile-iconrow {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
  }
  /* Save button — the x-save-button component renders "★ Saved"
     (or "☆ Save") so it needs horizontal padding for the label.
     min-height stays at var(--tap) for the floor; width is auto
     so the chip stretches to fit the star + text without
     squashing the label. */
  .match-pair-mobile-iconrow .save-form button,
  .match-pair-mobile-iconrow .save-form .btn {
    min-height: var(--tap);
    min-width: var(--tap);
    padding: 0 14px;
    gap: 6px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: 999px;
    font: 500 13px/1 var(--sans);
    color: var(--ink);
    white-space: nowrap;
  }
  .match-pair-mobile-thumb,
  .match-thumb {
    min-width: var(--tap); min-height: var(--tap);
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: 999px;
    font-size: 18px;
  }
  /* 👎 popover wrapper — keeps the reason chips anchored to the
     button, and opens UPWARD (bottom: 100%) so the chips don't
     clip below the card on a bottom-anchored 48 px button. */
  .match-pair-mobile-thumbs-wrap { position: relative; }
  .match-pair-mobile-thumbs-wrap .match-thumbs-reasons {
    position: absolute;
    bottom: calc(100% + 6px);
    right: 0;
    margin-top: 0;
  }

  /* ── State-tabs: rounded pill segmented control per Frame 1
        (the underlined-text desktop variant doesn't translate to a
        mobile-app feel). [Active | Closed] sits in one ivory pill;
        the selected tab is paper-white with subtle shadow. */
  .matches-state-tabs {
    border-bottom: 0;
    margin: 0;
    background: var(--ivory-2, #efe8db);
    border-radius: 999px;
    padding: 3px;
    gap: 0;
    display: inline-flex;
  }
  .matches-state-tab {
    padding: 6px 16px;
    font-size: 13px;
    border-bottom: 0;
    margin-bottom: 0;
    border-radius: 999px;
    transition: background-color 120ms ease;
    min-height: 36px;
  }
  .matches-state-tab--active {
    background: var(--paper);
    color: var(--ink);
    font-weight: 600;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
    border-bottom-color: transparent;
  }
  .matches-state-tab .mono,
  .matches-state-tab--active .mono { color: inherit; }

  /* ── Bucket header per Frame 1 — UPPERCASE eyebrow style with the
        count as a small saffron-deep accent. Replaces the desktop
        serif "Possible · 50-79" treatment. */
  .match-bucket { margin: 16px 0 4px; }
  .match-bucket-header { padding: 0; border: 0; }
  .match-bucket-title {
    font: 600 11px/1 var(--sans);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink-3);
  }
  .match-bucket-count {
    font: 600 12px/1 var(--sans);
    color: var(--saffron-deep, #b04a1a);
    margin-left: 4px;
  }

  /* Dark-mode contrast safety net: the corner pill + bulk-check
     both use --paper as background, which blends into the same
     --paper underlying the .match-pair card in dark mode. A 1 px
     border via box-shadow keeps them visually separated. */
  [data-theme="dark"] .match-dial,
  [data-theme="dark"] .match-bulk-check {
    box-shadow: 0 0 0 1px var(--line);
  }
}

/* ════════════════════════════════════════════════════════════════
   /conversations/{id} mobile polish — Phase C of the Intros
   Dashboard PR. Locked 2026-06-07:

     1. Composer goes STICKY at the viewport bottom so the broker
        never has to scroll back to the textarea after the thread
        grows. 16 px font on the textarea defeats iOS focus-zoom.
        Send button hits the 48 px floor.

     2. The thread loses its desktop max-height: 520 px ceiling on
        mobile — the full available viewport (minus header + sticky
        composer + bottom-nav) is given to messages.

     3. Side-panel order on mobile: Contact share + Deal close
        (the two high-frequency actions) lift to the TOP, above the
        stacked context cards. Order via CSS `order` — no Blade
        change needed.

     4. Tighter header chrome (breadcrumb + h1) so above-the-fold
        belongs to the thread, not navigation.

   Desktop untouched — every rule inside @media (max-width: 800 px). */
@media (max-width: 800px) {

  /* ── Header chrome. The breadcrumb on /conversations/{c} carries
        a .breadcrumb--conversation scoping class so this rule actually
        matches — the parent ".conversation-layout" sits BELOW the
        breadcrumb in the DOM, not above it. */
  .breadcrumb--conversation {
    font-size: 11px;
    padding-bottom: 4px;
    margin-bottom: 8px;
  }
  .conversation-head {
    padding-bottom: 8px;
    margin-bottom: 12px;
  }
  .conversation-title {
    font-size: 20px;
  }
  .conversation-sub {
    font-size: 11px;
  }

  /* ── Thread is its OWN scroll container on mobile — cap height
        to the viewport minus the header + sticky composer + bottom-
        nav so the scrollTop write in conversation-thread.js
        scrollToBottom() actually moves the scroll position (without
        a height cap there's no overflow → scrollTop = 0 always). */
  .conversation-thread {
    max-height: calc(100dvh - 240px);
    overflow-y: auto;
    padding-bottom: 16px;
  }

  /* ── Sticky composer */
  .conversation-composer {
    position: sticky;
    bottom: 0;
    z-index: 5;
    background: var(--paper);
    border-top: 1px solid var(--line);
    padding: 10px 14px var(--bottom-nav-clearance-12, 76px);
    margin: 0 -14px;
    box-shadow: 0 -4px 12px -4px rgba(20, 18, 16, 0.08);
  }
  .conversation-composer .form-textarea {
    /* fs-input-allow — explicit 16 px defeats iOS focus-zoom on
       the conversation composer. The base .form-input ships at
       16 px globally; this guards against any cascade override. */
    font-size: 16px;
    min-height: 56px;
    border-radius: 12px;
  }
  .conversation-composer-actions {
    margin-top: 8px;
  }
  .conversation-composer-actions .btn {
    min-height: var(--tap);
    min-width: 120px;
    padding: 0 18px;
  }

  /* ── Side-panel reorder. Push contact share + deal close (the
        two high-frequency mobile actions) above buyer + listing
        context. Reviews + end-conversation stay last. */
  .conversation-side {
    display: flex;
    flex-direction: column;
    gap: 12px;
  }
  .conversation-share-card { order: 1; }
  .deal-card { order: 2; }
  .conversation-context-card:not(.conversation-share-card):not(.deal-card):not(.conversation-close-card) {
    order: 3;
  }
  .conversation-close-card { order: 99; }

  /* ── Each context card tighter on mobile */
  .conversation-context-card {
    padding: 12px;
    border-radius: 10px;
  }
  .conversation-context-title {
    font-size: 14px;
  }

  /* ── Message bubbles slightly wider on mobile to maximize content */
  .message {
    max-width: 90%;
    padding: 10px 12px;
  }
  .message-body {
    font-size: 14px;
  }

  /* ── Deal-close form inputs: 16 px to defeat iOS zoom + 48 px
        tap floor on the submit button */
  .deal-form-label {
    font-size: 12px;
    color: var(--ink-2);
  }
  .deal-card .form-input { font-size: 16px; }
  .deal-card .btn-primary,
  .deal-form .btn-primary,
  .review-form .btn-secondary {
    min-height: var(--tap);
    width: 100%;
  }

  /* ── Share-row button hits the 48 px floor */
  .share-row .btn-sm,
  .share-row button {
    min-height: var(--tap);
    padding: 0 14px;
  }

  /* ── Close + report controls — bigger tap targets, full-width.
        Stack the row on mobile so the .close-row-hint copy ("Mutual.
        Re-openable.") stays visible instead of being squeezed by the
        button at width:100%. */
  .close-row {
    width: 100%;
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
  }
  .close-row-hint { text-align: center; }
  .close-report-form { width: 100%; }
  .close-row .btn-sm,
  .close-row button,
  .close-report-form .btn-danger {
    min-height: var(--tap);
    width: 100%;
  }
  .close-row-report {
    min-height: var(--tap);
    padding: 12px;
    width: 100%;
    text-align: left;
    background: transparent;
    border: 0;
    color: var(--ink-3);
    font-size: 13px;
  }

  /* ── Intros Dashboard mobile polish — tighter padding inside
        rows so 360 px viewports don't crush the Accept/Decline
        button column under the row text. */
  .intros-dashboard-row {
    padding: 10px 12px;
    gap: 8px;
  }
  .intros-dashboard-name {
    font-size: 14px;
  }
  .intros-dashboard-context {
    font-size: 12px;
  }
  .intros-dashboard-note {
    font-size: 12px;
  }
  /* Accept/Decline keep 12 px — readable floor on primary actions
     in the owner-side pending row. The padding bump reclaims room
     so 12 px doesn't crush the row at 360 px. */
  .intros-dashboard-accept,
  .intros-dashboard-decline {
    padding: 0 12px;
    font-size: 12px;
  }
}

/* ============================================================
   Super-admin analytics dashboard (/admin/analytics)
   Reuses .admin-table / .admin-section / .dash-kpi; these add
   the date-range control, KPI strip, chart cards + grid.
   ============================================================ */
.analytics-daterange {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 18px;
  margin: 12px 0 20px;
  padding: 10px 12px;
  border: 1px solid #e5e7eb;
  border-radius: 10px;
  background: #fafafa;
}
.analytics-presets { display: flex; flex-wrap: wrap; gap: 6px; }
.analytics-preset {
  font: inherit;
  font-size: 12px;
  padding: 4px 10px;
  border: 1px solid #d1d5db;
  border-radius: 999px;
  background: #fff;
  color: #374151;
  cursor: pointer;
}
.analytics-preset:hover { border-color: #2563eb; color: #2563eb; }
.analytics-range-inputs { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.analytics-range-inputs label { display: inline-flex; align-items: center; gap: 6px; color: #6b7280; }
.analytics-range-inputs input[type="date"] {
  font: inherit;
  font-size: var(--fs-input);
  padding: 6px 8px;
  border: 1px solid #d1d5db;
  border-radius: 6px;
}
.analytics-apply {
  font: inherit;
  font-size: 13px;
  padding: 5px 14px;
  border: 0;
  border-radius: 6px;
  background: #2563eb;
  color: #fff;
  cursor: pointer;
}
.analytics-apply:hover { background: #1d4ed8; }

.analytics-kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 12px;
  margin-bottom: 24px;
}

.analytics-leaderboards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 18px;
}
.analytics-two-col {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 18px;
}

.analytics-chart-card { width: 100%; }
.analytics-chart-title { color: #6b7280; margin: 0 0 6px; }
.analytics-chart-canvas { min-height: 220px; }

.admin-table th a.is-active { color: #2563eb; font-weight: 600; }
.admin-table th a { color: inherit; text-decoration: none; }
.admin-table th a:hover { color: #2563eb; }

/* ════════════════════════════════════════════════════════════════════════
   Guided onboarding — Getting-Started hub ("Pehla Kadam") + spotlight tour
   ("Rishta Rahnuma"). Brand tokens only (--ink / --paper / --ivory / --line /
   --saffron / --charcoal); honours prefers-reduced-motion. Markup lives in
   resources/views/components/onboarding-hub.blade.php; engine in
   public/js/onboarding-tour.js; data in App\Domain\Onboarding.
   ════════════════════════════════════════════════════════════════════════ */

/* — Getting-Started checklist card — */
.onboarding-hub {
  position: relative;
  margin: 0 0 18px;
  padding: 18px 20px;
  background: radial-gradient(130% 150% at 0% 0%, color-mix(in oklab, var(--saffron) 11%, var(--paper)) 0%, var(--paper) 58%);
  border: 1px solid color-mix(in oklab, var(--saffron) 28%, var(--line));
  border-radius: 16px;
  box-shadow: 0 1px 2px color-mix(in oklab, var(--ink) 6%, transparent);
}
.onboarding-hub-close {
  position: absolute; top: 12px; right: 12px;
  width: 26px; height: 26px;
  display: inline-flex; align-items: center; justify-content: center;
  border: none; border-radius: 8px; background: transparent;
  color: var(--ink-3); cursor: pointer;
}
.onboarding-hub-close:hover { background: var(--ivory-2); color: var(--ink); }

.onboarding-hub-head { display: flex; align-items: center; gap: 14px; }
.onboarding-hub-headtext { flex: 1 1 auto; min-width: 0; }
.onboarding-hub-title { font-size: 16px; font-weight: 650; color: var(--ink); margin: 0; }
.onboarding-hub-sub { font-size: 12px; color: var(--ink-3); margin: 2px 0 0; }

.onboarding-ring { position: relative; flex: 0 0 auto; width: 40px; height: 40px; display: inline-grid; place-items: center; }
.onboarding-ring svg { position: absolute; inset: 0; }
.onboarding-ring-track { stroke: color-mix(in oklab, var(--saffron) 22%, var(--line)); }
.onboarding-ring-fill { stroke: var(--saffron-deep); transition: stroke-dashoffset .6s cubic-bezier(.2, .7, .2, 1); }
.onboarding-ring-count { font-size: 11px; font-weight: 650; color: var(--ink-2); font-variant-numeric: tabular-nums; }

.onboarding-tourbtn { flex: 0 0 auto; gap: 6px; }

.onboarding-tasks { list-style: none; margin: 16px 0 0; padding: 0; display: grid; gap: 8px; }
.onboarding-task {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 14px; border-radius: 12px;
  background: var(--paper); border: 1px solid var(--line);
}
.onboarding-task.is-done {
  background: color-mix(in oklab, var(--saffron) 6%, var(--paper));
  border-color: color-mix(in oklab, var(--saffron) 22%, var(--line));
}
.onboarding-task-mark {
  flex: 0 0 auto; width: 22px; height: 22px; border-radius: 999px;
  display: inline-grid; place-items: center;
  border: 2px solid var(--line); color: var(--paper);
}
.onboarding-task.is-done .onboarding-task-mark { background: var(--saffron-deep); border-color: var(--saffron-deep); }
.onboarding-task-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.onboarding-task-title { font-size: 13.5px; font-weight: 600; color: var(--ink); }
.onboarding-task.is-done .onboarding-task-title { color: var(--ink-3); text-decoration: line-through; text-decoration-color: color-mix(in oklab, var(--ink-4) 60%, transparent); }
.onboarding-task-body { font-size: 11.5px; color: var(--ink-3); }
.onboarding-task-cta { flex: 0 0 auto; font-size: 12.5px; padding: 7px 13px; }
.onboarding-task-state { flex: 0 0 auto; font-size: 11px; color: var(--saffron-deep); letter-spacing: .04em; text-transform: uppercase; }

.onboarding-hub-done { display: flex; align-items: center; gap: 14px; }
.onboarding-seal {
  flex: 0 0 auto; width: 40px; height: 40px; border-radius: 999px;
  display: inline-grid; place-items: center;
  background: color-mix(in oklab, var(--saffron) 18%, var(--paper));
  border: 1.5px solid var(--saffron-deep); color: var(--saffron-deep);
}
.onboarding-hub-done > div { flex: 1 1 auto; min-width: 0; }
.onboarding-replay { flex: 0 0 auto; }

/* — Spotlight walkthrough overlay — */
.tour-overlay {
  position: fixed; inset: 0; z-index: 1000;
  --tour-scrim: color-mix(in oklab, var(--charcoal) 62%, transparent);
}
.tour-overlay.is-dim { background: var(--tour-scrim); }

.tour-spotlight {
  position: fixed; border-radius: 12px; pointer-events: none;
  box-shadow: 0 0 0 9999px var(--tour-scrim), 0 0 0 2px var(--saffron-deep);
  transition: top .25s ease, left .25s ease, width .25s ease, height .25s ease;
  animation: tour-pulse 2.4s ease-in-out infinite;
}
@keyframes tour-pulse {
  0%, 100% { box-shadow: 0 0 0 9999px var(--tour-scrim), 0 0 0 2px var(--saffron-deep); }
  50%      { box-shadow: 0 0 0 9999px var(--tour-scrim), 0 0 0 5px color-mix(in oklab, var(--saffron) 40%, transparent); }
}

.tour-tip {
  position: fixed; z-index: 1001;
  width: min(340px, calc(100vw - 32px)); max-width: 340px;
  background: var(--paper); color: var(--ink);
  border: 1px solid var(--line); border-radius: 14px;
  box-shadow: 0 18px 50px -12px color-mix(in oklab, var(--charcoal) 45%, transparent);
  padding: 16px 18px 14px;
}
.tour-tip--center { top: 50% !important; left: 50% !important; transform: translate(-50%, -50%) !important; }
.tour-tip--sheet {
  left: 12px !important; right: 12px !important; bottom: 14px !important; top: auto !important;
  width: auto; max-width: none; transform: none !important;
}

.tour-tip-thread { display: flex; align-items: center; gap: 6px; margin-bottom: 10px; }
.tour-tip-dot { width: 7px; height: 7px; border-radius: 999px; background: var(--line); transition: all .2s ease; }
.tour-tip-dot.is-past { background: color-mix(in oklab, var(--saffron) 50%, var(--line)); }
.tour-tip-dot.is-current { width: 20px; background: var(--saffron-deep); }
.tour-tip-step { font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-4); margin: 0 0 4px; }
.tour-tip-title { font-size: 16px; font-weight: 650; color: var(--ink); margin: 0 0 6px; }
.tour-tip-body { font-size: 13px; line-height: 1.5; color: var(--ink-2); margin: 0 0 14px; }
.tour-tip-actions { display: flex; align-items: center; gap: 8px; }
.tour-tip-spacer { flex: 1 1 auto; }
.tour-skip { color: var(--ink-3); }

@media (prefers-reduced-motion: reduce) {
  .tour-spotlight { animation: none; transition: none; }
  .onboarding-ring-fill { transition: none; }
}

@media (max-width: 700px) {
  .onboarding-hub-head { flex-wrap: wrap; }
  .onboarding-tourbtn { order: 3; width: 100%; justify-content: center; margin-top: 4px; }
  .onboarding-task { flex-wrap: wrap; }
  .onboarding-task-cta { width: 100%; }
}

/* ─────────────────────────────────────────────────────────────────
   Phase 10a — Infinite-scroll sentinel for /feed/latest. HTMX-driven:
   hx-trigger="revealed" fires when the sentinel enters the viewport;
   the response swaps the sentinel with the next batch + a fresh
   sentinel. End-of-stream replaces the sentinel with .feed-stream-end.
   ───────────────────────────────────────────────────────────── */
.feed-stream-sentinel {
  min-height: 56px;
  padding: 16px 0 24px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.feed-stream-state {
  /* The live region wrapper. Always rendered when a sentinel is in
     the DOM so screen readers have a stable anchor to attach to;
     content swaps between .feed-stream-loading and .feed-stream-retry
     via HTMX error hooks. */
  display: flex;
  align-items: center;
  justify-content: center;
}
.feed-stream-loading {
  font-size: 12px;
  color: var(--ink-3);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.feed-stream-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--saffron, #c8541f);
  animation: feed-stream-pulse 1s ease-in-out infinite;
}
@keyframes feed-stream-pulse {
  0%, 100% { opacity: 0.3; transform: scale(0.85); }
  50%      { opacity: 1;   transform: scale(1.15); }
}
.feed-stream-retry {
  /* HTMX response/send error hooks swap the loader for this button.
     Plain button styled like a chip — affordance reads "tap to recover"
     without being so loud that it competes with feed content. */
  font: inherit;
  font-size: 12px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--saffron, #c8541f);
  background: transparent;
  border: 1px solid var(--saffron, #c8541f);
  border-radius: 999px;
  padding: 10px 16px;
  cursor: pointer;
  min-height: 44px;
  /* Match the rest of the touch-target floor so the lint passes. */
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.feed-stream-retry:hover,
.feed-stream-retry:focus-visible {
  background: var(--saffron, #c8541f);
  color: #fff;
  outline: none;
}
.feed-stream-end {
  padding: 24px 0 32px;
  text-align: center;
  font-size: 11px;
  color: var(--ink-3);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border-top: 1px dashed var(--line);
  margin-top: 12px;
}
@media (prefers-reduced-motion: reduce) {
  .feed-stream-dot {
    /* Static saffron circle reads as decoration; the aria-hidden span
       + text ("Loading more…") inside the role=status region carries
       the loading semantic. Hide entirely so reduced-motion users
       don't get a vestigial dot with no animation context. */
    display: none;
  }
}

/* ════════════════════════════════════════════════════════════════════════
   Help explainer — the always-available static reference panel
   (x-help-explainer), companion to the one-time spotlight tour. Native
   <details>; brand tokens; honours prefers-reduced-motion. Content from
   OnboardingRegistry::concepts().
   ════════════════════════════════════════════════════════════════════════ */
.help-explainer {
  margin: 0 0 16px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--paper);
  overflow: hidden;
}
.help-explainer[open] { border-color: color-mix(in oklab, var(--saffron) 26%, var(--line)); }
.help-explainer-summary {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 12px 16px; cursor: pointer; list-style: none;
  font-size: 13.5px; font-weight: 600; color: var(--ink);
  user-select: none;
}
.help-explainer-summary::-webkit-details-marker { display: none; }
.help-explainer-summary:hover { background: var(--ivory-2); }
.help-explainer-lead { display: inline-flex; align-items: center; gap: 9px; }
.help-explainer-icon {
  flex: 0 0 auto; width: 24px; height: 24px; border-radius: 999px;
  display: inline-grid; place-items: center;
  background: color-mix(in oklab, var(--saffron) 14%, var(--paper));
  color: var(--saffron-deep);
}
.help-explainer-chevron { color: var(--ink-3); transition: transform .2s ease; }
.help-explainer[open] .help-explainer-chevron { transform: rotate(180deg); }
.help-explainer-body {
  padding: 4px 16px 16px;
  display: grid; gap: 12px;
  border-top: 1px solid var(--line);
}
@media (min-width: 720px) {
  .help-explainer-body { grid-template-columns: 1fr 1fr; }
}
.help-explainer-card {
  padding: 12px 14px; border-radius: 10px;
  background: var(--ivory-2); border: 1px solid var(--line);
}
.help-explainer-card-title { font-size: 13px; font-weight: 650; color: var(--ink); margin: 0 0 4px; }
.help-explainer-card-body { font-size: 12.5px; line-height: 1.55; color: var(--ink-2); margin: 0; }

@media (prefers-reduced-motion: reduce) {
  .help-explainer-chevron { transition: none; }
}

/* ─────────────────────────────────────────────────────────────────
   Compose discussion post — instant photo preview + real upload bar.
   Driven by Alpine.data('composePhoto') (public/js/compose-photo.js).
   ───────────────────────────────────────────────────────────── */
.compose-photo-alert {
  background: color-mix(in srgb, #c0392b 8%, var(--ivory-2, #fff));
  border: 1px solid color-mix(in srgb, #c0392b 30%, transparent);
  color: #8e2a20;
  border-radius: 10px;
  padding: 10px 14px;
  font-size: 13px;
  margin-bottom: 16px;
}

/* Dropzone — the "Add a photo" affordance shown until a file is picked. */
.compose-photo-drop {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-height: 120px;
  padding: 20px;
  border: 1.5px dashed var(--line, #d9d4cc);
  border-radius: 12px;
  background: var(--ivory-2, #faf8f4);
  cursor: pointer;
  text-align: center;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.compose-photo-drop:hover,
.compose-photo-drop:focus-within {
  border-color: var(--saffron, #c8541f);
  background: color-mix(in srgb, var(--saffron, #c8541f) 5%, var(--ivory-2, #faf8f4));
}
/* The native file input is visually hidden but stays in the DOM (and in
   FormData) — the wrapping label is the click + focus surface. */
.compose-photo-file {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
}
.compose-photo-drop-icon {
  font-size: 28px;
  line-height: 1;
  color: var(--saffron, #c8541f);
  font-weight: 300;
}
.compose-photo-drop-text {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink-1, #2b2620);
}
.compose-photo-drop-hint {
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--ink-3, #8a8276);
  text-transform: uppercase;
}

/* Preview — thumbnail + filename + remove, shown once a photo is chosen. */
.compose-photo-preview {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.compose-photo-frame {
  position: relative;
  border-radius: 12px;
  overflow: hidden;
  border: 1px solid var(--line, #d9d4cc);
  background: var(--ink-1, #2b2620);
  max-height: 340px;
}
.compose-photo-thumb {
  display: block;
  width: 100%;
  max-height: 340px;
  object-fit: contain;
}
/* Upload bar overlays the bottom edge of the thumbnail. */
.compose-photo-bar-track {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 6px;
  background: color-mix(in srgb, #000 35%, transparent);
}
.compose-photo-bar {
  height: 100%;
  background: var(--saffron, #c8541f);
  border-radius: 0 3px 3px 0;
  transition: width 0.2s ease;
}
/* Finalize phase (bytes done, server processing) — width is pinned to
   100% inline; a moving highlight communicates "still working". */
.compose-photo-bar--finalizing {
  background-image: linear-gradient(
    90deg,
    var(--saffron, #c8541f) 0%,
    color-mix(in srgb, #fff 55%, var(--saffron, #c8541f)) 50%,
    var(--saffron, #c8541f) 100%
  );
  background-size: 200% 100%;
  animation: compose-photo-sweep 1.1s linear infinite;
}
@keyframes compose-photo-sweep {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
.compose-photo-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.compose-photo-name {
  font-size: 12px;
  color: var(--ink-3, #8a8276);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.compose-photo-remove {
  font: inherit;
  font-size: 12px;
  color: var(--ink-3, #8a8276);
  background: transparent;
  border: 1px solid var(--line, #d9d4cc);
  border-radius: 999px;
  padding: 8px 14px;
  min-height: 44px;
  cursor: pointer;
  flex-shrink: 0;
}
.compose-photo-remove:hover:not(:disabled),
.compose-photo-remove:focus-visible {
  border-color: #c0392b;
  color: #c0392b;
  outline: none;
}
.compose-photo-remove:disabled {
  opacity: 0.5;
  cursor: default;
}

/* Posting status row — covers text-only posts (instant upload then the
   AI-moderation finalize phase). */
.compose-posting {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 16px;
  font-size: 13px;
  color: var(--ink-2, #5a5247);
  letter-spacing: 0.02em;
}
.compose-posting-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--saffron, #c8541f);
  animation: compose-photo-pulse 1s ease-in-out infinite;
}
@keyframes compose-photo-pulse {
  0%, 100% { opacity: 0.3; transform: scale(0.85); }
  50%      { opacity: 1;   transform: scale(1.15); }
}

@media (prefers-reduced-motion: reduce) {
  .compose-photo-bar--finalizing { animation: none; }
  .compose-photo-bar { transition: none; }
  .compose-posting-dot { animation: none; opacity: 0.8; }
}
