/* Override Squarespace c-wrapper width constraint */
.c-wrapper { max-width: none !important; width: 100% !important; padding-left: 0 !important; padding-right: 0 !important; }

/* ── oh-prefixed namespace to avoid KW collisions ── */
*, *::before, *::after { box-sizing: border-box; }

/* Kill the default 8px body margin — was showing as a thin white
   border around the lavender controls block at the page edges. */
html, body { margin: 0; padding: 0; background: #e8ecf1; }
body { min-width: 320px; }

.oh-wrap {
  font-family: 'Century Gothic', 'CenturyGothicPaneuropean', Arial, Helvetica, sans-serif;
  background: #e8ecf1;
  padding: 0 0 48px;
  color: #333;
}

/* HEADER */
.oh-header {
  background: #32143f;
  padding: 32px 0 28px;
  text-align: center;
}
.oh-header-inner {
  max-width: 1920px;
  margin: 0 auto;
  padding: 0 24px;
  position: relative;  /* anchor for header route link */
}
/* Back link on the /route/ page header. Listings page no longer uses
   a header route link — moved to a wide CTA bar below the filters
   (see .oh-route-cta below). */
.oh-header-back {
  position: absolute;
  top: 0;
  left: 24px;
  display: inline-flex;
  align-items: center;
  padding: 8px 14px;
  color: #E098FF;
  font-family: inherit;
  font-size: 13px;
  font-weight: bold;
  letter-spacing: 0.4px;
  text-decoration: none;
  transition: color 0.15s;
}
.oh-header-back:hover { color: #fff; }
@media (max-width: 719px) {
  .oh-header-back {
    position: static;
    /* Generous gap below the back button so the ABODEslc brand block
       isn't crowding it on mobile. */
    margin: 4px auto 18px;
    display: inline-flex;
  }
  .oh-header { padding-bottom: 18px; }
}

/* Route Planner CTA — lives INSIDE the controls body, below the city
   chips, so it inherits the body's narrower column (not the full row
   width). No background, just a thin top divider to separate it from
   the city chips above. */
.oh-route-cta {
  display: block;
  width: 100%;
  padding: 12px 0;
  margin-bottom: 6px;
  background: transparent;
  color: #32143f;
  font-family: inherit;
}
.oh-route-cta-inner {
  display: flex;
  align-items: center;
  gap: 6px 12px;
  flex-wrap: wrap;
}
/* FAVORITES label takes its own row (like "Open House Day" sits above
   its chips). Hearts + Plan Route button share the next row. */
.oh-route-cta-main { flex: 1 1 100%; }
.oh-route-cta-main {
  /* Matches .oh-filter-label so "Favorites" reads as the same kind of
     row-label as "Open House Day" / "City" above it. */
  font-size: 11px;
  font-weight: bold;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: #7a4f9a;
  white-space: nowrap;
  flex-shrink: 0;
}
.oh-route-cta-empty {
  font-size: 13.5px;
  font-weight: 600;
  color: rgba(50,20,63,0.6);
  flex: 0 1 auto;
}
/* Hearts row is a clickable filter toggle (no longer a separate
   "Show favorites" button). Each heart represents one hearted home —
   no fixed slot count. Hearts 1-5 are bright; 6+ are dimmed to nudge
   the user toward a tighter route. */
.oh-stop-label { display: none; }
@media (min-width: 925px) {
  .oh-stop-label { display: inline; }
  .oh-stop-label::after { content: '\00a0'; }
}

.oh-route-cta-hearts {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex-shrink: 0;
  background: transparent;
  border: 1.5px solid transparent;
  border-radius: 999px;
  padding: 5px 10px;
  cursor: pointer;
  font-family: inherit;
  transition: background 0.15s, border-color 0.15s;
}
.oh-route-cta-hearts:hover {
  background: rgba(224,152,255,0.12);
  border-color: rgba(224,152,255,0.4);
}
.oh-route-cta-hearts.is-active {
  background: rgba(224,152,255,0.28);
  border-color: rgba(50,20,63,0.4);
}
/* Route stop pills mirror the "✓ Added to route" pill on the listing
   cards: light lavender (empty placeholder) → saturated lavender with
   a dark check (one stop added). Same #E098FF / #F5F0FC / #DCC8F5
   palette as the filter chips so it all hangs together. */
.oh-route-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 6px 14px;
  border-radius: 20px;
  border: 1.5px solid #dcc8f5;
  box-sizing: border-box;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.4;
  white-space: nowrap;
  color: #5a3a7a;
}
.oh-route-chip.empty {
  background: #F5F0FC;
  opacity: 0.45;
}
.oh-route-chip.filled {
  background: #E098FF;
  border-color: #E098FF;
  color: #32143f;
}
@keyframes oh-heart-pop {
  0%   { transform: scale(0.6); }
  60%  { transform: scale(1.25); }
  100% { transform: scale(1); }
}
.oh-route-chip.just-filled { animation: oh-heart-pop 0.3s ease-out; }
.oh-route-cta-overflow {
  height: 36px;
  min-width: 36px;
  padding: 0 10px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  box-sizing: border-box;
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
  color: #32143f;
  background: #F5F0FC;
  border: 1px solid #DCC8F5;
}
.oh-route-cta-hint {
  font-size: 12px;
  font-style: italic;
  color: #7a4f9a;
  flex: 0 1 auto;
  min-width: 0;
}
/* Plan Route button — own affordance on the right, so the row is
   never read as one giant clickable strip. Dark-purple pill matching
   the rest of the brand. */
.oh-route-cta-plan-btn {
  margin-left: auto;
  padding: 8px 18px;
  background: #32143f;
  color: #fff;
  border-radius: 999px;
  font-size: 14px;
  font-weight: bold;
  letter-spacing: 0.3px;
  text-decoration: none;
  flex-shrink: 0;
  transition: background 0.15s, transform 0.15s;
}
.oh-route-cta-plan-btn:hover {
  background: #4a2055;
  transform: translateX(2px);
}
/* Flex-line break that used to force the Plan Route button onto its
   own row on mobile. Disabled — user wants the button next to the
   hearts at all viewports. Keeping the element in the HTML so the
   layout stays predictable if we ever want to re-enable it. */
.oh-route-cta-mobile-break { display: none; }

@media (max-width: 719px) {
  /* Mobile layout stacks the label on row 1 (like "Open House Day"),
     with hearts and the Route Planner button sharing row 2. */
  .oh-route-cta { padding: 10px 0; }
  .oh-route-cta-inner {
    flex-wrap: wrap;
    gap: 10px;
    justify-content: flex-start;
    align-items: center;
  }
  .oh-route-cta-main { flex: 1 1 100%; }
  .oh-route-cta-hearts { flex: 0 1 auto; }
  .oh-route-chip { padding: 6px 10px; }
  .oh-route-cta-empty { flex: 1 1 100%; text-align: left; font-size: 12.5px; }
  .oh-route-cta-hint { flex: 1 1 100%; }
  .oh-route-cta-plan-btn { flex: 0 0 auto; }
}
.oh-brand {
  display: block;
  font-size: 11px;
  font-weight: bold;
  letter-spacing: 3px;
  text-transform: uppercase;
  color: #E098FF;
  margin-bottom: 8px;
}
.oh-brand-sub {
  display: block;
  font-size: 9px;
  font-weight: normal;
  letter-spacing: 1.5px;
  color: rgba(255,255,255,0.45);
  margin-top: 2px;
  text-transform: uppercase;
}
.oh-title {
  margin: 0 0 8px;
  font-size: clamp(26px, 5vw, 42px);
  font-weight: bold;
  color: #fff;
  text-transform: uppercase;
  letter-spacing: 2px;
}
.oh-date {
  font-size: 16px;
  color: #E8A820;
  font-weight: bold;
  margin: 0;
}

/* CONTROLS */
.oh-controls {
  background: #faf7fd;
}
/* Full-width count bar — replaces the old bottom border of the filter
   section. Uses the old border lavender, clickable to jump to listings. */
.oh-count-bar {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  width: 100%;
  margin: 0;
  padding: 13px 20px;
  border: none;
  background: #E098FF;
  color: #32143f;
  font-family: inherit;
  font-size: 16px;
  font-weight: bold;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 0.15s ease;
}
.oh-count-bar:hover { background: #D079F5; }
.oh-count-bar strong { color: #32143f; }
.oh-count-bar-arrow {
  position: relative;
  top: -2px;
  font-size: 18px;
  line-height: 1;
  transition: transform 0.15s ease;
}
.oh-count-bar:hover .oh-count-bar-arrow { transform: translateY(3px); }
.oh-controls-inner {
  max-width: 1400px;
  margin: 0 auto;
  padding: 24px 20px 0;
}
.oh-controls-row1 {
  display: none !important;
}
/* Sort+Reset inline on the search bar row (override the column-direction
   used elsewhere when this group lives in a filter row with a label) */
.oh-controls-row1 #oh-sort-group {
  flex-direction: row;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
  flex-wrap: nowrap;
}
/* FILTER ROWS */
.oh-frow {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px 28px;
  padding: 10px 0;
  border-top: 1px solid #f0eaf8;
}
.oh-frow:first-child { border-top: none; padding-top: 8px; }
#oh-featured-group { flex: 0 0 auto; flex-direction: column; align-items: flex-start; gap: 5px; }
#oh-day-group      { flex: 0 0 auto; flex-direction: column; align-items: flex-start; gap: 5px; min-width: 0; }
#oh-time-group     { flex: 0 0 auto; flex-direction: column; align-items: flex-start; gap: 5px; min-width: 0; }
#oh-price-group    { flex: 0 0 auto; flex-direction: column; align-items: flex-start; gap: 5px; }
#oh-beds-group     { flex: 0 0 auto; flex-direction: column; align-items: flex-start; gap: 5px; }
#oh-baths-group    { flex: 0 0 auto; flex-direction: column; align-items: flex-start; gap: 5px; }
#oh-sqft-group     { flex: 0 0 auto; flex-direction: column; align-items: flex-start; gap: 5px; }
#oh-dom-group      { flex: 0 0 auto; flex-direction: column; align-items: flex-start; gap: 5px; }
#oh-sort-group     { flex: 0 0 auto; flex-direction: column; align-items: flex-start; gap: 5px; }
#oh-city-group     { flex: 1 1 100%; }

.oh-filter-group {
  display: flex;
  align-items: center;
  gap: 7px;
  flex-wrap: wrap;
}
.oh-filter-label {
  /* Demoted: section header above each group is the dominant landmark
     now; the per-row label just identifies which filter row this is. */
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: rgba(50,20,63,0.55);
  white-space: nowrap;
}
/* Action-led section header — one per themed filter group ("When you're
   free", "Find a home", "Plan your route"). Bigger and bolder than the
   per-row labels so the eye sees the three sections first, then the rows
   inside. */
.oh-section-header {
  font-size: 18px;
  font-weight: 700;
  color: #32143f;
  letter-spacing: 0.02em;
  margin: 22px 0 4px;
}
.oh-section-header:first-child { margin-top: 0; }
/* Full-width section row — wraps the "Pick when to see homes" block
   above the map/home grid and the "Plan your route" block below it.
   Same inner padding as #oh-controls-body so the chips/buttons inside
   line up with the Find a home content visually. Thin top border on
   each section reads as a quiet separator between bands. */
.oh-section-row {
  margin: 18px 0 8px;
  padding-top: 16px;
  border-top: 1px solid rgba(50,20,63,0.12);
}
.oh-section-row:first-child { border-top: none; padding-top: 0; margin-top: 0; }
.oh-section-row .oh-section-header { margin-top: 0; }
/* No inner divider lines between rows WITHIN a section (Day/Time inside
   "Pick when to see homes", Price/City inside "Set your budget"). Only
   the .oh-section-row border-top separates sections from each other. */
.oh-section-row .oh-frow { border-top: none; padding-top: 0; padding-bottom: 0; }
/* Desktop: map sits on the LEFT, sections column on the right. Map is
   #oh-city-map-panel and is later in source order than #oh-controls-body,
   so order: -1 pulls it to the left side of the flex row. */
@media (min-width: 1140px) {
  #oh-controls-layout {
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    gap: 32px;
  }
  #oh-city-map-panel {
    order: -1;
    align-self: flex-start;
  }
  #oh-controls-body {
    flex: 1 1 0;
    min-width: 0;
  }
  /* On desktop, let city chips wrap so all cities are visible at once,
     filling the full width of the right-hand column instead of
     squeezing into the space left after an inline label. */
  #oh-city-group {
    flex-direction: column;
    align-items: flex-start;
    gap: 5px;
    min-width: 0;
  }
  #oh-city-chips {
    flex-wrap: wrap;
    overflow-x: visible;
    width: 100%;
  }
}
/* Subtitle: plain-English explanation of what the section is for. Tells
   a first-time visitor exactly what to do without being a Step 1/2/3
   prescription. */
.oh-section-subtitle {
  margin: 0 0 12px;
  font-size: 13px;
  font-weight: 500;
  color: rgba(50,20,63,0.65);
  line-height: 1.45;
  max-width: 640px;
}
.oh-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.oh-chip {
  padding: 6px 14px;
  border-radius: 20px;
  border: 1.5px solid #dcc8f5;
  background: #f5f0fc;
  color: #5a3a7a;
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
  white-space: nowrap;
  line-height: 1.4;
}
.oh-chip.active {
  background: #E098FF;
  border-color: #E098FF;
  color: #32143f;
}
.oh-chip:hover:not(.active) {
  background: #ede0fa;
  border-color: #9B6EC8;
  color: #32143f;
}
/* City chips keep the gold hover because they're paired with map
   polygons — gold is the "chip ↔ shape" link color. Day/time/other
   chips have no map relationship and get the default purple hover. */
#oh-city-chips .oh-chip:hover:not(.active) {
  border-color: #E8A820;
}
.oh-chip--gold {
  border-color: #f0c84a;
  background: #fffbeb;
  color: #7a5200;
}
.oh-chip--gold.active {
  background: #E8A820;
  border-color: #E8A820;
  color: #fff;
}
.oh-chip--gold:hover:not(.active) {
  background: #fff3cc;
  border-color: #E8A820;
  color: #5a3a00;
}
.oh-chip--purple {
  border-color: #dcc8f5;
  background: #f5f0fc;
  color: #5a3a7a;
}
.oh-chip--purple.active {
  background: #E098FF;
  border-color: #E098FF;
  color: #32143f;
}
.oh-chip--purple:hover:not(.active) {
  background: #ede0fa;
  border-color: #c080e8;
  color: #32143f;
}
.oh-chip--past,
.oh-chip--unavailable {
  opacity: 0.4;
  text-decoration: line-through;
  cursor: not-allowed;
  pointer-events: none;
}

