:root {
  --pink-deep: #d1477a;
  --pink-dark: #b93d6b;
  --pink-mid: #e37da0;
  --pink-soft: #f6a8c0;
  --pink-pale: #fbd7e1;
  --paper: #fdf1f2;
  --line: #f6dce3;
  /* The dark espresso/burgundy anchor — used for restaurant names and other
     primary content so pink can stay reserved for actions/accents instead
     of carrying the whole page. Was already here as general body-text ink;
     now leaned on much more deliberately. */
  --ink: #3a2233;
  --muted: #9c7686;
  --gold: #f0a020;
  --gold-ink: #8a5a00;
  --cream: #fdf3df;
  --green: #2fa968;
  --red: #c0392b;
}

* { box-sizing: border-box; }

html, body { height: 100%; }
body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  color: var(--ink);
  background: var(--paper);
}

/* The fixed-viewport, no-page-scroll trick (only .results scrolls) is only
   for the map app shell (index.html). About/Privacy are normal content
   pages and need to scroll like any other page — applying this globally
   was clipping their content with no way to reach the rest of it. */
body.app-shell {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* ---------- decorative scalloped edges ---------- */
.scallop {
  height: 14px;
  background-image: radial-gradient(circle at 8px 0, transparent 8px, var(--pink-deep) 8.5px);
  background-size: 16px 14px;
  background-repeat: repeat-x;
}
.scallop.top { transform: rotate(180deg); }

/* ---------- header ---------- */
/* Grid (not flex+space-between) so the nav links land at the true visual
   center of the header — identical position on every page — as long as
   each page's header has the same three parts (brand / nav / cta link). */
.topbar {
  display: grid;
  /* minmax(0, 1fr), not plain 1fr — otherwise each outer column's default
     minimum width is driven by its own content (the tagline differs in
     length per page), so the two sides end up unequal and the centered
     nav visibly shifts when you navigate between pages. */
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: 1.5rem;
  padding: 1rem 1.75rem;
  background: white;
  border-top: 4px solid var(--pink-deep);
  flex-shrink: 0;
}
.topbar .cta-btn { justify-self: end; }
.brand { display: flex; align-items: center; gap: 0.75rem; min-width: 0; }
.brand-mark {
  width: 48px;
  height: 48px;
  flex-shrink: 0;
  border-radius: 50%;
  border: 2px solid var(--pink-deep);
}
.topbar h1 {
  margin: 0;
  font-family: "Lobster", cursive;
  font-size: 2.15rem;
  font-weight: 400;
  letter-spacing: 0.01em;
  color: var(--pink-deep);
}
.topbar h1 a { color: inherit; text-decoration: none; }
.tagline {
  margin: 0;
  color: var(--pink-deep);
  font-size: 0.68rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  line-height: 1.3;
  display: flex;
  align-items: center;
  gap: 0.3rem;
}
.tagline .sparkle { width: 11px; height: 11px; color: var(--gold); }

/* Pink/white checkerboard, diner-tablecloth style — HungryPig's one
   deliberate brand texture. Used sparingly (the main header, and once more
   by the sidebar mascot nook) rather than as a generic page-wide divider,
   so it reads as a signature rather than wallpaper. Squares sized to match
   the strip height so each one is a clearly visible check, not a dithered
   pattern. */
.diner-stripe {
  height: 9px;
  flex-shrink: 0;
  background-color: white;
  background-image:
    linear-gradient(45deg, var(--pink-deep) 25%, transparent 25%, transparent 75%, var(--pink-deep) 75%, var(--pink-deep)),
    linear-gradient(45deg, var(--pink-deep) 25%, transparent 25%, transparent 75%, var(--pink-deep) 75%, var(--pink-deep));
  background-size: 9px 9px;
  background-position: 0 0, 4.5px 4.5px;
}
/* The sidebar placement sits inside the padded controls column rather than
   running edge-to-edge — rounded so it reads as a deliberate little
   ornament there, not a misaligned divider. */
.diner-stripe-inset { border-radius: 999px; margin: 0.25rem 0 0.4rem; }

.main-nav {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  list-style: none;
  margin: 0;
  padding: 0;
}
.main-nav a {
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--muted);
  padding-bottom: 0.35rem;
  border-bottom: 2px solid transparent;
}
.main-nav a:hover { color: var(--pink-deep); }
.main-nav a[aria-current="page"] { color: var(--pink-deep); border-bottom-color: var(--pink-deep); }

.cta-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.6rem 1.3rem 0.85rem;
  background: var(--pink-deep);
  color: white;
  border: none;
  text-decoration: none;
  border-radius: 999px;
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  cursor: pointer;
  box-shadow: 0 3px 10px rgba(209, 71, 122, 0.35);
  transition: background 0.15s, transform 0.15s;
  white-space: nowrap;
}
.cta-btn:hover { background: var(--pink-dark); transform: translateY(-1px); }
.cta-btn svg { width: 14px; height: 14px; }

/* ---------- layout ---------- */
/* The header above is fixed height; this region fills the rest of the
   viewport exactly, so only .results (its own overflow-y) ever scrolls —
   nothing pushes the header/sidebars off-screen. */
.layout {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: 280px 1fr 340px;
  gap: 0;
}

/* ---------- sidebar controls ---------- */
.controls {
  padding: 1.25rem 1.5rem;
  background: var(--paper);
  border-right: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
/* Desktop: no toggle, body just always renders. Mobile turns this into a
   collapsible accordion — see the mobile block at the end of this file. */
.controls-toggle { display: none; }
.controls-body {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  flex: 1;
  min-height: 0;
}
.control-row { display: flex; flex-direction: column; gap: 0.4rem; }
/* Quieter than before on purpose — these are settings, not actions. Pink
   is reserved for things you actually tap (the CTA, Choose for me), so
   filters/labels sit in muted ink instead of competing for the same
   attention. */
.control-row label {
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
}
.select-wrap, .zip-input-wrap { position: relative; }
.select-wrap svg, .zip-input-wrap svg {
  position: absolute;
  left: 0.85rem;
  top: 50%;
  transform: translateY(-50%);
  width: 16px;
  height: 16px;
  color: var(--muted);
  pointer-events: none;
}
.control-row select,
.zip-input-wrap input {
  width: 100%;
  padding: 0.6rem 0.9rem 0.6rem 2.4rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  font-size: 0.9rem;
  background: white;
  color: var(--ink);
  appearance: none;
  transition: border-color 0.15s, box-shadow 0.15s;
}
.control-row select { padding-right: 1.9rem; }
/* Native <select>s have no reliable open/closed CSS hook across browsers
   except :open — swaps the chevron to point up while the dropdown is
   actually expanded, back down once it's closed. */
.select-wrap .select-arrow {
  left: auto;
  right: 0.85rem;
  width: 10px;
  height: 6px;
  transition: transform 0.15s ease;
}
.select-wrap:has(select:open) .select-arrow {
  transform: translateY(-50%) rotate(180deg);
}
.control-row select:focus,
.zip-input-wrap input:focus {
  outline: none;
  border-color: var(--pink-deep);
  box-shadow: 0 0 0 3px rgba(209, 71, 122, 0.15);
}
.checkbox-row { flex-direction: row; align-items: center; gap: 0.55rem; }
.checkbox-row input[type="checkbox"] {
  width: 1.05rem;
  height: 1.05rem;
  accent-color: var(--pink-deep);
}
.checkbox-row label {
  font-size: 0.9rem;
  font-weight: 500;
  text-transform: none;
  letter-spacing: normal;
  color: var(--ink);
}

.secondary-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  padding: 0.6rem 1rem;
  background: white;
  color: var(--pink-deep);
  border: 1.5px solid var(--pink-deep);
  border-radius: 999px;
  font-size: 0.85rem;
  font-weight: 700;
  cursor: pointer;
  transition: background 0.15s;
}
.secondary-btn:hover { background: var(--pink-pale); }
/* "Choose for me" is the fun, differentiating action in this sidebar — worth
   the strongest pill treatment, filled rather than just outlined, so it
   doesn't read as equal weight to a plain settings control. */