.oh-price-input {
  width: 120px;
  padding: 6px 14px;
  border: 1.5px solid #dcc8f5;
  border-radius: 20px;
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.4;
  background: #f5f0fc;
  color: #5a3a7a;
  outline: none;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
  text-align: center;
}
.oh-price-input:focus { border-color: #E098FF; }
.oh-price-input::placeholder { color: #bbb; }
.oh-price-input:not(:placeholder-shown) {
  background: #E098FF;
  border-color: #E098FF;
  color: #32143f;
  font-weight: 700;
}
.oh-price-clear {
  appearance: none;
  -webkit-appearance: none;
  background: none;
  border: none;
  padding: 0;
  margin-left: 2px;
  font-size: 15px;
  line-height: 1;
  color: #9B6EC8;
  cursor: pointer;
  display: none;
}
.oh-price-clear:hover { color: #32143f; }
.oh-reset-btn {
  padding: 9px 16px;
  border: 1.5px solid #E098FF;
  border-radius: 8px;
  font-family: 'Century Gothic', 'CenturyGothicPaneuropean', Arial, Helvetica, sans-serif;
  font-size: 15px;
  font-weight: bold;
  background: #fff;
  color: #7a4f9a;
  cursor: pointer;
  white-space: nowrap;
  letter-spacing: 0.3px;
  transition: border-color 0.15s, color 0.15s, background 0.15s;
}
.oh-reset-btn:hover { background: #FAF4FF; border-color: #c060e8; color: #32143f; }


/* RANGE SLIDERS (kept for backwards compat) */
.oh-slider-group {
  display: flex;
  flex-direction: column;
  gap: 5px;
  flex: 1 1 140px;
  max-width: 220px;
}
.oh-slider-group--wide {
  flex: 4 1 340px;
  max-width: 560px;
}
.oh-slider-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
}
.oh-slider-val {
  font-size: 12px;
  color: #555;
}
.oh-range-wrap {
  position: relative;
  height: 24px;
}
.oh-range-track {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  height: 4px;
  left: 0;
  right: 0;
  background: #e0e4ec;
  border-radius: 2px;
  pointer-events: none;
}
.oh-range-fill {
  position: absolute;
  top: 0;
  height: 100%;
  background: #32143f;
  border-radius: 2px;
}
input.oh-range {
  position: absolute;
  width: 100%;
  height: 24px;
  top: 0;
  background: transparent;
  -webkit-appearance: none;
  appearance: none;
  pointer-events: none;
  margin: 0;
  padding: 0;
  outline: none;
}
input.oh-range::-webkit-slider-thumb {
  -webkit-appearance: none;
  pointer-events: all;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #32143f;
  cursor: pointer;
  border: 2px solid #fff;
  box-shadow: 0 1px 4px rgba(0,0,0,0.25);
}
input.oh-range::-moz-range-thumb {
  pointer-events: all;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: #32143f;
  cursor: pointer;
  border: 2px solid #fff;
  box-shadow: 0 1px 4px rgba(0,0,0,0.25);
}

.oh-search {
  flex: 1 1 200px;
  min-width: 120px;
  padding: 9px 14px 9px 36px;
  border: 1.5px solid #d0d4dc;
  border-radius: 8px;
  font-family: inherit;
  font-size: 16px;
  background: #f8f9fc url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2.5'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.35-4.35'/%3E%3C/svg%3E") 10px center/16px no-repeat;
  outline: none;
}
.oh-search:focus { border-color: #E098FF; }

.oh-select {
  padding: 9px 12px;
  border: 1.5px solid #d0d4dc;
  border-radius: 8px;
  font-family: inherit;
  font-size: 16px;
  background: #f8f9fc;
  outline: none;
  cursor: pointer;
  min-width: 140px;
}
.oh-select:focus { border-color: #E098FF; }

.oh-count {
  font-size: 14px;
  color: #666;
  white-space: nowrap;
  margin-left: auto;
  padding: 8px 14px;
  background: #f0e8f6;
  border-radius: 999px;
  line-height: 1.2;
}
.oh-count strong { color: #32143f; }

/* VIEW TOGGLE */

/* MAIN CONTENT AREA */
.oh-main {
  max-width: 1400px;
  margin: 0 auto;
  padding: 28px 20px 0;
}

/* QUICK SORT — sits at the top of the grey grid area, right below the
   lavender count bar, so sort is reachable without scrolling back up
   to the full filter panel. */
.oh-quick-sort {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 18px;
}
.oh-quick-sort-label {
  font-size: 13px;
  font-weight: 600;
  color: #5a3a7a;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin-right: 2px;
}
/* Below desktop: scroll horizontally in one row instead of wrapping,
   same pattern as #oh-day-chips / #oh-time-chips. */
@media (max-width: 1139px) {
  .oh-quick-sort {
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .oh-quick-sort::-webkit-scrollbar { display: none; }
  .oh-quick-sort-label { flex-shrink: 0; }
}

/* GRID */
.oh-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 22px;
}
@media (max-width: 1139px) { .oh-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 719px) { .oh-grid { grid-template-columns: 1fr; } }

/* Desktop (>=1000px): hide the mobile chip rows + sort label so the
   typed inputs stay primary. See the matching <=999px block further down
   that demotes search/sort, swaps inputs for chips, and reorders rows. */
@media (min-width: 1140px) {
  .oh-mobile-chips,
  .oh-sort-mobile-label { display: none !important; }
  /* Demote the desktop search bar from full-row-width to a sensible
     fixed width so the sort dropdown, reset, and count have visual
     presence on the right. */
  .oh-controls-row1 .oh-search { flex: 0 1 320px; max-width: 320px; }

  /* "Pick when to see homes" row: header + subtitle stack in the left
     column with day chips next to them on the right. Time chips drop
     to their own full-width row below. */
  .oh-section-row-time {
    display: grid;
    grid-template-columns: auto 1fr;
    grid-template-areas:
      "header   day"
      "subtitle day"
      "time     time";
    column-gap: 28px;
    row-gap: 2px;
    align-items: start;
  }
  .oh-section-row-time { row-gap: 2px; }
  .oh-section-row-time .time-spacer { display: none; }
  /* Bigger gap between the subtitle and the time chip row below.
     The header→subtitle gap is tight (2px); time gets its own breathing
     room because it's a different visual unit. */
  .oh-section-row-time .oh-frow:not(#oh-row-a) { margin-top: 14px; }
  .oh-section-row-time .oh-section-header { grid-area: header; margin: 0; }
  .oh-section-row-time .oh-section-subtitle { grid-area: subtitle; margin: 0; max-width: 320px; }
  .oh-section-row-time #oh-row-a { grid-area: day; align-self: center; }
  .oh-section-row-time .oh-frow:not(#oh-row-a) { grid-area: time; min-width: 0; }
  .oh-section-row-time .oh-frow { border-top: none; padding: 0; }
  .oh-section-row-time .oh-filter-group { gap: 4px; }
  .oh-section-row-time .oh-chips {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .oh-section-row-time .oh-chips::-webkit-scrollbar { display: none; }
  /* Time group must fill the grid cell so chips have a bounded width to scroll */
  #oh-time-group { flex: 1 1 0; min-width: 0; }
  #oh-time-chips { width: 100%; min-width: 0; }

  /* "Set your budget and area" row: same pattern as the time row —
     header + subtitle on the left, Price (min/max) on the right, City
     chips on their own row below. */
  .oh-section-row-home {
    display: grid;
    grid-template-columns: minmax(auto, 260px) 1fr;
    grid-template-areas:
      "header   price"
      "subtitle price"
      "city     city";
    column-gap: 28px;
    row-gap: 2px;
    align-items: start;
  }
  .oh-section-row-home .oh-section-header { grid-area: header; margin: 0; }
  .oh-section-row-home .oh-section-subtitle { grid-area: subtitle; margin: 0; max-width: 320px; }
  .oh-section-row-home #oh-row-b { grid-area: price; align-self: center; }
  .oh-section-row-home .oh-frow:not(#oh-row-b) { grid-area: city; min-width: 0; margin-top: 14px; }

  /* "Plan your route" row: title block (header + subtitle stacked
     tight) on the left, route content (circles + Plan my route button
     stacked) inline right next to it. Both flex items align to top so
     the title stays snug regardless of how tall the route column gets. */
  .oh-section-row-route {
    display: flex;
    align-items: flex-start;
    gap: 28px;
  }
  .oh-section-row-route .oh-section-title-block {
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex: 0 1 auto;
  }
  .oh-section-row-route .oh-section-header { margin: 0; line-height: 1.15; }
  .oh-section-row-route .oh-section-subtitle { margin: 0; max-width: 320px; line-height: 1.35; }
  .oh-section-row-route .oh-route-cta { flex: 0 0 auto; padding: 0; width: auto; }
  /* Circles + Plan my route button sit inline, tight together. */
  .oh-section-row-route .oh-route-cta-inner {
    flex-direction: row;
    align-items: center;
    flex-wrap: nowrap;
    gap: 16px;
  }
  .oh-section-row-route .oh-route-cta-plan-btn { margin-left: 0; }
}

@media (min-width: 1140px) and (max-width: 1319px) {
  .oh-stop-label { display: none; }
  .oh-stop-label::after { content: ''; }
}

/* CARD */
.oh-card {
  background: #fff;
  border-radius: 14px;
  overflow: hidden;
  box-shadow: 0 2px 10px rgba(0,0,0,0.09);
  display: flex;
  flex-direction: column;
  transition: transform 0.18s, box-shadow 0.18s;
  /* The whole card is a tap target now (opens the listing modal).
     Buttons inside override this with their own cursor styles. */
  cursor: pointer;
}
.oh-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 8px 24px rgba(0,0,0,0.14);
}
.oh-card--team {
  border: 3px solid #E8A820;
  background: #FFFBF0;
  box-shadow: 0 2px 10px rgba(232,168,32,0.25);
}
.oh-card--team:hover {
  box-shadow: 0 8px 24px rgba(232,168,32,0.35);
}
.oh-card--abode {
  border: 3px solid #E098FF;
  background: #FAF7FC;
  box-shadow: 0 2px 10px rgba(224,152,255,0.2);
}
.oh-card--abode:hover {
  box-shadow: 0 8px 24px rgba(224,152,255,0.35);
}

.oh-photo-wrap {
  position: relative;
  width: 100%;
  padding-top: 56.25%; /* 16:9 */
  overflow: hidden;
  background: #d5dce8;
}
.oh-photo-wrap a {
  position: absolute; inset: 0;
  display: block;
}
.oh-photo-wrap > a img,
.oh-photo-wrap > img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 0.3s;
}
.oh-card:hover .oh-photo-wrap > a img,
.oh-card:hover .oh-photo-wrap > img { transform: scale(1.04); }

/* Photo carousel arrows */
.oh-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  background: rgba(0,0,0,0.45);
  color: #fff;
  border: none;
  border-radius: 5px;
  width: 28px;
  height: 38px;
  font-size: 15px;
  cursor: pointer;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0.55;   /* always visible but subtle; brightens on hover */
  transition: opacity 0.15s, background 0.15s;
  padding: 0;
  line-height: 1;
}
.oh-photo-wrap:hover .oh-arrow { opacity: 1; }
.oh-arrow:hover { background: rgba(0,0,0,0.7); }
/* Generous invisible click target — extends the hit area 60px above and
   below the visible 38px-tall button, and 12px on each side. The visual
   button stays the same size; users just don't have to land precisely
   on it. position:absolute keeps the pseudo out of the button's flex
   flow so the arrow character stays centered. */
.oh-arrow::before {
  content: '';
  position: absolute;
  top: -60px; bottom: -60px;
  left: -12px; right: -12px;
  background: transparent;
}
.oh-arrow--prev { left: 6px; }
.oh-arrow--next { right: 6px; }
.oh-photo-count {
  position: absolute;
  bottom: 8px;
  right: 8px;
  background: rgba(0,0,0,0.5);
  color: #fff;
  font-size: 11px;
  padding: 2px 7px;
  border-radius: 10px;
  z-index: 10;
  pointer-events: none;
  letter-spacing: 0.5px;
}

/* Badge overlay on photo */
.oh-badge {
  position: absolute;
  top: 10px; left: 10px;
  padding: 4px 10px;
  border-radius: 20px;
  font-size: 11px;
  font-weight: bold;
  letter-spacing: 0.5px;
  z-index: 1;
}
.oh-badge-abode {
  background: #32143f;
  color: #E098FF;
  border: 1px solid #E098FF;
}
.oh-badge-team {
  background: #E8A820;
  color: #fff;
}

/* Freshness pill — top-right of the photo, opposite .oh-badge, so a card can
   carry both a Team/ABODEslc badge and a "just posted" pill without collision.
   Same geometry as .oh-badge so the two read as siblings. Only rendered while
   the open house is genuinely new (see ohPostedPill in app.js). */
.oh-fresh-pill {
  position: absolute;
  top: 10px; right: 10px;
  padding: 4px 10px;
  border-radius: 20px;
  font-size: 11px;
  font-weight: bold;
  letter-spacing: 0.5px;
  background: rgba(0,0,0,0.5);
  color: #fff;
  z-index: 1;
  pointer-events: none;   /* the whole photo is the tap target */
  white-space: nowrap;
}
/* Under 24 hours old — accent colors, plus a slow glow so new arrivals catch
   the eye while scanning the grid. Deliberately gentle: a dozen of these can
   animate at once in a full grid. */
.oh-fresh-pill--hot {
  background: #E098FF;
  color: #32143f;
}
@media (prefers-reduced-motion: no-preference) {
  .oh-fresh-pill--hot {
    animation: oh-fresh-glow 2.6s ease-in-out infinite;
  }
}
@keyframes oh-fresh-glow {
  0%, 100% { box-shadow: 0 0 0 0 rgba(224,152,255,0.55); }
  50%      { box-shadow: 0 0 10px 2px rgba(224,152,255,0.55); }
}

/* Team note overlay at bottom of photo */
.oh-photo-note {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  background: rgba(232, 168, 32, 0.95);
  backdrop-filter: blur(4px);
  padding: 6px 14px 6px 98px;
  min-height: 52px;
  display: flex;
  align-items: center;
  font-size: 13px;
  line-height: 1.6;
  color: #fff;
  z-index: 1;
  overflow: visible;
}
.oh-photo-note--abode {
  background: rgba(224, 152, 255, 0.97);
  padding: 10px 14px;
  min-height: auto;
  justify-content: center;
  font-size: 14px;
  font-weight: bold;
  letter-spacing: 0.3px;
  color: #32143f;
}

/* Card body */
.oh-card-body {
  padding: 16px 18px 12px;
  flex: 1;
  display: flex;
  flex-direction: column;
}
.oh-card-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 8px;
  margin: 0 0 2px;
}
.oh-card-header .oh-address { margin: 0; flex: 1; }
.oh-card-header .oh-dom-tag { margin: 3px 0 0; flex-shrink: 0; }
.oh-card-meta {
  display: flex;
  flex-direction: column;
  gap: 3px;
  align-items: flex-start;
  margin: 0 0 0;
}
.oh-card-meta .oh-price { margin: 0; }
.oh-card-meta .oh-details { margin: 0; text-align: left; font-size: 13px; color: #888; }

/* Stat row (Beds / Baths / Sq Ft / Days on Market) — single filled
   lavender strip with four columns inside. Lighter visual weight than
   four separate boxes; still scannable because each value sits above
   its uppercase label. Faint dividers between cells keep the columns
   readable without adding hard rectangles. */
.oh-card-stats {
  display: grid;
  /* Price gets the lion's share so the full "$3,250,000" fits without
     ellipsis. Bed/Bath need very little (single digits) so they pinch
     down to 0.7fr. Sqft still gets 1.2fr for "10,400". */
  grid-template-columns: 3fr 0.7fr 0.7fr 1.2fr;
  background: #f5f0fc;
  border-radius: 8px;
  padding: 7px 2px;
  margin: 6px 0 10px;
}
.oh-stat {
  display: flex;
  flex-direction: column;
  justify-content: center;  /* vertically center val + label as a group */
  padding: 0 2px;            /* tighter so spec cells don't waste width */
  text-align: center;
  min-width: 0;
  border-right: 1px solid rgba(122, 79, 154, 0.15);
}
.oh-stat:last-child { border-right: none; }
/* Price cell has no label, so the value sits dead-center on its own.
   Larger font than the spec cells to keep it the visual anchor.
   clamp() lets the value shrink on narrow cards (3-col desktop or 2-col
   mid-viewport) so "$3.25M" / "7,005" don't get ellipsised. The card
   layouts at the breakpoint between 3-col and 2-col give cards in the
   260-300px width range — that's where the values used to crush. */
.oh-stat--price .oh-stat-val { font-size: clamp(16px, 1.7vw, 22px); }
.oh-stat-val {
  display: block;
  font-size: clamp(13px, 1.25vw, 16px);
  font-weight: bold;
  color: #32143f;
  line-height: 1.1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.oh-stat-lbl {
  display: block;
  font-size: clamp(8px, 0.7vw, 9px);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: #7a4f9a;
  margin-top: 3px;
  white-space: nowrap;
}

/* ── Listing card layout (grid cards only — modal / route-stop reuse of
   .oh-card-stats keep their existing grid styling above). The card body
   reads top-to-bottom as: address + "View on map" link, city, then a
   single-line stat row (price • beds • baths • sq ft), then a full-width
   pill button that combines the open house day/time with the "Add to
   route" action. ── */
.oh-grid article .oh-card-body {
  padding: 14px 16px 14px;
  gap: 6px;
}
.oh-grid article .oh-card-header { gap: 10px; margin: 0; }
.oh-grid article .oh-card-map-link {
  flex: 0 0 auto;
  background: transparent;
  border: none;
  padding: 0;
  cursor: pointer;
  font-size: 13px;
  font-weight: 700;
  color: #6B2BC4;
  white-space: nowrap;
}
.oh-grid article .oh-card-map-link:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}
.oh-grid article .oh-city { margin: 0; }
.oh-grid article .oh-card-stats {
  display: flex;
  align-items: baseline;
  gap: 6px;
  flex-wrap: nowrap;
  background: transparent;
  border-radius: 0;
  padding: 4px 0 0;
  margin: 8px 0 0;
}
.oh-grid article .oh-stat {
  display: inline-flex;
  flex-direction: row;
  align-items: baseline;
  gap: 4px;
  padding: 0;
  border-right: none;
  text-align: left;
}
.oh-grid article .oh-stat-val {
  display: inline;
  font-size: 13px;
  font-weight: 700;
  color: rgba(50, 20, 63, 0.85);
  line-height: 1;
}
.oh-grid article .oh-stat-lbl {
  display: inline;
  font-size: 11px;
  font-weight: 500;
  text-transform: lowercase;
  letter-spacing: 0;
  color: rgba(50, 20, 63, 0.55);
  margin-top: 0;
  line-height: 1;
}
.oh-grid article .oh-stat--price .oh-stat-val {
  font-size: 18px;
  font-weight: 800;
  color: #32143f;
  margin-right: 4px;
}

/* Add-to-Route pill button: full-width, mirrors the filter chip palette.
   When the listing is in the route, fills with the saturated lavender +
   flips the CTA copy to "✓ Added to route" (handled in app.js). */
.oh-grid article .oh-card-add-route {
  order: 4;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  margin: 10px 0 0;
  padding: 10px 14px;
  background: #F5F0FC;
  border: 1px solid #DCC8F5;
  border-radius: 12px;
  cursor: pointer;
  color: #32143f;
  font: inherit;
  transition: background 0.15s, border-color 0.15s;
}
.oh-grid article .oh-card-add-route:hover {
  background: #E098FF;
  border-color: #E098FF;
}
.oh-grid article .oh-card-add-route.is-added {
  background: #E098FF;
  border-color: #E098FF;
}
.oh-grid article .oh-card-add-time {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  font-weight: 700;
  min-width: 0;
}
.oh-grid article .oh-card-add-slot {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
}
.oh-grid article .oh-card-add-day {
  color: #6B2BC4;
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.oh-grid article .oh-card-add-hours {
  color: #32143f;
  font-size: 13px;
}
.oh-grid article .oh-card-add-sep {
  color: rgba(50, 20, 63, 0.35);
  padding: 0 2px;
}
.oh-grid article .oh-card-add-cta {
  flex: 0 0 auto;
  font-weight: 700;
  font-size: 13px;
  color: #6B2BC4;
  white-space: nowrap;
}
.oh-grid article .oh-card-add-route.is-added .oh-card-add-cta,
.oh-grid article .oh-card-add-route.is-added .oh-card-add-day { color: #32143f; }
@media (max-width: 1139px) {
  /* "+ Add to route" / "✓ Added to route" trims to "+ Add" / "✓ Added"
     on mobile so the pill doesn't overflow on narrow cards. The full
     phrasing stays in the aria-label for screen readers. */
  .oh-grid article .oh-card-add-cta-suffix { display: none; }
}
.oh-dom-tag {
  display: inline-block;
  margin-left: 6px;
  padding: 3px 8px;
  background: #f0eaf8;
  color: #7a4f9a;
  border-radius: 4px;
  font-size: 12px;
  font-weight: bold;
  letter-spacing: 0.3px;
  vertical-align: middle;
  white-space: nowrap;
}
.oh-address {
  font-size: 16px;
  font-weight: bold;
  color: #32143f;
  margin: 0 0 1px;
  line-height: 1.3;
}
.oh-city {
  font-size: 13px;
  font-weight: 600;
  color: #aaa;
  margin: 0 0 8px;
}
.oh-price {
  font-size: 22px;
  font-weight: bold;
  color: #32143f;
  margin: 0;
}
.oh-details {
  font-size: 14px;
  font-weight: 600;
  color: #888;
  margin: 0;
}
.oh-mls {
  font-size: 11px;
  color: #ccc;
  margin: 0 0 4px;
}
.oh-times {
  /* Date sits BELOW city and ABOVE stats now. No border-top — used to
     have a line that separated times from the rest, but with the new
     order that line read as cutting the card content in half. */
  margin: 4px 0 8px;
  flex: 0 0 auto;
}
.oh-time-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 0 0 5px; }
.oh-time-pill {
  display: inline;
  padding: 0;
  background: none;
  color: #555;
  border-radius: 0;
  font-size: 15px;
  font-weight: bold;
  white-space: nowrap;
}
.oh-cal-btn {
  display: inline-block;
  padding: 3px 9px;
  background: #ECE4F2;
  border: 1px solid #E098FF;
  border-radius: 4px;
  font-size: 12px;
  color: #32143f;
  text-decoration: none;
  white-space: nowrap;
  font-weight: normal;
  vertical-align: middle;
}
.oh-cal-btn:hover { background: #E098FF; color: #fff; }

.oh-mls-btn {
  display: block;
  width: 100%;
  margin: 0 0 8px;
  padding: 10px 18px;
  background: #fff;
  color: #32143f;
  border: 1.5px solid #32143f;
  border-radius: 8px;
  font-family: 'Century Gothic', 'CenturyGothicPaneuropean', Arial, Helvetica, sans-serif;
  font-size: 15px;
  font-weight: bold;
  text-align: center;
  cursor: pointer;
  text-decoration: none;
  transition: background 0.2s, color 0.2s;
}
.oh-card-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  width: 100%;
  max-width: 280px;
  margin: 0 auto 8px;
}
.oh-card-actions > button { flex: 1 1 0; min-width: 0; }

/* Mini action icons inline with the address — map (left) + heart
   (right) sit at the top-right of the card body, immediately below
   the photo. Each is a small square-ish button with a soft purple-tint
   bg; active states flip the bg to lavender. */
.oh-card-mini-actions {
  display: flex;
  gap: 6px;
  flex-shrink: 0;
  margin: 0;
}
.oh-card-icon-btn {
  width: 34px;
  height: 30px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: #fff;
  border: 1.5px solid rgba(50,20,63,0.18);
  border-radius: 8px;
  padding: 0;
  cursor: pointer;
  color: #32143f;
  transition: background 0.15s, border-color 0.15s, transform 0.1s;
}
.oh-card-icon-btn:hover {
  background: #FAF4FF;
  border-color: rgba(50,20,63,0.45);
}
.oh-card-icon-btn:active { transform: scale(0.95); }
.oh-card-icon-btn.is-active {
  background: rgba(224,152,255,0.45);
  border-color: #32143f;
}
.oh-card-icon-btn.oh-map-view-active {
  background: rgba(224,152,255,0.45);
  border-color: #32143f;
}
.oh-card-map-btn {
  width: auto;
  padding: 0 10px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.02em;
}
/* Heart inside the card heart button. Outlined when unselected; filled
   lavender when in route — matches the CTA hearts exactly. */
.oh-card-heart-svg { width: 18px; height: 18px; display: block; }
.oh-card-heart-btn .oh-card-heart-svg path {
  fill: none;
  stroke: rgba(50,20,63,0.55);
  stroke-width: 1.8;
}
.oh-card-heart-btn.is-active .oh-card-heart-svg path {
  fill: #E098FF;
  stroke: #32143f;
  stroke-width: 1.2;
}
/* Map icon — currentColor stroke so it picks up the button's color. */
.oh-card-map-svg { width: 18px; height: 18px; display: block; }

.oh-map-btn {
  display: block;
  padding: 6px 8px;
  border-radius: 6px;
  font-size: 12px;
  font-weight: bold;
  font-family: inherit;
  text-align: center;
  text-decoration: none;
  border: 1.5px solid #32143f;
  color: #32143f;
  background: #fff;
  cursor: pointer;
  transition: background 0.2s, color 0.2s;
}
.oh-map-btn.oh-map-view-active { background: #32143f; color: #fff; border-color: #32143f; }
@media (hover: hover) {
  .oh-map-btn:hover { background: #32143f; color: #fff; }
  .oh-map-btn.oh-map-view-active:hover { background: #5a2a70; border-color: #5a2a70; }
}
.oh-mls-btn:hover { background: #32143f; color: #fff; }

/* Share button — sits below "See More Info" */
.oh-share-btn {
  display: block;
  padding: 6px 8px;
  background: #fff;
  color: #7a5200;
  border: 1.5px solid #E8A820;
  border-radius: 6px;
  font-family: inherit;
  font-size: 12px;
  font-weight: bold;
  text-align: center;
  cursor: pointer;
  transition: background 0.2s, color 0.2s, border-color 0.2s;
}
@media (hover: hover) {
  .oh-share-btn:hover { background: #E8A820; color: #32143f; }
}

/* Toast — used for "Link copied" and "Added to route" confirmations.
   Optionally contains an inline action link (.oh-toast-action). */
#oh-share-toast {
  position: fixed; left: 50%; bottom: 28px; transform: translate(-50%, 20px);
  background: #32143f; color: #fff; padding: 10px 16px; border-radius: 8px;
  font-size: 14px; font-family: inherit; box-shadow: 0 6px 24px rgba(50,20,63,0.25);
  opacity: 0; pointer-events: none; transition: opacity 0.2s, transform 0.2s;
  z-index: 9999;
  display: inline-flex; align-items: center; gap: 12px;
}
#oh-share-toast.show { opacity: 1; transform: translate(-50%, 0); pointer-events: auto; }
.oh-toast-action {
  color: #E098FF;
  font-weight: bold;
  text-decoration: none;
  white-space: nowrap;
  border-left: 1px solid rgba(255,255,255,0.18);
  padding-left: 12px;
}
.oh-toast-action:hover { color: #fff; }

/* Route planner card button */
.oh-route-btn {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 6px 10px;
  background: #fff;
  color: #d04a6b;
  border: 1.5px solid #f4b6c4;
  border-radius: 6px;
  font-family: inherit;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  text-decoration: none;
  transition: background 0.2s, color 0.2s, border-color 0.2s, transform 0.1s;
}
.oh-route-btn:hover { background: #fdeef2; }
.oh-route-btn:active { transform: scale(0.94); }
.oh-route-btn.in-route {
  background: #fff;
  color: #d04a6b;
  border-color: #d04a6b;
}
.oh-route-btn.in-route:hover { background: #fdeef2; }
.oh-route-btn.route-full { opacity: 0.45; cursor: not-allowed; }

/* Route Planner page — full-page layout (was a fixed footer tray).
   Inner element IDs and most descendant rules are preserved so the
   render code didn't need to be renamed everywhere. */
#oh-route-page {
  background: #32143f;
  color: #fff;
  font-family: 'Century Gothic', 'CenturyGothicPaneuropean', Arial, Helvetica, sans-serif;
  min-height: calc(100vh - 200px);
  padding: 32px 0 64px;
}
/* The shared .oh-wrap has a gray background + 48px bottom padding that
   was bleeding out below the purple route page. When the route page is
   the wrap's child, match the wrap's background to the route page and
   zero its bottom padding so the purple fills to the page bottom. */
.oh-wrap:has(#oh-route-page) {
  background: #32143f;
  padding-bottom: 0;
}
body:has(#oh-route-page) { background: #32143f; }
#oh-route-tray-body {
  max-width: 1400px;
  margin: 0 auto;
  padding: 0 24px;
  display: flex;
  flex-direction: column;
  gap: 18px;
}
#oh-route-empty {
  text-align: left;
  padding: 60px 24px;
  color: rgba(255,255,255,0.7);
}
#oh-route-empty p {
  font-size: 16px;
  margin: 0 0 18px;
  text-align: center;
}
#oh-route-empty a {
  display: inline-block;
  padding: 10px 22px;
  background: #E098FF;
  color: #32143f;
  border-radius: 999px;
  font-weight: bold;
  text-decoration: none;
}
#oh-route-empty a:hover { background: #fff; }
/* Single-column itinerary layout: summary → stops → reasoning → actions,
   centered, max 820px. Reads top-to-bottom like a printed plan. */
#oh-route-layout {
  display: flex;
  flex-direction: column;
  gap: 20px;
  max-width: 820px;
  margin: 0 auto;
  width: 100%;
}
/* Header summary chip — the titular at-a-glance line of the itinerary. */
#oh-route-summary {
  text-align: center;
  font-size: 20px;
  color: rgba(255,255,255,0.82);
  letter-spacing: 0.2px;
  line-height: 1.5;
  padding: 8px 16px 16px;
}
@media (min-width: 720px) {
  #oh-route-summary { font-size: 22px; }
}
#oh-route-summary strong {
  color: #E098FF;
  font-weight: bold;
}
.oh-route-summary-pending {
  font-style: italic;
  font-size: 0.9em;
  color: rgba(255,255,255,0.5);
}

/* Visit-duration slider + schedule analysis + optimize controls all
   in one card at the top of the planner. Width matches the stop cards
   below it for clean vertical alignment down the column. */
#oh-route-pace {
  width: 100%;
  padding: 14px 18px;
  background: rgba(224,152,255,0.06);
  border: 1px solid rgba(224,152,255,0.18);
  border-radius: 12px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.oh-route-pace-slider-wrap {
  display: flex;
  flex-direction: column;
}
/* Slider lives on one tidy row centered in the card. The label sits on
   the left, then Quick · slider · Thorough as one inline group, then the
   live value chip on the right — tight gaps so it doesn't sprawl across
   the whole card width. */
.oh-route-pace-label-text { white-space: nowrap; }
.oh-route-pace-control {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  row-gap: 10px;
  background: rgba(0,0,0,0.18);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: 20px;
  /* Extra horizontal padding so the 30px thumb at min/max positions
     doesn't kiss the pill edge — the thumb's outer radius is ~15px,
     so 18px padding keeps a small visual breathing margin. */
  padding: 8px 18px 10px;
  min-width: 200px;
  width: 100%;
  max-width: 360px;
  box-sizing: border-box;
}
.oh-route-pace-end {
  font-size: 10.5px;
  font-weight: bold;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: rgba(255,255,255,0.45);
  white-space: nowrap;
  flex: 1 1 50%;
}
/* Slider forced to its own full-width row via flex-basis 100%; order:-1
   so it renders BEFORE the two end labels even though they come first
   in source. The two ends share row 2 with text-align driving the
   left/right placement. */
.oh-route-pace-control #oh-route-pace-slider {
  order: -1;
  flex: 1 0 100%;
  width: 100%;
  margin: 0;
}
.oh-route-pace-end:first-of-type { text-align: left; }
.oh-route-pace-end:last-of-type  { text-align: right; }
.oh-route-pace-actions {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: center;
}
/* When neither button has reason to show, hide the row entirely so
   the slider/alert card doesn't have an empty footer. */
.oh-route-pace-actions:has(button:not([style*="display: none"])) { /* no-op selector, container always renders */ }
#oh-route-pace #oh-route-reasoning {
  margin: 0;
  padding: 0;
  font-size: 13.5px;
  text-align: left;
  max-width: none;
}
.oh-route-pace-label {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 12px;
  font-size: 13px;
  color: rgba(255,255,255,0.7);
  margin: 0;
  letter-spacing: 0.2px;
}
/* Source order is: text, control, value. We want the visual layout
   to be: [text  ·  value]  /  [control] — i.e. "Time at each stop"
   and "45 min" share row 1, the slider pill takes row 2 by itself. */
.oh-route-pace-label .oh-route-pace-label-text { order: 0; }
.oh-route-pace-label .oh-route-pace-value      { order: 1; }
.oh-route-pace-label .oh-route-pace-control    { order: 2; flex: 1 0 100%; }
.oh-route-pace-value {
  color: #E098FF;
  font-weight: bold;
  font-size: 14px;
  min-width: 56px;
  text-align: left;
  white-space: nowrap;
}
/* The slider input itself is just the touch zone — height generous so
   the thumb has vertical breathing room above and below the labels.
   The visible TRACK is styled via the pseudo-elements below so it's
   a clearly visible bar, not the input's background (which was getting
   eaten by various browser defaults). */
#oh-route-pace-slider {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 36px;
  background: transparent;
  outline: none;
  margin: 0;
  padding: 0;
  cursor: pointer;
}
#oh-route-pace-slider::-webkit-slider-runnable-track {
  height: 8px;
  background: rgba(224,152,255,0.45);
  border-radius: 4px;
}
#oh-route-pace-slider::-moz-range-track {
  height: 8px;
  background: rgba(224,152,255,0.45);
  border-radius: 4px;
}
/* Bumped thumb to 30px for a comfortable touch target on phones.
   The visible "puck" stays 18px-equivalent via the layered border;
   the rest of the 30×30 surface is the invisible hit-zone the
   browser uses for finger taps and drags. */
#oh-route-pace-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 30px; height: 30px;
  border-radius: 50%;
  background: #E098FF;
  border: 3px solid #fff;
  cursor: pointer;
  box-shadow: 0 1px 6px rgba(0,0,0,0.35);
  /* Re-center the 30px thumb on the 8px track (WebKit positions the
     thumb's top at the track's top by default). */
  margin-top: -11px;
}
#oh-route-pace-slider::-moz-range-thumb {
  width: 30px; height: 30px;
  border-radius: 50%;
  background: #E098FF;
  border: 3px solid #fff;
  cursor: pointer;
  box-shadow: 0 1px 6px rgba(0,0,0,0.35);
}

/* Stops always stacked vertically now, on every viewport.
   Mobile (default): vertical card — photo on top, info below.
   Desktop (≥700px): horizontal card — photo dominates the left side
   (≈65% of card width), info compact column on the right. Big photo
   is the whole point. */
#oh-route-stops {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0;
  width: 100%;
}
.oh-route-stop {
  background: rgba(255,255,255,0.06);
  border: 1px solid rgba(224,152,255,0.22);
  border-radius: 14px;
  padding: 0;
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: border-color 0.2s, box-shadow 0.2s;
}
/* Title bar nested inside the info column. Two rows: top row has
   stop number · address · city + Lock + Remove (×); bottom row has
   compact home info (price · bd · ba · sqft). Open-window time is
   intentionally NOT here — it lives in the narration's "Open X–Y"
   sentence to avoid duplication. No dark background band anymore
   since this is now a section of the info column, not a full-card
   header banner. */
.oh-route-stop-bar {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 0 0 8px;
  margin: 0 0 8px;
  background: transparent;
  border-bottom: 1px solid rgba(224,152,255,0.18);
  color: #fff;
  line-height: 1.3;
}
.oh-route-stop-bar-top {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13.5px;
}
.oh-route-stop-bar-num {
  font-weight: bold;
  letter-spacing: 1px;
  text-transform: uppercase;
  font-size: 11.5px;
  color: #E098FF;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  flex-shrink: 0;
}
.oh-route-stop-bar-num.stop-one { color: #E8A820; }
.oh-route-stop-bar-sep {
  color: rgba(255,255,255,0.3);
  flex-shrink: 0;
}
/* Address row sits BELOW the Stop N + Lock + × row, so the address
   has the full info-column width to breathe rather than competing
   with the action buttons for space. */
.oh-route-stop-bar-addr-row {
  display: flex;
  align-items: baseline;
  gap: 6px;
  font-size: 13.5px;
  flex-wrap: wrap;
}
.oh-route-stop-bar-addr {
  font-weight: bold;
  color: #fff;
  flex: 0 1 auto;
  min-width: 0;
}
.oh-route-stop-bar-city {
  color: rgba(255,255,255,0.78);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 0 1 auto;
  min-width: 0;
}
.oh-route-stop-bar-stats {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  font-size: 12.5px;
  color: rgba(255,255,255,0.72);
  letter-spacing: 0.2px;
}
.oh-route-stop-bar-stats > span:first-child {
  color: #E098FF;
  font-weight: bold;
}
.oh-route-stop-bar-top .oh-route-stop-lock {
  margin-left: auto;
  flex-shrink: 0;
}
/* Below the title bar: photo + info side by side on desktop, stacked
   on mobile. */
.oh-route-stop-grid {
  display: flex;
  flex-direction: column;
}
@media (min-width: 720px) {
  .oh-route-stop-grid {
    /* Info column on the LEFT, photo on the RIGHT — row-reverse keeps
       photo as the second child in the DOM (so mobile stacks correctly
       with photo on top) while flipping visual order on desktop. */
    flex-direction: row-reverse;
    align-items: stretch;
  }
}
/* Persistent locked-as-Stop-1 state — gold border + soft gold halo so
   it's obvious which stop is anchored. Replaces the brief flash. */
.oh-route-stop.oh-stop-pinned {
  border-color: #E8A820;
  box-shadow: 0 0 0 1px rgba(232,168,32,0.35), 0 4px 18px rgba(232,168,32,0.12);
}
.oh-route-stop-photo {
  position: relative;
  width: 100%;
  padding-top: 75%;            /* 4:3 — matches URE's native 640×480 source so no awkward crop */
  background: rgba(0,0,0,0.2);
  overflow: hidden;
}
.oh-route-stop-photo img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
}
/* Time column (mobile: full-width strip above photo with stop badge + range) */
.oh-route-stop-time-col {
  padding: 12px 14px 8px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.oh-route-stop-time-range {
  display: flex;
  align-items: baseline;
  gap: 6px;
  font-size: 14px;
  color: rgba(255,255,255,0.85);
  font-weight: bold;
}
.oh-route-stop-time-pt { white-space: nowrap; }
.oh-route-stop-time-sep { color: rgba(255,255,255,0.4); }
.oh-route-stop-time-fallback {
  font-size: 12px;
  color: rgba(255,255,255,0.7);
}
/* Info column (mobile: address etc. below photo) */
.oh-route-stop-info {
  padding: 10px 14px 14px;
  position: relative;
}
/* Per-stop narration — small italic helper text explaining the timing
   experience ("Stop 2 opens at noon. For a ~20-min visit, start
   between 10:00 AM and 11:10 AM…"). */
.oh-route-stop-narrate {
  margin-top: 10px;
  font-size: 14px;
  font-style: italic;
  color: rgba(255,255,255,0.65);
  line-height: 1.5;
}
/* "Open X–Y." sits on its own line above the planning sentence. */
.oh-route-stop-narrate-open {
  margin-bottom: 6px;
  font-style: normal;
}
.oh-route-stop-narrate strong {
  color: rgba(255,255,255,0.92);
  font-style: normal;
  font-weight: bold;
}
.oh-route-stop-narrate.tight {
  color: rgba(255,200,0,0.78);
}
/* Lock-as-Stop-1 icon button. Lives at the bottom of the time column.
   Filled gold when this stop is pinned, muted when not. */
.oh-route-stop-lock {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: transparent;
  border: 1px solid rgba(255,255,255,0.15);
  border-radius: 999px;
  padding: 5px 10px 5px 8px;
  color: rgba(255,255,255,0.55);
  font-family: inherit;
  font-size: 11px;
  font-weight: bold;
  letter-spacing: 0.2px;
  cursor: pointer;
  text-transform: none;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.oh-route-stop-lock:hover {
  background: rgba(255,255,255,0.06);
  color: #fff;
  border-color: rgba(255,255,255,0.3);
}
.oh-route-stop-lock.locked {
  color: #E8A820;
  border-color: rgba(232,168,32,0.6);
  background: rgba(232,168,32,0.08);
}
.oh-route-stop-lock.locked:hover {
  background: rgba(232,168,32,0.18);
  border-color: #E8A820;
  color: #E8A820;
}
.oh-route-stop-lock svg { flex-shrink: 0; }
/* On mobile the time strip is a horizontal row above the photo —
   hide the lock's text label there so the row doesn't get cramped. */
@media (max-width: 719px) {
  .oh-route-stop-lock { padding: 5px; }
  .oh-route-stop-lock-label { display: none; }
}

/* Route stop card reuses the listing card's .oh-card-stats / .oh-stat
   classes for the price/beds/baths/sqft strip in the info column.
   Small spacing tweak so the strip nestles between the city line and
   the narration text on dark backgrounds. */
.oh-route-stop-info .oh-card-stats {
  margin: 10px 0 6px;
}
.oh-route-stop-num {
  font-size: 12px;
  font-weight: bold;
  letter-spacing: 1px;
  color: #E098FF;
  text-transform: uppercase;
  display: flex;
  align-items: center;
  gap: 5px;
}
.oh-route-stop-num.stop-one { color: #E8A820; }
.oh-route-stop-pin-icon { opacity: 0.85; flex-shrink: 0; }
@keyframes oh-pin-flash {
  0%   { border-color: #E8A820; box-shadow: 0 0 0 3px rgba(232,168,32,0.35); }
  65%  { border-color: #E8A820; box-shadow: 0 0 10px rgba(232,168,32,0.12); }
  100% { border-color: rgba(224,152,255,0.35); box-shadow: none; }
}
.oh-stop-pinned-flash { animation: oh-pin-flash 0.75s ease-out forwards; }
.oh-route-stop-addr {
  font-size: 13px;
  font-weight: bold;
  color: #fff;
  line-height: 1.3;
  margin-bottom: 2px;
}
.oh-route-stop-city {
  font-size: 12px;
  color: rgba(255,255,255,0.6);
  line-height: 1.3;
  margin-bottom: 2px;
}
.oh-route-stop-time {
  font-size: 12px;
  color: #ccc;
}

/* Desktop: horizontal card layout — photo dominates the left, info
   column on the right. Placed AFTER the base .oh-route-stop rules so
   its overrides actually win the cascade. */
/* Desktop itinerary: 3-column row inside each card —
     [ time column | photo (centerpiece) | info ]
   Placed AFTER the base rules so its overrides win the cascade. */
@media (min-width: 720px) {
  .oh-route-stop {
    transition: transform 0.15s, box-shadow 0.15s, border-color 0.15s;
  }
  .oh-route-stop:hover {
    transform: translateY(-1px);
    border-color: rgba(224,152,255,0.35);
    box-shadow: 0 6px 24px rgba(0,0,0,0.22);
  }
  /* Title bar gets a touch more breathing room on desktop. */
  .oh-route-stop-bar {
    padding: 13px 20px;
    gap: 5px;
  }
  .oh-route-stop-bar-top { font-size: 15px; }
  .oh-route-stop-bar-num { font-size: 12px; }
  .oh-route-stop-bar-addr-row { font-size: 15px; }
  .oh-route-stop-bar-addr { font-size: 16px; }
  .oh-route-stop-bar-city { font-size: 14px; }
  .oh-route-stop-bar-stats { font-size: 13px; }
  /* Photo — centerpiece on desktop. 4:3 aspect ratio matches the
     native URE source so the image doesn't get awkwardly cropped. */
  .oh-route-stop-photo {
    flex: 0 0 50%;
    width: auto;
    padding-top: 0;
    aspect-ratio: 4 / 3;
    align-self: center;
    min-height: 0;
  }
  /* Info column on the LEFT (via row-reverse on the grid). Title bar
     + narration stack from the top — content should align to the top
     of the card, not center vertically, since the title bar is the
     visual anchor. */
  .oh-route-stop-info {
    flex: 1 1 auto;
    min-width: 0;
    /* Left padding matches the pace box's inner left edge (18px) so
       the stop address sits flush vertically with "Starting at X" in
       the reasoning above. */
    padding: 16px 20px 16px 18px;
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    gap: 4px;
  }
  .oh-route-stop-city { font-size: 14px; }
}

.oh-route-connector {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 8px 0;
  text-align: center;
}
.oh-route-connector::before {
  content: '↓';
  font-size: 16px;
  color: rgba(224,152,255,0.4);
  line-height: 1;
  margin-bottom: 2px;
}
.oh-route-connector-label {
  font-size: 13.5px;
  font-weight: bold;
  padding: 4px 12px;
  border-radius: 12px;
  white-space: nowrap;
}
.oh-route-connector-label.ok   { background: rgba(100,220,100,0.2); color: #7defa0; }
.oh-route-connector-label.warn { background: rgba(255,200,0,0.2);   color: #ffe066; }
.oh-route-connector-label.bad  { background: rgba(255,80,80,0.2);   color: #ff8080; }
.oh-route-connector-label.calc { color: rgba(255,255,255,0.7); font-weight: normal; font-style: italic; }
.oh-route-connector-sublabel {
  font-size: 12px;
  color: rgba(255,255,255,0.5);
  white-space: nowrap;
}
/* Stops are now stacked vertically on every viewport, so the connector
   arrow stays ↓ — no horizontal override needed. */
.oh-route-stop-gap {
  font-size: 11px;
  font-weight: bold;
  margin-top: 4px;
  padding: 2px 6px;
  border-radius: 4px;
  display: inline-block;
}
.oh-route-stop-gap.ok   { background: rgba(100,220,100,0.2); color: #7defa0; }
.oh-route-stop-gap.warn { background: rgba(255,200,0,0.2);   color: #ffe066; }
.oh-route-stop-gap.bad  { background: rgba(255,80,80,0.2);   color: #ff8080; }
/* × button now lives in the title bar (right of the Lock button)
   instead of floating in the photo's top-right corner. */
.oh-route-remove {
  width: 24px; height: 24px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.15);
  color: rgba(255,255,255,0.6);
  font-size: 14px;
  cursor: pointer;
  line-height: 1;
  padding: 0;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  margin-left: 6px;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.oh-route-remove:hover {
  background: rgba(220,60,60,0.55);
  color: #fff;
  border-color: rgba(220,60,60,0.7);
}
.oh-route-set-first {
  background: rgba(224,152,255,0.08);
  border: 1px solid rgba(224,152,255,0.28);
  color: rgba(224,152,255,0.55);
  font-size: 11px;
  font-weight: bold;
  cursor: pointer;
  line-height: 1;
  padding: 4px 10px;
  border-radius: 100px;
  letter-spacing: 0.3px;
  white-space: nowrap;
  font-family: 'Century Gothic', 'CenturyGothicPaneuropean', Arial, Helvetica, sans-serif;
}
@media (hover: hover) {
  .oh-route-set-first:hover { background: rgba(232,168,32,0.15); border-color: rgba(232,168,32,0.5); color: #E8A820; }
}
#oh-route-reasoning {
  font-size: 14.5px;
  color: rgba(255,255,255,0.58);
  /* Drop the centering (margin: 0 auto + max-width: 720) — it indented
     the reasoning unpredictably relative to the stop cards below. Now
     left-aligned to the pace box's inner edge so "Starting at 726..."
     anchors the same x as the card content. */
  padding: 4px 0 8px;
  font-style: italic;
  line-height: 1.55;
  white-space: pre-wrap;
  text-align: left;
}
.oh-route-emphasis {
  color: #E098FF;
  font-weight: bold;
  font-style: normal;
}
/* Fix-for-me button — sits on its own line below the conflict text
   with margin-top breathing room so it never crowds the message. When
   shown, the Reset to optimal button is hidden (see renderRouteTray)
   to avoid two "fix this" affordances. */
.oh-conflict-fix-btn {
  display: block;
  margin: 12px 0 0;
  padding: 8px 16px;
  background: #E098FF;
  color: #32143f;
  border: 1.5px solid #E098FF;
  border-radius: 20px;
  font-size: 13px;
  font-weight: bold;
  font-style: normal;
  font-family: inherit;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}
.oh-conflict-fix-btn:hover {
  background: #d070f0;
  border-color: #d070f0;
}
#oh-route-tray-actions {
  display: flex;
  flex-direction: column;
  gap: 14px;
  align-items: center;
  margin-top: 8px;
}
/* Footer action layout: primary share buttons side-by-side at center,
   utility row in a small wrap below, clear-all link last and quiet. */
.oh-route-actions-primary {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
  width: 100%;
  max-width: 560px;
}
@media (min-width: 600px) {
  .oh-route-actions-primary {
    grid-template-columns: 1fr 1fr;
  }
}
.oh-route-actions-utility {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: center;
  gap: 6px;
}
/* Utility buttons: subtle ghost-styled chips for low-stakes actions
   (Optimize / Reset / Add more / Clear all) so they don't compete with
   the primary share buttons. */
.oh-route-util-btn {
  background: transparent;
  color: rgba(255,255,255,0.7);
  border: 1px solid rgba(255,255,255,0.18);
  padding: 8px 16px;
  border-radius: 999px;
  font-family: inherit;
  font-size: 13.5px;
  font-weight: bold;
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
  letter-spacing: 0.3px;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.oh-route-util-btn:hover {
  background: rgba(255,255,255,0.08);
  color: #fff;
  border-color: rgba(255,255,255,0.32);
}
.oh-route-util-btn.gold {
  color: #E8A820;
  border-color: rgba(232,168,32,0.45);
}
.oh-route-util-btn.gold:hover {
  background: rgba(232,168,32,0.12);
  color: #E8A820;
  border-color: #E8A820;
}
/* Destructive action — its own text-link style instead of a pill so it
   never visually competes with optimize/reset/add-more. Sits on its own
   line below the utility row. */
.oh-route-clear-link {
  align-self: center;           /* center under the utility row */
  margin-top: 4px;
  padding: 4px 0;
  background: transparent;
  border: none;
  color: rgba(255,128,128,0.65);
  font-family: inherit;
  font-size: 12.5px;
  font-weight: normal;
  letter-spacing: 0.2px;
  cursor: pointer;
  text-decoration: underline;
  text-decoration-color: rgba(255,128,128,0.3);
  text-underline-offset: 3px;
  transition: color 0.15s, text-decoration-color 0.15s;
}
.oh-route-clear-link:hover {
  color: #ff8080;
  text-decoration-color: #ff8080;
}
.oh-route-util-btn.blocked,
.oh-route-launch-btn.blocked {
  opacity: 0.3 !important;
  cursor: not-allowed !important;
  pointer-events: none !important;
  filter: grayscale(0.5);
}
.oh-route-launch-btn {
  padding: 15px 22px;
  border-radius: 10px;
  font-family: inherit;
  font-size: 15.5px;
  font-weight: bold;
  letter-spacing: 0.3px;
  cursor: pointer;
  text-decoration: none;
  border: 1.5px solid transparent;
  white-space: nowrap;
  text-align: center;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  box-sizing: border-box;
  transition: background 0.15s, color 0.15s, border-color 0.15s, transform 0.05s;
}
.oh-route-launch-btn:active { transform: scale(0.985); }
.oh-route-launch-btn.google {
  background: #E098FF;
  color: #32143f;
  box-shadow: 0 2px 12px rgba(224,152,255,0.18);
}
.oh-route-launch-btn.google:hover { background: #d070f0; }
.oh-route-launch-btn.gold {
  background: #E8A820;
  color: #32143f;
}
.oh-route-launch-btn.gold:hover { background: #d49510; }
.oh-route-launch-btn.outline {
  background: transparent;
  color: #fff;
  border-color: rgba(255,255,255,0.32);
}
.oh-route-launch-btn.outline:hover {
  background: rgba(255,255,255,0.08);
  border-color: rgba(255,255,255,0.5);
}
.oh-route-launch-btn.apple {
  background: rgba(255,255,255,0.12);
  color: #fff;
  border: 1.5px solid rgba(255,255,255,0.25);
}
.oh-route-launch-btn.apple:hover { background: rgba(255,255,255,0.22); }
.oh-route-launch-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.oh-route-launch-btn.blocked {
  opacity: 0.25 !important;
  cursor: not-allowed !important;
  pointer-events: none !important;
  filter: grayscale(0.5);
}
#oh-route-reset-btn.conflict-pulse {
  background: #E8A820 !important;
  border: 2.5px solid #fff !important;
  color: #32143f !important;
  box-shadow: 0 0 0 3px rgba(232,168,32,0.5), 0 0 18px rgba(232,168,32,0.55) !important;
  animation: oh-conflict-pulse 1.6s ease-in-out 3;
  font-size: 15px !important;
}
@keyframes oh-conflict-pulse {
  0%   { box-shadow: 0 0 0 3px rgba(232,168,32,0.5), 0 0 18px rgba(232,168,32,0.55); transform: scale(1); }
  50%  { box-shadow: 0 0 0 7px rgba(232,168,32,0.2), 0 0 28px rgba(232,168,32,0.8); transform: scale(1.03); }
  100% { box-shadow: 0 0 0 3px rgba(232,168,32,0.5), 0 0 18px rgba(232,168,32,0.55); transform: scale(1); }
}
#oh-route-reasoning.conflict-msg {
  background: rgba(220,80,60,0.15);
  border-left: 3px solid rgba(255,120,100,0.6);
  border-radius: 0 6px 6px 0;
  padding: 8px 14px;
  font-style: normal;
  color: rgba(255,200,180,0.95);
  font-size: 13px;
}
/* Soft-warning state — feasible but tight (e.g. "Stop 3: only ~44 min"
   when the user bumped the visit slider). Yellowish callout so the
   trade-off jumps out without escalating to red. */
#oh-route-reasoning.warn-msg {
  background: rgba(232,168,32,0.12);
  border-left: 3px solid rgba(255,200,80,0.7);
  border-radius: 0 6px 6px 0;
  padding: 8px 14px;
  font-style: normal;
  color: rgba(255,225,170,0.95);
  font-size: 13.5px;
  text-align: left;
}
#oh-route-reasoning.warn-msg .oh-route-emphasis { color: #ffd866; }
/* Optimize button is hidden by default; JS reveals it once the optimizer
   resolves. When the current order matches optimal, the button stays
   visible in a disabled state with "✓ Route is optimal" copy, so the
   user can always see the optimization state. Visual styling comes from
   .oh-route-util-btn (utility pill). */
#oh-route-optimize-btn { display: none; }
#oh-route-optimize-btn.calculating { opacity: 0.6; cursor: default; }
#oh-route-optimize-btn.is-optimal {
  color: rgba(125,239,160,0.85);
  border-color: rgba(125,239,160,0.4);
  cursor: default;
}
#oh-route-optimize-btn.is-optimal:hover {
  background: transparent;
  color: rgba(125,239,160,0.85);
  border-color: rgba(125,239,160,0.4);
}
#oh-route-count-badge {
  display: inline-block;
  background: #E098FF;
  color: #32143f;
  border-radius: 50%;
  width: 18px; height: 18px;
  font-size: 11px;
  font-weight: bold;
  text-align: center;
  line-height: 18px;
  margin-left: 6px;
}


.oh-pick-agent { position: absolute; top: -38px; left: 14px; width: 76px; height: 76px; border-radius: 50%; object-fit: cover; border: 3px solid #fff; box-shadow: 0 2px 8px rgba(0,0,0,0.3); display: block; }
.oh-pick-agent-initial { display: flex; align-items: center; justify-content: center; background: #32143f; color: #fff; font-size: 20px; font-weight: bold; }

/* Callout note bar (for abode listings) */
.oh-callout {
  margin: 12px 18px 16px;
  padding: 10px 14px;
  border-radius: 6px;
  font-size: 13px;
  line-height: 1.6;
}
.oh-callout-abode {
  background: #f0ecf5;
  border-left: 4px solid #32143f;
  color: #32143f;
}
.oh-callout strong { display: block; margin-bottom: 2px; }

/* MAP */

/* SPLIT VIEW */
.oh-main--split {
  display: flex;
  align-items: flex-start;
  gap: 20px;
  max-width: 1920px;
  margin: 0 auto;
  padding: 16px 20px 0;
}
.oh-main--split .oh-grid-wrap {
  flex: 0 0 480px;
  min-width: 260px;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: #d0d4dc transparent;
}
.oh-main--split .oh-map-wrap { flex: 1; min-width: 0; position: sticky; align-self: flex-start; max-height: 700px; overflow: hidden; }
.oh-main--split .oh-grid { grid-template-columns: 1fr; }
@media (max-width: 1199px) {
  .oh-main--split .oh-grid-wrap { flex: 1 1 100%; }
  .oh-main--split .oh-grid { grid-template-columns: 1fr; }
}

/* NO RESULTS */
.oh-empty {
  text-align: center;
  padding: 60px 20px;
  color: #888;
  font-size: 15px;
  display: none;
}

/* FOOTER */
.oh-footer {
  background: #32143f;
  padding: 28px 0;
  text-align: center;
  margin-top: 48px;
}
.oh-footer-inner {
  max-width: 1920px;
  margin: 0 auto;
  padding: 0 24px;
}
.oh-footer p { margin: 0 0 6px; font-size: 13px; color: #E098FF; }
.oh-footer strong { display: block; font-size: 15px; color: #fff; margin: 0 0 10px; }
.oh-footer small { font-size: 11px; color: #ECE4F2; }

@media (min-width: 769px) { #oh-controls-body { display: block !important; } }

/* ── TABLET + DESKTOP (769px+): row layout, controls-body is block ── */
@media (min-width: 769px) {
  /* Row A: Day (auto) left | Time (grows) right */
  #oh-row-a { gap: 32px; align-items: flex-start; }
  #oh-row-a #oh-day-group  { flex: 0 0 auto; }
  #oh-row-a #oh-time-group { flex: 1 1 0; }

  /* Row B: Featured | Price | Sort + Reset */
  #oh-row-b { gap: 32px; align-items: flex-start; }
  #oh-row-b #oh-featured-group { flex: 0 0 auto; }
  #oh-row-b #oh-price-group    { flex: 0 0 auto; }
  #oh-row-b #oh-sort-group     { flex: 0 0 auto; }
}

/* ── MOBILE (max 768px): stacked layout, map moved into controls by JS ── */
@media (max-width: 768px) {
  .oh-controls-inner { padding: 0 14px; }
  .oh-controls-row1 { gap: 8px; padding: 8px 0; }

  /* Each frow stacks vertically */
  .oh-frow {
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
    padding: 8px 0;
  }

  /* All chip filter groups: column layout on mobile */
  #oh-day-group, #oh-time-group, #oh-featured-group, #oh-price-group, #oh-sort-group {
    flex: none;
    align-items: flex-start;
  }
  /* Price on its own row; Beds/Baths/Sq Ft wrap together on the next row */
  #oh-price-group { flex: 0 0 100%; }
  /* Day + Time chips both scroll horizontally on narrow screens */
  #oh-day-group, #oh-time-group { align-items: flex-start; min-width: 0; max-width: 100%; }
  #oh-day-chips, #oh-time-chips {
    width: 100%;
    min-width: 0;
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  #oh-day-chips::-webkit-scrollbar, #oh-time-chips::-webkit-scrollbar { display: none; }
  /* Hide featured row on mobile */
  #oh-featured-group { display: none; }
  /* Mobile row 1: [Search ......][Showing] on line 1, [Sort][Reset] on line 2.
     Search flexes to fill the space left by the count pill. */
  .oh-controls-row1 .oh-search { flex: 1 1 auto; min-width: 0; }
  .oh-controls-row1 #oh-sort-group { flex: 0 0 100%; order: 1; }
  /* On narrow phones: drop "Showing" so "464 of 464" fits inline with
     search bar. Pill made tighter, search bar shrinks more aggressively.
     margin-left:auto removed because it prevents search from shrinking. */
  .oh-controls-row1 .oh-count { font-size: 12px; padding: 4px 8px; flex-shrink: 0; margin-left: 0; }
  .oh-controls-row1 .oh-count-label { display: none; }
  .oh-controls-row1 .oh-search { min-width: 80px; padding-left: 30px; padding-right: 10px; }
  /* Featured chips scroll on mobile (kept for completeness) */
  #oh-curation-chips {
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  #oh-curation-chips::-webkit-scrollbar { display: none; }

  /* City: label above, chips scroll horizontally */
  #oh-city-group { flex-direction: column; align-items: flex-start; gap: 5px; min-width: 0; max-width: 100%; }
  #oh-city-chips {
    width: 100%;
    min-width: 0;
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  #oh-city-chips::-webkit-scrollbar { display: none; }

  .oh-chip { padding: 6px 14px; font-size: 15px; }
  .oh-arrow { opacity: 1; }
}

/* ── Mobile/tablet controls rework (<=999px): demote search/sort/reset,
   swap typed price/beds/baths/sqft for one-tap range chips, and re-order
   so numeric chip filters come first, then open-house chips, then
   (when a city is selected) the SLV map, then the route planner. The
   raw <input> rows stay rendered for desktop. Chip rendering and the
   map-relocate-to-after-city behavior are wired up in app.js. This block
   lives AFTER the existing @media (max-width: 768px) rules above so its
   declarations win on phones (where both queries match). */
@media (max-width: 1139px) {
  /* Top strip: count headline + search icon + sort pill */
  .oh-controls-row1 {
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    gap: 10px;
    padding: 10px 16px;
  }
  /* Top strip order (left → right):
     Reset · Sort · Search · "Showing N of N"
     app.js moves Reset out of #oh-sort-group so each item has its own
     flex order in the row. */
  .oh-controls-row1 .oh-reset-btn {
    flex: 0 0 auto;
    order: 1;
    font-size: 12px;
    padding: 6px 12px;
    border-radius: 20px;
    background: transparent;
    border: 1px solid #DCC8F5;
    color: #6B2BC4;
    font-weight: 600;
    height: 38px;
  }
  .oh-controls-row1 #oh-sort-group {
    flex: 0 0 auto;
    order: 2;
    gap: 6px;
    position: relative;
    flex-direction: row;
    align-items: center;
  }
  .oh-controls-row1 #oh-sort {
    width: 64px;
    min-width: 64px;
    max-width: 64px;
    padding: 6px 10px;
    color: transparent;
    background-color: #F5F0FC;
    background-image: none;
    border: 1px solid #DCC8F5;
    border-radius: 20px;
    height: 38px;
    appearance: none;
    -webkit-appearance: none;
  }
  .oh-sort-mobile-label {
    position: absolute;
    left: 10px;
    top: 50%;
    transform: translateY(-50%);
    font-size: 12px;
    font-weight: 600;
    color: #32143f;
    pointer-events: none;
    letter-spacing: 0;
    z-index: 2;
    white-space: nowrap;
  }
  .oh-controls-row1 .oh-search {
    flex: 0 0 auto !important;
    width: 38px !important;
    min-width: 0 !important;
    height: 38px;
    padding: 0 !important;
    font-size: 0;
    background: #F5F0FC url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2332143f' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='11' cy='11' r='7'/><line x1='21' y1='21' x2='16.5' y2='16.5'/></svg>") center/18px no-repeat;
    border: 1px solid #DCC8F5;
    border-radius: 20px;
    order: 3;
  }
  .oh-controls-row1 .oh-search::placeholder { color: transparent; }
  .oh-controls-row1 .oh-count {
    flex: 1 1 auto;
    font-size: 13px;
    padding: 0 0 0 4px;
    background: transparent;
    border: none;
    text-align: right;
    order: 4;
    margin-left: 0;
    white-space: nowrap;
  }
  .oh-controls-row1 .oh-count-label,
  .oh-controls-row1 .oh-count-of { display: inline; }
  .oh-controls-row1 .oh-count strong { font-size: 14px; color: #32143f; }

  /* Order on mobile: all three sections live inside #oh-controls-body
     (Time → Home → Route) so source order = mobile visual order.
     The map is slotted into #oh-controls-body by JS; give it order 2
     so it lands between the Home section and the Route section. */
  #oh-controls-body { display: flex; flex-direction: column; gap: 14px; }
  #oh-controls-body .oh-section-row-time { order: 0; }
  #oh-controls-body .oh-section-row-home { order: 1; }
  #oh-controls-body #oh-city-map-panel { order: 2; margin: 0; }
  #oh-controls-body .oh-section-row-route { order: 3; }

  /* Map: always visible on mobile, full-width. */
  #oh-city-map-panel { display: block !important; max-height: none; width: 100%; max-width: none; min-width: 0; margin: 0 auto; padding: 0; }
  #oh-city-map-container { display: block; flex: none; }

  /* Stack controls + slotted map vertically */
  #oh-controls-layout { display: flex; flex-direction: column; }
  #oh-controls-body { order: 1; }

  /* Hide the raw typed inputs, show the chip rows instead.
     Exception: Price uses the same chip-styled typed inputs as desktop,
     so we keep its typed-input row visible and hide its mobile chips. */
  #oh-beds-group > div:not(.oh-mobile-chips),
  #oh-baths-group > div:not(.oh-mobile-chips),
  #oh-sqft-group > div:not(.oh-mobile-chips) { display: none !important; }
  #oh-price-group .oh-mobile-chips { display: none !important; }
  .oh-mobile-chips {
    display: flex;
    flex-wrap: nowrap;
    gap: 6px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    width: 100%;
    padding-bottom: 4px;
  }
  .oh-mobile-chips::-webkit-scrollbar { display: none; }
  .oh-mobile-chip {
    flex: 0 0 auto;
    padding: 6px 14px;
    background: #F5F0FC;
    border: 1px solid #DCC8F5;
    border-radius: 20px;
    font-size: 14px;
    font-weight: 600;
    color: #5A3A7A;
    cursor: pointer;
    white-space: nowrap;
  }
  .oh-mobile-chip.active {
    background: #E098FF;
    border-color: #E098FF;
    color: #32143f;
  }
  #oh-price-group, #oh-beds-group, #oh-baths-group, #oh-sqft-group { width: 100%; }
  #oh-row-b > div { flex-direction: column; gap: 14px; }

  /* Tighten Day/Time/City rows: drop the dividers and extra row margin */
  #oh-controls-body .oh-frow { border-top: none; padding: 0; margin: 0; }
  #oh-controls-body .oh-filter-group { gap: 6px; }
  #oh-controls-body .oh-filter-label { margin: 0; }

  /* Bleed scrollable chip rows to the true viewport edge. Using viewport
     units (100vw / calc) so the chips ignore intermediate container
     padding entirely. width:100vw makes the box exactly the viewport
     width; margin-left flips the box back so its left edge sits at the
     viewport's left edge; padding-left re-insets the first chip to
     align with the rest of the content. The padding-right lets the
     last chip scroll right up to the viewport edge.
     #oh-controls-body has overflow:hidden in the desktop-layout rule
     so its contents don't escape the right column; on mobile that
     same rule clips this bleed, so override here. */
  #oh-controls-body { overflow: visible; }
  #oh-day-chips,
  #oh-time-chips,
  #oh-city-chips,
  .oh-mobile-chips {
    width: 100vw;
    max-width: 100vw;
    margin-left: calc(50% - 50vw);
    margin-right: calc(50% - 50vw);
    padding-left: 14px;
    padding-right: 14px;
    box-sizing: border-box;
  }

  /* More breathing room above the OPEN HOUSE TIME label on mobile —
     was crowding the day chips above it. */
  #oh-controls-body .oh-section-row-time .oh-frow:not(#oh-row-a) {
    margin-top: 14px;
  }

  /* Tighten space between section chips and the divider line below.
     The divider sits at the top border of the NEXT section, so the
     gap = current section margin-bottom + flex gap + next section
     margin-top. Collapse the flex gap and section margins on mobile
     and let the section padding-top do the visual separation.
     Keep margin-top on the first (Time) section for breathing room
     above the "Pick when to see homes" header. */
  #oh-controls-body { gap: 4px; }
  #oh-controls-body .oh-section-row { border-top: none; padding-top: 8px; margin: 0; }
  #oh-controls-body .oh-section-row-time { padding-top: 0; margin-top: 16px; }
  #oh-controls-body .oh-section-row-home { margin-top: 16px; }
  #oh-controls-body .oh-section-row-route { margin-top: 0; padding-top: 2px; border-top: none; }

  /* Push City label + chips down a bit within the Home section */
  #oh-controls-body .oh-section-row-home .oh-frow:not(#oh-row-b) {
    margin-top: 14px;
  }

  /* Route section: tuck circles up under the subtitle and put the
     View route button INLINE next to the circles (not below).
     Override the base margin-left:auto so the button sits snug
     against the circles, and hide the "View route" label so only
     the arrow shows — a compact icon-only pill matching the
     dark-purple style.
     Re-order so the button renders right after the circles in flex
     layout, with the "Narrow it down to 5" hint pushed below them
     on its own row — otherwise the hint (which is flex-basis 100%
     on mobile) forces the button to wrap to a third row. */
  #oh-controls-body .oh-route-cta { padding: 0 0 14px; margin-bottom: 0; }
  #oh-controls-body .oh-route-cta-plan-btn { margin-left: 0; padding: 8px 14px; order: 1; }
  #oh-controls-body .oh-route-cta-plan-btn-label { display: none; }
  #oh-controls-body .oh-route-cta-hearts { order: 0; }
  #oh-controls-body .oh-route-cta-hint { order: 2; }
}

/* Floating "Back to top" pill inside the listing modal — mirrors the
   .oh-fab-top button on the listings page. Position fixed at the
   bottom-center of the viewport so it doesn't fight the close X at
   the top. Visible only when the overlay has scrolled past a
   threshold (.is-visible toggled by JS). */
.oh-modal-fab-top {
  position: fixed;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  background: #32143f;
  color: #fff;
  border: none;
  border-radius: 24px;
  padding: 12px 22px;
  font-family: 'Century Gothic', 'CenturyGothicPaneuropean', Arial, Helvetica, sans-serif;
  font-size: 14px;
  font-weight: bold;
  letter-spacing: 0.5px;
  cursor: pointer;
  box-shadow: 0 4px 16px rgba(0,0,0,0.45);
  z-index: 2020;
  display: none;
  align-items: center;
  gap: 6px;
  transition: background 0.2s, transform 0.15s;
}
.oh-modal-fab-top.is-visible { display: inline-flex; }
.oh-modal-fab-top:hover {
  background: #4a1f5e;
  transform: translateX(-50%) translateY(-2px);
}

/* STICKY BACK-TO-FILTERS FAB */
.oh-fab-top {
  position: fixed;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  background: #32143f;
  color: #fff;
  border: none;
  border-radius: 24px;
  padding: 13px 22px;
  font-family: 'Century Gothic', 'CenturyGothicPaneuropean', Arial, Helvetica, sans-serif;
  font-size: 15px;
  font-weight: bold;
  letter-spacing: 0.5px;
  cursor: pointer;
  box-shadow: 0 4px 16px rgba(0,0,0,0.3);
  z-index: 1000;
  display: none;
  align-items: center;
  gap: 6px;
  transition: background 0.2s, transform 0.15s;
}
.oh-fab-top.oh-fab-visible { display: flex; }
.oh-fab-top:hover { background: #4a1f5e; transform: translateX(-50%) translateY(-2px); }

#oh-controls-layout {
  display: flex;
  align-items: stretch;
  gap: 16px;
}
/* Desktop sidebar layout: body is a flex item beside the map. overflow:
   hidden prevents long content from breaking out of the right column.
   Scoped to desktop only — on mobile that overflow:hidden was clipping
   the edge-bleed chip rows. */
@media (min-width: 1140px) {
  #oh-controls-body { flex: 1; min-width: 0; overflow-x: clip; overflow-y: visible; }
}
#oh-city-map-panel {
  /* Map sits on the LEFT as a column-spanning anchor next to the
     three filter sections. Capped max-height so the map doesn't
     dominate the controls when the right column is short. */
  flex: 0 0 auto;
  min-width: 380px;
  max-width: 540px;
  max-height: 600px;
  padding: 0 0 19px;
  display: flex;
  flex-direction: column;
}
#oh-city-map-panel #oh-city-map-svg {
  max-height: 100%;
  width: auto;
  height: auto;
}
/* Wider desktops: bump the map's max-width a touch but keep the
   capped height so it stays balanced with the filter column. */
@media (min-width: 1200px) {
  #oh-city-map-panel {
    min-width: 440px;
    max-width: 620px;
    max-height: 640px;
  }
}
#oh-city-map-panel.oh-map-open { /* mobile legacy */ }
#oh-city-map-panel #oh-city-group .oh-filter-label { display: none; }
.oh-map-panel-label { display: block; margin-bottom: 10px !important; }

@media (min-width: 769px) {
  .oh-map-panel-label { display: none; }
  #oh-city-map-panel #oh-city-group .oh-filter-label { display: block; margin-bottom: 4px; }
}
#oh-city-map-panel #oh-city-group { margin-top: 12px; }
#oh-city-map-panel #oh-city-chips {
  width: 100%;
  max-width: 100%;
  margin-left: 0;
  margin-right: 0;
  padding-left: 0;
  padding-right: 0;
}
/* Search bar improvements for wider mobile (720–768px) */
/* Tablet portrait band: map stays as a LEFT sidebar. Starts at 769px. */
@media (max-width: 1139px) and (min-width: 769px) {
  #oh-city-map-panel {
    min-width: 240px;
    max-width: 320px;
  }
}
#oh-city-map-container {
  position: relative;
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}
/* The satellite image and white wash are injected as children of the SVG
   (see app.js OH_SATELLITE_URL block) so they share the SVG's 500x549
   viewBox and stay locked to the city polygons. Border/shadow/radius
   live on the SVG itself so the framing wraps the actual map shape,
   not the wider container box (which would otherwise show purple gaps
   on either side of the SVG when its 500:549 ratio is narrower than
   the available column). */
#oh-city-map-svg {
  height: 100%;
  width: auto;
  max-width: 100%;
  display: block;
  background: transparent;
  position: relative;
  z-index: 1;
  border-radius: 8px;
  overflow: hidden;
}
@media (max-width: 768px) {
  #oh-city-map-svg { height: auto; width: 100%; }
  #oh-city-map-panel { min-width: 0; max-height: none; }
}


/* Mobile: override controls-layout back to block (placed after the
   max-width:1139px block so it wins the cascade). */
@media (max-width: 768px) {
  #oh-controls-layout { display: block; }
}

/* Render city polygons with crisp edges (no anti-aliased edge blending).
   Strokes render at their true color instead of averaging with the fill
   beneath. Looks slightly more pixelated on diagonal edges but the city
   boundaries are already polygonal, so the trade-off is worth it for
   accurate stroke colors. */
#oh-city-map-svg .oh-map-city polygon,
#oh-city-map-svg .oh-map-city path { shape-rendering: crispEdges; }

.oh-map-city polygon, .oh-map-city path { fill: rgba(0,0,0,0.001); stroke: #9B6EC8; stroke-width: 2; stroke-opacity: 1; cursor: pointer; transition: fill 0.15s, stroke 0.15s; }

.oh-map-city.oh-map-active polygon, .oh-map-city.oh-map-active path { stroke: #32143f; stroke-width: 2.5; stroke-opacity: 1; fill: rgba(50,20,63,0.45); fill-opacity: 1; }
.oh-map-city.oh-map-no-listings polygon, .oh-map-city.oh-map-no-listings path { stroke: transparent; fill: transparent; pointer-events: none; cursor: default; }
@media (hover: hover) {
  /* Gold "chip ↔ shape" highlight only applies to non-active chips. When
     a chip is clicked into the active state, the active styling wins
     immediately even if the mouse hasn't left the chip yet. */
  .oh-chip-map-hover:not(.active) { background: #E8A820 !important; color: #32143f !important; border-color: #E8A820 !important; }
  /* Gold hover only applies to non-active polygons — same reasoning as
     .oh-chip-map-hover above. Click into active state wins immediately. */
  .oh-map-city.oh-map-hover:not(.oh-map-active) polygon,
  .oh-map-city.oh-map-hover:not(.oh-map-active) path { stroke: #E8A820; stroke-width: 3.5; stroke-opacity: 1; fill: rgba(232,168,32,0.10); fill-opacity: 1; }
}

/* Sandy is rendered as two elements: a <path> (fill, with White City
   hole via evenodd) and a <polygon> (outer ring only). The polygon
   provides the outer outline. The path now also strokes — this matters
   because the path's geometry includes the inner ring around White
   City, and without a stroke on the path that inner border (Sandy's
   true boundary with WC) is never drawn. Path+polygon double-stroke
   the outer ring at identical coordinates so it's a perfect overdraw,
   not a visible double line. */
.oh-map-city[data-city="Sandy"] path {
  fill-rule: evenodd;   /* enforce hole geometry from CSS too */
}
.oh-map-city[data-city="Sandy"] polygon { fill: none !important; }
/* ── Mini map card overlay ── */
.oh-minimap-overlay {
  position: absolute; inset: 0; z-index: 15;  /* above .oh-arrow (z:10) so photo nav doesn't leak through */
  background: transparent;
  display: flex; align-items: center; justify-content: center;
  overflow: hidden;
}
/* Custom mini-map zoom buttons (Leaflet's built-in zoomControl is off
   because it intermittently rendered only the minus button here). */
.oh-minimap-zoom {
  position: absolute;
  top: 8px; left: 8px;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.oh-minimap-zoom button {
  width: 32px; height: 32px;
  border: none;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.95);
  color: #32143f;
  font-size: 20px;
  font-weight: bold;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.35);
  padding: 0;
  line-height: 1;
}
.oh-minimap-zoom button:hover { background: #fff; }
.oh-minimap-zoom button:active { transform: scale(0.94); }
.oh-minimap-close {
  position: absolute; top: 6px; right: 6px;
  background: rgba(50,20,63,0.8); color: #fff;
  border: none; border-radius: 50%;
  width: 26px; height: 26px;
  font-size: 12px; cursor: pointer; z-index: 10;
  display: flex; align-items: center; justify-content: center;
  line-height: 1;
}
.oh-minimap-close:hover { background: rgba(50,20,63,1); }
.oh-agent-initial { display:flex; align-items:center; justify-content:center; width:40px; height:40px; border-radius:50%; background:#32143f; color:#fff; font-size:16px; font-weight:bold; border:2px solid rgba(255,255,255,0.3); }
#oh-city-map .leaflet-interactive { cursor: pointer; }
#oh-city-map-close {
  position: absolute;
  top: 6px; right: 6px;
  z-index: 1000;
  background: rgba(50,20,63,0.72);
  color: #fff;
  border: none;
  border-radius: 50%;
  width: 26px; height: 26px;
  font-size: 13px;
  line-height: 26px;
  text-align: center;
  cursor: pointer;
  padding: 0;
}
#oh-city-map-close:hover { background: rgba(50,20,63,1); }
#oh-map-toggle-link {
  display: none;
  font-size: 10px;
  color: #9B6EC8;
  text-decoration: none;
  margin-left: 6px;
  font-weight: normal;
  text-transform: none;
  letter-spacing: 0;
}
#oh-map-toggle-link:hover { color: #32143f; }
@media (max-width: 479px) {
  #oh-map-toggle-link { display: inline; }
}


/* ── "Text me this route" lead form ──
   Centered card over a dimmed backdrop, shown by the route planner's SMS
   button the first time someone taps it. Same dark ABODEslc palette the
   old full-screen gate used, minus the gate. */
#oh-sms-lead {
  position: fixed !important; inset: 0 !important; z-index: 99999 !important;
  background: rgba(26,10,38,0.82) !important;
  -webkit-backdrop-filter: blur(4px) !important; backdrop-filter: blur(4px) !important;
  display: flex !important; align-items: center !important; justify-content: center !important;
  padding: 24px !important; overflow-y: auto !important;
  font-family: 'Century Gothic', 'Trebuchet MS', Arial, sans-serif !important;
  color: #fff !important;
}
#oh-sms-lead[hidden] { display: none !important; }
#oh-sms-lead-card {
  position: relative !important;
  background: #32143f !important;
  border: 1px solid rgba(255,255,255,0.18) !important;
  border-radius: 14px !important;
  padding: 30px 26px 24px !important;
  max-width: 380px !important; width: 100% !important;
  text-align: center !important;
  box-shadow: 0 24px 64px rgba(0,0,0,0.5) !important;
  animation: ohSmsLeadIn 0.18s ease-out !important;
}
@keyframes ohSmsLeadIn {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}
#oh-sms-lead-card h2 { color: #E098FF !important; font-size: 20px !important; margin: 0 0 8px !important; }
#oh-sms-lead-card p {
  color: rgba(255,255,255,0.75) !important; font-size: 14px !important;
  margin: 0 0 20px !important; line-height: 1.5 !important;
}
.oh-sms-lead-x {
  position: absolute !important; top: 10px !important; right: 12px !important;
  background: none !important; border: none !important; cursor: pointer !important;
  color: rgba(255,255,255,0.5) !important; font-size: 16px !important; line-height: 1 !important;
  padding: 6px !important;
}
.oh-sms-lead-x:hover { color: #fff !important; }

/* Shared field styling for the lead form. */
.ohg-fld {
  width: 100% !important; padding: 12px 14px !important; font-size: 16px !important;
  border-radius: 8px !important; border: 2px solid rgba(255,255,255,0.25) !important;
  background: rgba(255,255,255,0.1) !important; color: #fff !important;
  font-family: inherit !important; outline: none !important; box-sizing: border-box !important;
  margin-bottom: 11px !important; display: block !important;
}
.ohg-fld::placeholder { color: rgba(255,255,255,0.5) !important; }
.ohg-namerow { display: flex !important; gap: 10px !important; }
.ohg-namerow .ohg-fld { flex: 1 1 0 !important; min-width: 0 !important; }
.ohg-fld:focus { border-color: #E8A820 !important; }
.ohg-btn {
  width: 100% !important; padding: 13px !important; font-size: 15px !important; font-weight: bold !important;
  background: #E8A820 !important; color: #32143f !important; border: none !important; border-radius: 8px !important;
  cursor: pointer !important; font-family: inherit !important; margin-top: 4px !important; display: block !important;
}
.ohg-btn:active { background: #c9901a !important; }
.ohg-err { color: #ff9090 !important; font-size: 13px !important; min-height: 18px !important; margin-top: 9px !important; }
.ohg-err.ohg-info { color: #E098FF !important; } /* progress messages ("One sec…") not red */
.ohg-consent {
  display: flex !important; align-items: flex-start !important; gap: 9px !important;
  text-align: left !important; margin: 14px 0 20px !important; cursor: pointer !important;
  font-size: 11px !important; line-height: 1.45 !important; color: rgba(255,255,255,0.6) !important;
}
.ohg-consent-box {
  -webkit-appearance: checkbox !important; appearance: checkbox !important;
  width: 18px !important; height: 18px !important; min-width: 18px !important; margin: 1px 0 0 0 !important;
  accent-color: #E8A820 !important; cursor: pointer !important; flex-shrink: 0 !important;
}
[hidden] { display: none !important; }

/* ── Listing detail modal ──
   Vertical scroll-through-photos UI. Overlay = dark scrollable backdrop;
   modal = white card centered with max-width on desktop, fullscreen on
   phone. Body contains the listing info; #oh-listing-photos is a
   vertical stack of all photos beneath. */
#oh-listing-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.78);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  z-index: 2000;
  overflow-y: auto;
  padding: 40px 16px;
  box-sizing: border-box;
  animation: oh-modal-fade 0.18s ease-out;
}
#oh-listing-overlay.open { display: block; }
#oh-listing-modal {
  position: relative;
  background: #fff;
  border-radius: 16px;
  max-width: 760px;
  margin: 0 auto;
  overflow: hidden;
  box-shadow: 0 24px 64px rgba(0,0,0,0.5);
}
.oh-listing-close {
  position: fixed;
  top: 14px; right: 16px;
  z-index: 2010;
  background: rgba(20,8,30,0.85);
  color: #fff;
  border: none;
  border-radius: 50%;
  width: 38px; height: 38px;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  display: none; align-items: center; justify-content: center;
  box-shadow: 0 4px 12px rgba(0,0,0,0.4);
  transition: background 0.15s, transform 0.15s;
}
/* The X now lives outside the overlay (so it pins to the viewport and doesn't
   scroll with the photos); show it only while the overlay is open. */
#oh-listing-overlay.open ~ .oh-listing-close { display: flex; }
.oh-listing-close:hover {
  background: #32143f;
  transform: scale(1.05);
}
/* Vertical photo stack — phone-style scroll-through. Each image is
   full-width inside the modal card. */
#oh-listing-photos {
  display: flex;
  flex-direction: column;
  background: #f3eefa;
}
#oh-listing-photos img {
  width: 100%;
  height: auto;
  display: block;
  /* No seams — photos flow into each other so the scroll feels like
     one continuous reel rather than a stack of discrete cards. */
}
/* Modal mirrors the card layout: heart + map + share are the inline
   icon row next to the address (no more big bottom action row). The
   .oh-card-icon-btn / .oh-card-heart-btn styles defined for cards
   carry over unchanged. Share button gets the same .copied confirmation
   state as before — defined here so both the modal share button and
   any legacy share button share the green flash. */
.oh-card-icon-btn.copied,
.oh-share-btn.copied,
.oh-listing-share-btn.copied {
  background: #e6f7ec !important;
  border-color: #4caf50 !important;
  color: #2e7d32 !important;
}
/* Icon-sized buttons can't hold "✓ Copied" inside their fixed 34×30
   (mobile) / 42×38 (desktop) box, so when .copied is on, let them
   auto-expand horizontally to fit the label. */
.oh-card-icon-btn.copied {
  width: auto !important;
  padding: 0 12px;
}
/* Modal share button is a fixed 36px circle — when it flips to "✓ Copied"
   let it grow into a pill so the label isn't clipped by the round shape. */
.oh-listing-share-btn.copied {
  width: auto !important;
  border-radius: 18px;
  padding: 0 14px;
}
.oh-share-copied-label {
  font-family: inherit;
  font-size: 13px;
  font-weight: bold;
  white-space: nowrap;
  letter-spacing: 0.2px;
}
@media (min-width: 641px) {
  #oh-listing-body .oh-card-icon-btn.copied { padding: 0 16px; }
  #oh-listing-body .oh-share-copied-label { font-size: 15px; }
}
/* Phone: modal slides up from the bottom with a dark strip at the top
   for the close button. The X sits in that strip ABOVE the modal —
   never overlaps the heart/share/map icons in the modal header.
   Address font drops to 18px and body padding tightens so the address
   + 3 icon buttons (map/share/heart) all fit on one row, and share
   has room to expand to "✓ Copied" without pushing icons off-screen. */
@media (max-width: 640px) {
  #oh-listing-overlay { padding: 56px 0 0; }
  #oh-listing-modal {
    border-radius: 16px 16px 0 0;
    min-height: calc(100vh - 56px);
  }
  .oh-listing-close { top: 10px; right: 12px; }
  #oh-listing-body { padding: 16px 16px 18px; }
  .oh-listing-address-lg { font-size: 18px; }
  /* Slightly smaller icon buttons in the modal header so all 3 fit
     side-by-side with the address even on the narrowest phones. */
  #oh-listing-body .oh-card-icon-btn { width: 30px; height: 28px; }
  #oh-listing-body .oh-card-heart-svg,
  #oh-listing-body .oh-card-map-svg,
  #oh-listing-body .oh-card-share-svg { width: 16px; height: 16px; }
  #oh-listing-body .oh-card-mini-actions { gap: 4px; }
}
#oh-listing-body {
  padding: 20px 24px 22px;
  font-family: 'Century Gothic', 'CenturyGothicPaneuropean', Arial, sans-serif;
}
/* Modal info section reuses the card's .oh-card-header / .oh-address /
   .oh-city / .oh-card-stats classes for a 1:1 visual match with the
   listings grid — with two modal-specific tweaks: address scales up
   (modals have more room than card thumbnails), and the stats row is
   capped at ~360px so it doesn't sprawl across the full modal width. */
.oh-listing-address-lg { font-size: 22px; line-height: 1.2; margin: 0; }
/* Address + city stack as a tight block on the left, with the icon
   row on the right of the header. Lets the city tuck directly under
   the address without inheriting the icon-row height. */
.oh-listing-addr-block {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.oh-listing-addr-block .oh-city { margin: 0; }
/* Minimal modal header: address block on the left, single share button
   on the right. Stats / open-house times / route action all live on
   the card behind the modal, so the modal stays focused on photos. */
.oh-listing-header-minimal {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin: 0 0 12px;
}
.oh-listing-share-btn {
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: #F5F0FC;
  border: 1px solid #DCC8F5;
  border-radius: 50%;
  padding: 0;
  cursor: pointer;
  color: #32143f;
  transition: background 0.15s, border-color 0.15s;
}
.oh-listing-share-btn:hover { background: #E098FF; border-color: #E098FF; }
.oh-listing-share-btn svg { width: 18px; height: 18px; }
.oh-listing-stats-tight {
  max-width: 360px;
  margin-left: 0;
  margin-right: auto;
}
.oh-listing-section-label {
  font-size: 11px; font-weight: bold; text-transform: uppercase;
  letter-spacing: 1px; color: #aaa; margin: 14px 0 8px;
}
.oh-listing-times { margin: 0 0 10px; }
.oh-listing-times .oh-time-row { margin-bottom: 6px; }

/* Desktop modal scaling — the card-sized type looked tiny inside the
   roomier modal. Bumps address, stats, times, and labels by ~1.6–1.8×
   so the content fills the modal proportionally. Only applies when
   the modal isn't running fullscreen (≥ 641px viewport). */
@media (min-width: 641px) {
  #oh-listing-body { padding: 28px 32px 32px; }
  .oh-listing-address-lg { font-size: 34px; line-height: 1.15; }
  #oh-listing-body .oh-city { font-size: 18px; margin-bottom: 14px; }
  #oh-listing-body .oh-listing-section-label {
    font-size: 14px;
    letter-spacing: 1.2px;
    margin: 22px 0 10px;
  }
  #oh-listing-body .oh-listing-times .oh-time-pill { font-size: 20px; }
  #oh-listing-body .oh-listing-times .oh-time-row { margin-bottom: 10px; }
  /* Stats grid scales up to match the rest of the info section. */
  #oh-listing-body .oh-listing-stats-tight {
    max-width: 540px;
    padding: 12px 8px;
    margin-top: 14px;
    border-radius: 12px;
  }
  #oh-listing-body .oh-stat--price .oh-stat-val { font-size: 32px; }
  #oh-listing-body .oh-stat-val { font-size: 22px; }
  #oh-listing-body .oh-stat-lbl { font-size: 12px; margin-top: 5px; }
  /* Mini icon buttons (map/share/heart) — bigger to match. */
  #oh-listing-body .oh-card-icon-btn { width: 42px; height: 38px; }
  #oh-listing-body .oh-card-heart-svg,
  #oh-listing-body .oh-card-map-svg,
  #oh-listing-body .oh-card-share-svg { width: 22px; height: 22px; }
  .oh-listing-close { width: 46px; height: 46px; font-size: 22px; }
}
.oh-listing-note {
  margin: 12px 0 0; padding: 10px 14px;
  background: #f5f0ff; border-left: 3px solid #E098FF;
  border-radius: 4px; font-size: 13px; color: #555;
}
/* Leaflet map view — swaps in where the photo stack was. Height
   matched to a "decently big" map without blowing past the typical
   stack of 2-3 cover photos. */
#oh-listing-map {
  width: 100%;
  height: 480px;
  background: #f3eefa;
}
@media (max-width: 640px) {
  #oh-listing-map { height: 70vh; }
}