#chooseForMeBtn { background: var(--pink-pale); border-color: var(--pink-pale); color: var(--pink-dark); }
#chooseForMeBtn:hover { background: var(--pink-soft); }

/* "Update my location" / "Enable location access" is a fallback, not a
   primary action — a plain underlined text link instead of a second pill
   next to Choose for me keeps it from competing for the same attention. */
.text-action-btn {
  align-self: flex-start;
  background: none;
  border: none;
  padding: 0;
  color: var(--pink-deep);
  font-size: 0.85rem;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.text-action-btn:hover { color: var(--pink-dark); }

.zip-input-wrap { flex: 1; }
.zip-input-group { display: flex; gap: 0.5rem; align-items: center; }
.zip-input-group .secondary-btn {
  background: var(--pink-deep);
  color: white;
  border-color: var(--pink-deep);
  padding: 0.65rem 1.2rem;
}
.zip-input-group .secondary-btn:hover { background: var(--pink-dark); }

#searchBtn { display: none; } /* superseded by the header CTA button */

.status { font-size: 0.83rem; color: var(--muted); min-height: 1.2em; }

.mascot-note {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  padding-top: 0.5rem;
  flex-shrink: 0;
}
/* Desktop keeps the mascot at the bottom of the sidebar (above); this
   second copy below the map is mobile-only — see the mobile block. */
.mobile-mascot { display: none; }
.speech-bubble {
  position: relative;
  background: white;
  border: 1.5px solid var(--pink-pale);
  border-radius: 999px;
  padding: 0.55rem 1.1rem;
  font-size: 0.83rem;
  color: var(--pink-deep);
  font-weight: 600;
}
.speech-bubble::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -7px;
  transform: translateX(-50%);
  width: 12px;
  height: 12px;
  background: white;
  border-right: 1.5px solid var(--pink-pale);
  border-bottom: 1.5px solid var(--pink-pale);
  clip-path: polygon(0 0, 100% 0, 0 100%);
}
/* inline-block so `.about-hero`'s text-align: center still centers it —
   a bare inline <svg> centered that way before this wrapper existed. */
.mascot-wrap { position: relative; display: inline-block; }
.mascot-pig {
  width: 76px;
  height: auto;
  transform-origin: 50% 100%;
  /* Mobile browsers flash a highlight box on tap for clickable elements by
     default — the pig doesn't need that, the dance + oink already say "hey,
     that did something." */
  -webkit-tap-highlight-color: transparent;
}
.mascot-pig:hover { animation: pig-dance 0.6s ease-in-out infinite; cursor: pointer; }
@keyframes pig-dance {
  0%, 100% { transform: rotate(-8deg) translateY(0); }
  25% { transform: rotate(6deg) translateY(-4px); }
  50% { transform: rotate(-6deg) translateY(0); }
  75% { transform: rotate(8deg) translateY(-4px); }
}

/* top/left are set inline by JS to the click position within .mascot-wrap */
.oink-bubble {
  position: absolute;
  top: 0;
  left: 0;
  /* The pig gets its own stacking context while its hover/dance transform is
     active — without an explicit z-index here, DOM order would let the pig
     (later in the markup) paint over this bubble whenever that's happening,
     which is almost always exactly when you've just clicked it. */
  z-index: 5;
  background: white;
  border: 1.5px solid var(--pink-pale);
  border-radius: 999px;
  padding: 0.3rem 0.7rem;
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--pink-deep);
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transform: translate(-50%, -50%) scale(0.6);
  transition: opacity 0.15s, transform 0.15s;
}
.oink-bubble.show {
  opacity: 1;
  transform: translate(-50%, -70%) scale(1);
}

/* ---------- map ---------- */
.map {
  width: 100%;
  height: 100%;
  background: #f3e4e8;
}
/* Google injects a focusable div for keyboard panning that picks up the
   browser's default blue focus ring on click/drag — jumps out hard against
   this palette. Swap it for a subtle neutral inset line instead of just
   removing it outright, so keyboard users still get a focus indicator. */
.map:focus-within { outline: none; box-shadow: inset 0 0 0 1px var(--line); }
.map * { outline: none; }

.map-toggle {
  display: flex;
  background: white;
  border-radius: 999px;
  padding: 0.2rem;
  box-shadow: 0 2px 10px rgba(58, 34, 51, 0.18);
  font-size: 0.8rem;
  font-weight: 700;
  margin: 10px;
}
.map-toggle button {
  border: none;
  background: transparent;
  padding: 0.4rem 0.9rem;
  border-radius: 999px;
  cursor: pointer;
  color: var(--muted);
}
.map-toggle button.active { background: var(--pink-deep); color: white; }

.map-round-btn {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: none;
  background: white;
  color: var(--pink-deep);
  box-shadow: 0 2px 10px rgba(58, 34, 51, 0.18);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 10px;
}
.map-round-btn:hover { background: var(--pink-pale); }
.map-round-btn svg { width: 18px; height: 18px; }
.zoom-stack { display: flex; flex-direction: column; gap: 8px; }

.map-pig-flag {
  width: 44px;
  height: 44px;
  margin-bottom: -6px;
}

/* ---------- results ---------- */
/* The only scrollable region in the desktop layout — header, controls, and
   map stay put; ad-slot/footer live at the end of this same scroll area. */
.results {
  background: white;
  border-left: 1px solid var(--line);
  height: 100%;
  overflow-y: auto;
  padding: 0.5rem 0;
}
.results-list { list-style: none; margin: 0; padding: 0; }

.result-card {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  padding: 0.85rem 1.1rem;
  border-bottom: 1px solid var(--line);
  cursor: pointer;
  transition: background 0.15s;
}
.result-card:hover { background: var(--pink-pale); }
.result-card.highlighted { background: var(--pink-pale); }

.notable-card {
  border-left: 3px solid var(--gold);
  background: linear-gradient(to right, rgba(240, 160, 32, 0.08), transparent 55%);
}
.notable-card:hover, .notable-card.highlighted {
  background: linear-gradient(to right, rgba(240, 160, 32, 0.14), var(--pink-pale) 70%);
}
/* min-width + pill radius (not a fixed circle) so 2-digit numbers get room
   to breathe instead of being squeezed into a circle sized for one digit —
   a list of 10+ results is common. */
.result-badge {
  position: relative;
  flex-shrink: 0;
  min-width: 28px;
  height: 28px;
  padding: 0 5px;
  border-radius: 999px;
  /* Glossy little "gumball" look — matches the highlight added to the map
     pins, so the badge on a card reads as the same friendly object as its
     pin rather than a flat, separate style. */
  background: radial-gradient(circle at 32% 28%, var(--pink-mid), var(--pink-deep) 72%);
  color: white;
  font-size: 0.76rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  display: flex;
  align-items: center;
  justify-content: center;
}
.notable-card .result-badge {
  min-width: 32px;
  height: 32px;
  background: none;
}
.badge-star { position: absolute; inset: 0; width: 100%; height: 100%; color: var(--gold); }
.badge-num { position: relative; z-index: 1; color: var(--ink); font-size: 0.72rem; font-weight: 800; letter-spacing: -0.02em; }
.result-body { flex: 1; min-width: 0; }
/* The restaurant name is the first thing your eye should catch — bumped
   ~14% over the old 0.95rem and set in the dark espresso ink rather than
   pink, so it reads as the headline instead of just another pink element. */
.result-card h3 { margin: 0 0 0.3rem; font-size: 1.08rem; font-weight: 700; color: var(--ink); }
/* Distance/price/cuisine — plain supporting facts, kept quiet. */
.result-meta {
  font-size: 0.78rem;
  color: var(--muted);
  line-height: 1.4;
}
/* Rating line is deliberately separated from the meta line and explicitly
   labeled "Google reviews" — this is sourced, external metadata, not
   HungryPig's own take, and shouldn't blur together with the curation
   signal below it. */
.result-rating {
  font-size: 0.82rem;
  color: var(--muted);
  line-height: 1.4;
}
.result-rating .rating { color: var(--gold-ink); font-weight: 700; }
.result-rating .open-status { color: var(--green); font-weight: 600; }
.result-rating .closed-status { color: var(--red); font-weight: 600; }