/* ── Custom confirm modal — replaces ugly browser-native confirm() ── */
.oh-modal-back {
  position: fixed; inset: 0;
  background: rgba(20, 8, 30, 0.55);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  display: flex; align-items: center; justify-content: center;
  z-index: 100000;
  padding: 20px;
  animation: oh-modal-fade 0.16s ease-out;
}
.oh-modal-back.closing { animation: oh-modal-fade 0.14s ease-out reverse; }
@keyframes oh-modal-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.oh-modal {
  background: #fff;
  border-radius: 16px;
  padding: 22px 24px 18px;
  max-width: 360px;
  width: 100%;
  box-shadow: 0 18px 60px rgba(0,0,0,0.45);
  font-family: 'Century Gothic', 'CenturyGothicPaneuropean', Arial, Helvetica, sans-serif;
  animation: oh-modal-pop 0.18s cubic-bezier(0.2, 0.9, 0.3, 1.2);
}
@keyframes oh-modal-pop {
  from { opacity: 0; transform: translateY(8px) scale(0.96); }
  to   { opacity: 1; transform: none; }
}
.oh-modal-title {
  font-size: 17px;
  font-weight: bold;
  color: #32143f;
  margin-bottom: 6px;
  letter-spacing: 0.2px;
}
.oh-modal-msg {
  font-size: 14.5px;
  color: #555;
  line-height: 1.4;
  margin-bottom: 18px;
}
.oh-modal-actions {
  display: flex; gap: 10px;
  justify-content: flex-end;
}
.oh-modal-btn {
  padding: 9px 18px;
  border-radius: 999px;
  font-family: inherit;
  font-size: 14px;
  font-weight: bold;
  letter-spacing: 0.2px;
  cursor: pointer;
  border: 1.5px solid transparent;
  transition: background 0.15s, border-color 0.15s, color 0.15s, transform 0.1s;
}
.oh-modal-btn.cancel {
  background: #fff;
  border-color: #E098FF;
  color: #7a4f9a;
}
.oh-modal-btn.cancel:hover { background: #FAF4FF; }
.oh-modal-btn.confirm {
  background: #32143f;
  color: #fff;
  border-color: #32143f;
}
.oh-modal-btn.confirm:hover { background: #4a2055; }
.oh-modal-btn:focus-visible { outline: 2px solid #E098FF; outline-offset: 2px; }
/* Danger variant: confirm button turns red-ish for destructive actions
   (remove a stop, clear route, etc.). */
.oh-modal-danger .oh-modal-btn.confirm {
  background: #c44b6e;
  border-color: #c44b6e;
}
.oh-modal-danger .oh-modal-btn.confirm:hover {
  background: #a83758;
  border-color: #a83758;
}

/* ── Tablet layout (769px–1139px): desktop-lite split ──────────────────
   Override the mobile stacked/bleed rules from the max-width:1139px
   block above. Map sits left, controls take the remaining width — same
   structure as desktop but with a smaller map and tighter spacing.    */
/* ── TABLET (769–1139px): map sidebar left, controls right ── */
@media (min-width: 769px) and (max-width: 1139px) {
  /* Grid layout: controls column defines row height, map column fills it */
  #oh-controls-layout {
    display: grid;
    grid-template-columns: minmax(260px, 42%) 1fr;
    gap: 24px;
    align-items: start;
  }

  /* Map sits in column 1 — JS sets column width to equalize heights */
  #oh-city-map-panel {
    grid-column: 1;
    grid-row: 1;
    align-self: start;
    max-height: none;
    max-width: none;
    min-width: 0;
    padding-right: 24px;
    position: relative;
  }

  #oh-city-map-panel::after {
    content: '';
    position: absolute;
    right: 0;
    top: 0;
    bottom: 14px;
    width: 1px;
    background: rgba(50,20,63,0.12);
  }

  #oh-city-map-panel #oh-city-map-svg {
    width: 100%;
    height: auto;
    max-height: none;
  }

  #oh-city-map-container {
    flex: unset;
    min-height: unset;
    overflow: hidden;
  }


  /* Controls sit in column 2, define the row height */
  #oh-controls-body {
    grid-column: 2;
    grid-row: 1;
    min-width: 0;
    overflow: hidden;
  }

  /* Restore full search bar (overrides the icon-only mobile collapse) */
  .oh-controls-row1 .oh-search {
    flex: 1 1 200px !important;
    width: auto !important;
    min-width: 200px !important;
    padding: 8px 12px 8px 36px !important;
    font-size: inherit !important;
    background: #F5F0FC url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2332143f' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='11' cy='11' r='7'/><line x1='21' y1='21' x2='16.5' y2='16.5'/></svg>") 10px center/18px no-repeat !important;
    order: 3;
  }
  .oh-controls-row1 .oh-search::placeholder { color: #aaa !important; }

  /* City group sits under the map — just show scrolling chips */
  #oh-city-map-panel #oh-city-group {
    width: 100%;
    margin-top: 10px;
    gap: 5px;
  }
  #oh-city-map-panel #oh-city-chips {
    display: flex;
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    width: 100%;
    max-width: 100%;
    margin-left: 0;
    margin-right: 0;
    padding: 0;
    gap: 6px;
  }
  #oh-city-map-panel #oh-city-chips::-webkit-scrollbar { display: none; }

  /* Reset the viewport-bleed on day/time chips — they live in the
     controls column now, not the full viewport width */
  #oh-day-chips,
  #oh-time-chips,
  .oh-mobile-chips {
    width: 100%;
    max-width: 100%;
    margin-left: 0;
    margin-right: 0;
    padding-left: 0;
    padding-right: 0;
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
  }
  #oh-day-chips::-webkit-scrollbar,
  #oh-time-chips::-webkit-scrollbar { display: none; }

  /* Section rows: restore normal padding/borders */
  #oh-controls-body .oh-frow {
    border-top: revert;
    padding: revert;
    margin: revert;
  }
  /* Time group must fill the row width so #oh-time-chips can scroll */
  #oh-time-group { flex: 1 1 0; min-width: 0; max-width: 100%; }
  #oh-controls-body .oh-section-row { margin: revert; }
  #oh-controls-body .oh-section-row-time { margin-top: revert; }
  #oh-controls-body .oh-section-row-home { margin-top: 16px; }
}