/* One shared "endorsement" stamp for anything HungryPig or a third party is
   actually vouching for — a Michelin star, a James Beard nod, or a press
   pick — instead of a different pill style per source. Gold/cream rather
   than pink specifically so it doesn't compete with the pink used for
   actions elsewhere, and reads as its own distinct "seal of approval." */
.endorsement-badges { display: flex; flex-wrap: wrap; gap: 0.35rem; margin-top: 0.5rem; }
.endorsement-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.2rem 0.65rem;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.01em;
  color: var(--gold-ink);
  background: var(--cream);
  border: 1px solid rgba(240, 160, 32, 0.35);
}

/* "What to order" — specific dishes press mentions call out, most-mentioned
   first. Pills (unlike "why it's here" below) since these are discrete,
   scannable items rather than one editorial sentence — pink-outlined rather
   than the endorsement badge's gold, so it doesn't read as another
   accolade, just a menu shortlist. Label sits on its own line above the
   pill row (rather than inline with the first pill) so a narrow card
   doesn't wrap mid-way through the label and each pill doesn't force its
   own full-width row — several short pills can now sit side by side. */
.what-to-order {
  margin-top: 0.5rem;
}
.wto-label {
  display: block;
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
  margin-bottom: 0.3rem;
}
.dish-pill-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}
.dish-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.24rem 0.7rem;
  border-radius: 999px;
  font-size: 0.76rem;
  font-weight: 600;
  color: var(--pink-dark);
  background: white;
  border: 1px solid var(--pink-soft);
}
.dish-count { color: var(--muted); font-weight: 700; }

/* Plain text, not pills — "why it's here" is HungryPig's own editorial
   voice (a signature dish, the vibe), so it reads as a sentence rather than
   metadata chips competing with the endorsement badge above it. */
.why-here {
  margin-top: 0.4rem;
  font-size: 0.78rem;
  color: var(--muted);
  line-height: 1.4;
}
.open-external-btn {
  flex-shrink: 0;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: 1.5px solid var(--pink-pale);
  background: white;
  color: var(--pink-deep);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 0.15rem;
}
.open-external-btn:hover { background: var(--pink-pale); }
.open-external-btn svg { width: 14px; height: 14px; }

.results-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.75rem 1.1rem;
  border-top: 1px solid var(--line);
  font-size: 0.82rem;
}
#resultsCount { color: var(--pink-mid); font-weight: 600; }
#clearFiltersBtn {
  background: none;
  border: none;
  color: var(--pink-deep);
  font-weight: 700;
  cursor: pointer;
  font-size: 0.82rem;
  padding: 0;
}
#clearFiltersBtn:hover { text-decoration: underline; }

.ad-slot {
  padding: 1rem;
  text-align: center;
  background: white;
  border-top: 1px solid var(--line);
  min-height: 90px;
}
/* No AdSense unit uncommented yet, so right now this only ever contains an
   HTML comment — collapse it instead of reserving 90px+ of empty space.
   Comments don't count as content for :empty, so this "just works" the
   moment a real <ins> unit gets uncommented in here later. */
.ad-slot:empty { display: none; }

.site-footer {
  padding: 1rem 1.5rem;
  text-align: center;
  background: white;
  color: var(--muted);
  font-size: 0.85rem;
  border-top: 1px solid var(--line);
}
.site-footer a { color: var(--pink-deep); }

.policy {
  max-width: 640px;
  margin: 2rem auto;
  padding: 2rem;
  background: white;
  border-radius: 14px;
  box-shadow: 0 1px 3px rgba(58, 34, 51, 0.08);
  line-height: 1.6;
}
.policy h2 { font-size: 1.1rem; margin-top: 1.5rem; color: var(--pink-deep); }
.policy a { color: var(--pink-deep); }

.about-hero { max-width: 860px; margin: 0 auto; padding: 2.5rem 2rem; text-align: center; }
.about-hero .mascot-pig { width: 140px; margin-bottom: 1rem; }
.about-hero p { line-height: 1.6; color: var(--ink); }
.about-hero p a { color: var(--pink-deep); }
/* The header used to carry this sentiment on every page — moved here,
   its one true home, instead of competing with the header's logo/nav/CTA. */
.about-hero p.about-tagline { justify-content: center; margin: 0.25rem 0 1.25rem; color: var(--pink-deep); }
.about-contact {
  margin-top: 1.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
}
.about-contact h3 {
  margin: 0 0 0.5rem;
  font-size: 0.9rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--pink-deep);
}
/* Desktop already has this button in the header — only needed here once
   the header version is hidden on mobile (see the mobile block). */
.about-cta { display: none; }

/* ---------- mobile ---------- */
/* Kept as one block at the end of the file, on purpose: CSS resolves ties
   between equal-specificity rules by source order, so any mobile override
   declared earlier than the desktop rule it's meant to override (e.g. a
   plain `.map { height: 100% }` further down the file) loses and gets
   silently undone — which is exactly what was collapsing the map to zero
   height on phones. */
@media (max-width: 900px) {
  /* gap: 1.5rem (base) is sized for the desktop 3-column row layout; once
     mobile stacks brand/nav into a single column that same value becomes a
     much-too-large vertical gap between them. Padding goes asymmetric too —
     less above the logo, more below the nav before the checkered stripe. */
  .topbar { grid-template-columns: 1fr; justify-items: center; text-align: center; gap: 0.35rem; padding: 0.5rem 1rem 1rem; }
  /* No room for it on a phone header, and it'd otherwise make the header a
     different height per page depending on whether that page has one —
     desktop keeps it. About's copy moves below the page text instead
     (.about-cta); Privacy and the map page just lose it on mobile. */
  .topbar .cta-btn { display: none; }

  /* overflow-x: hidden (not the old blanket "auto") so if anything is still
     a hair too wide, it gets clipped instead of letting the whole page pan
     sideways — that sideways drift was the "overflowing to the right" bug.
     The app-shell override needs matching specificity (body.app-shell, not
     just body) or the desktop rule's overflow-y: hidden wins regardless of
     source order, since it's more specific. */
  body { overflow-x: hidden; }
  body.app-shell { overflow-y: auto; }
  .layout { grid-template-columns: 1fr; flex: none; }
  .controls, .results { height: auto; overflow: visible; }
  /* The map is the point — keep it visible without scrolling past a wall of
     filters. Search criteria collapse into an accordion above it instead. */
  .map { height: 55vh; }

  .controls { padding: 0.75rem 1rem; border-right: none; border-bottom: 1px solid var(--line); }
  .controls-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    padding: 0.6rem 0.9rem;
    background: white;
    border: 1.5px solid var(--pink-pale);
    border-radius: 999px;
    font-size: 0.85rem;
    font-weight: 700;
    color: var(--pink-deep);
    cursor: pointer;
  }
  .toggle-chevron { width: 16px; height: 16px; transition: transform 0.2s; }
  .controls-toggle[aria-expanded="true"] .toggle-chevron { transform: rotate(180deg); }
  .controls-body { display: none; }
  .controls-toggle[aria-expanded="true"] + .controls-body {
    display: flex;
    padding-top: 0.9rem;
  }
  /* The sidebar's mascot only shows on desktop — mobile has its own copy
     at the bottom of the results (.mobile-mascot), regardless of accordion
     state. */
  .controls-body .mascot-note { display: none; }
  .mobile-mascot {
    display: flex;
    padding: 0.65rem 1rem;
    background: var(--paper);
    border-top: 1px solid var(--line);
    border-bottom: 1px solid var(--line);
  }
  .mobile-mascot .mascot-pig { width: 56px; }

  .about-cta { display: inline-flex; margin-top: 1.5rem; }

  .zip-input-group { flex-wrap: wrap; }

  /* Smaller controls all round. */
  .secondary-btn, #clearFiltersBtn { padding: 0.45rem 0.8rem; font-size: 0.78rem; }
  .map-round-btn { width: 34px; height: 34px; }
  .map-round-btn svg { width: 15px; height: 15px; }
  .map-toggle { font-size: 0.72rem; }
  .map-toggle button { padding: 0.3rem 0.7rem; }
  .open-external-btn { width: 26px; height: 26px; }
  .result-badge { width: 22px; height: 22px; font-size: 0.7rem; }
}
