/*
 * Denver Pop Tops — application styles.
 * Airy, upbeat, professional. Mobile-first.
 */

:root {
  --bg:        #fbfbf9;
  --surface:   #ffffff;
  --ink:       #1d2733;
  --ink-soft:  #55616e;
  --muted:     #8a94a0;
  --line:      #e7e9e4;
  --brand:     #1f7a8c;   /* denver sky teal-blue */
  --brand-dk:  #16606f;
  --accent:    #f2a541;   /* warm upbeat sun */
  --danger:    #c0392b;
  --ok-bg:     #e7f4ef;
  --ok-ink:    #1a6b52;
  --alert-bg:  #fceceb;
  --alert-ink: #a5342a;
  --radius:    14px;
  --radius-sm: 9px;
  --shadow:    0 1px 2px rgba(29,39,51,.04), 0 8px 24px rgba(29,39,51,.06);
  --shadow-lg: 0 12px 40px rgba(29,39,51,.12);
  --maxw:      1120px;
  --font:      ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--font);
  color: var(--ink);
  background: var(--bg);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

main { flex: 1 0 auto; }

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

h1, h2, h3 { line-height: 1.2; letter-spacing: -.01em; }

img { max-width: 100%; display: block; }

.container {
  width: 100%;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 20px;
}

/* ---------- Header / nav ---------- */
.site-header {
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: 0;
  z-index: 20;
}
.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 64px;
  gap: 16px;
}
.brand {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  color: var(--ink);
  font-weight: 700;
  font-size: 1.15rem;
  letter-spacing: -.02em;
}
.brand:hover { color: var(--ink); }
.brand__mark { color: var(--brand); font-size: 1.3rem; line-height: 1; }
.brand__badge {
  font-size: .7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--brand-dk);
  background: var(--ok-bg);
  padding: 2px 8px;
  border-radius: 999px;
  margin-left: 4px;
}
.site-nav { position: relative; display: flex; align-items: center; }
.site-nav__menu, .admin-nav { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.site-nav__toggle {
  display: none;
  align-items: center;
  justify-content: center;
  border: 0;
  background: none;
  color: var(--ink);
  cursor: pointer;
  padding: 6px;
  border-radius: var(--radius-sm);
}
.site-nav__toggle:hover { background: #f2f3ef; }
.site-nav__link, .admin-nav__link {
  color: var(--ink-soft);
  font-weight: 600;
  font-size: .95rem;
  padding: 8px 12px;
  border-radius: var(--radius-sm);
}
.site-nav__link:hover, .admin-nav__link:hover { color: var(--ink); background: #f2f3ef; }
.site-nav__link--button, .admin-nav__link--button {
  border: 0; background: none; cursor: pointer;
  font-family: inherit;
}
form { margin: 0; }

/* Mobile: the menu collapses behind the hamburger and drops down from the right.
   nav_controller toggles `.is-open`; without JS the menu stays hidden on mobile
   but every link is still in the footer. */
@media (max-width: 640px) {
  .site-nav__toggle { display: inline-flex; }
  .site-nav__menu {
    display: none;
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    min-width: 190px;
    padding: 8px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    box-shadow: 0 10px 28px rgba(0, 0, 0, .14);
    z-index: 30;
  }
  .site-nav.is-open .site-nav__menu { display: flex; }
  .site-nav__menu .site-nav__link { display: block; }
  .site-nav__menu form { display: block; }
  .site-nav__menu .site-nav__link--button { width: 100%; text-align: left; }
}

/* ---------- Flash ---------- */
.flash { padding: 10px 0; font-weight: 600; font-size: .95rem; }
.flash--notice { background: var(--ok-bg); color: var(--ok-ink); }
.flash--alert  { background: var(--alert-bg); color: var(--alert-ink); }

/* ---------- Hero ---------- */
.hero {
  background: linear-gradient(160deg, #eaf4f5 0%, #fbfbf9 70%);
  padding: 56px 0 40px;
  border-bottom: 1px solid var(--line);
}
.hero__title { font-size: clamp(1.8rem, 5vw, 2.9rem); margin: 0 0 12px; max-width: 16ch; }
.hero__subtitle { font-size: clamp(1rem, 2.5vw, 1.2rem); color: var(--ink-soft); margin: 0; max-width: 46ch; }

/* ---------- View toggle (gallery / map) ---------- */
.browse { display: block; }
.view-toggle {
  display: inline-flex;
  margin: 24px auto 4px;
  padding: 4px;
  gap: 4px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 999px;
  box-shadow: var(--shadow);
}
/* Center the pill in its container. */
.container > .view-toggle { display: flex; width: max-content; margin-inline: auto; }
.view-toggle__option {
  padding: 8px 22px;
  border-radius: 999px;
  font-weight: 600;
  font-size: .95rem;
  color: var(--ink-soft);
  transition: background .15s ease, color .15s ease;
}
.view-toggle__option:hover { color: var(--ink); text-decoration: none; }
.view-toggle__option.is-active {
  background: var(--brand);
  color: #fff;
}
.view-toggle__option.is-active:hover { color: #fff; }

/* ---------- Neighborhood filter (gallery) ---------- */
.hood-filter { margin: 14px auto 0; }
/* Desktop: chips wrap and centre. Mobile (below) turns this into a swipe rail. */
.hood-filter__rail {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
}
.hood-filter__chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 14px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink-soft);
  font-weight: 600;
  font-size: .9rem;
  white-space: nowrap;
  transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.hood-filter__chip:hover { color: var(--ink); border-color: var(--muted); text-decoration: none; }
.hood-filter__chip.is-active {
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
}
.hood-filter__chip.is-active:hover { color: #fff; }
/* Mobile: one swipeable row instead of a wrapping block that eats vertical
   space. Bleeds to the screen edges so it reads as scrollable; snaps per chip. */
@media (max-width: 640px) {
  .hood-filter__rail {
    flex-wrap: nowrap;
    justify-content: flex-start;
    overflow-x: auto;
    scroll-snap-type: x proximity;
    margin-inline: -20px;
    padding: 2px 20px 8px;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .hood-filter__rail::-webkit-scrollbar { display: none; }
  .hood-filter__chip { scroll-snap-align: start; }
}

/* ---------- Gallery ---------- */
.gallery-section { padding: 36px 20px 64px; }
.gallery-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));
  gap: 24px;
}

.property-card {
  position: relative;
  display: flex;
  flex-direction: column;
  /* Clears the sticky 64px header when arriving via the "Back to gallery"
     anchor, so the returned-to card isn't tucked underneath it. */
  scroll-margin-top: 84px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow);
  transition: transform .15s ease, box-shadow .15s ease;
}
.property-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-lg); }
.property-card__link { display: flex; flex-direction: column; flex: 1 0 auto; color: var(--ink); }
.property-card__link:hover { color: var(--ink); text-decoration: none; }
.property-card__media { position: relative; aspect-ratio: 4 / 3; background: #eef0ec; }
.property-card__image { width: 100%; height: 100%; object-fit: cover; }
/* Hidden until loaded (see image_retry_controller) so the card's grey media
   background shows through while loading/retrying instead of the browser's
   broken-image glyph. Only applies once JS enhances the grid. */
.gallery-grid.is-enhanced .property-card__image { opacity: 0; transition: opacity .3s ease; }
.gallery-grid.is-enhanced .property-card__image.is-loaded { opacity: 1; }

/* Swipeable photo strip, only on cards with more than one photo. The browser
   does the scrolling; carousel_controller only lights the current dot. */
.property-card__scroller {
  /* Pinned to the media box rather than height:100% — the media gets its height
     from `aspect-ratio`, and a percentage against that is fussier than inset. */
  position: absolute; inset: 0;
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  /* Keeps a swipe past the last photo inside the strip — without this, iOS
     hands the overscroll to the page and it reads as a back-navigation. */
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}
.property-card__scroller::-webkit-scrollbar { display: none; }
/* No `touch-action` here on purpose: the default is what lets the browser
   decide between scrolling the page vertically and the strip horizontally.
   Pinning it to pan-x would stop a finger on a photo from scrolling the
   gallery at all. */
.property-card__slide { flex: 0 0 100%; scroll-snap-align: center; }

/* Position dots, in the same dark translucent family as the rest of the
   over-photo chrome. Purely indicative — see the partial for why. */
.property-card__dots {
  position: absolute; bottom: 10px; left: 0; right: 0;
  display: flex; justify-content: center; gap: 6px;
  pointer-events: none;
}
.property-card__dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: rgba(255,255,255,.55);
  box-shadow: 0 0 3px rgba(29,39,51,.55);
  transition: background .15s ease, transform .15s ease;
}
.property-card__dot.is-current { background: #fff; transform: scale(1.35); }

/* The dots are aria-hidden, so this is what a screen reader hears instead. */
.property-card__status {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.property-card__body { padding: 14px 16px 10px; flex: 1 0 auto; }

/* Card action row: favorite + share, right-aligned at the card's bottom. */
.property-card__actions { display: flex; justify-content: flex-end; gap: 8px; padding: 0 12px 12px; }

/* Circular icon buttons shared by favorite + share in the action row. */
.share-btn--icon, .fav-btn {
  position: relative; /* anchors the share "copied" label */
  width: 36px; height: 36px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 999px; background: #fff; border: 1px solid var(--line);
  box-shadow: var(--shadow); cursor: pointer;
}
.share-btn--icon:hover, .fav-btn:hover { background: var(--ok-bg); transform: scale(1.06); }

/* Share button */
.share-btn { display: inline-flex; align-items: center; gap: 8px; border: 0; cursor: pointer; font: inherit; }
.share-btn__icon { width: 18px; height: 18px; flex-shrink: 0; }
.share-btn--icon { color: var(--ink-soft); }
.share-btn--icon .share-btn__label {
  position: absolute; bottom: calc(100% + 6px); right: 0;
  background: var(--ink); color: #fff; font-size: .72rem; font-weight: 600;
  padding: 3px 8px; border-radius: 6px; white-space: nowrap;
  opacity: 0; pointer-events: none; transition: opacity .15s ease;
}
.share-btn--icon.is-shared .share-btn__label { opacity: 1; }

/* Favorite heart: hollow grey by default, filled red when favorited. */
.fav-btn { color: var(--ink-soft); }
.fav-btn__icon { width: 19px; height: 19px; flex-shrink: 0; }
.fav-btn__icon--filled { display: none; }
.fav-btn.is-favorited { color: #e0245e; border-color: #f3c9d5; }
.fav-btn.is-favorited .fav-btn__icon--hollow { display: none; }
.fav-btn.is-favorited .fav-btn__icon--filled { display: inline; }
.share-btn--text {
  background: var(--surface); color: var(--ink-soft);
  border: 1px solid var(--line); border-radius: 999px;
  padding: 9px 18px; font-weight: 600; font-size: .9rem;
  box-shadow: var(--shadow); white-space: nowrap;
}
.share-btn--text:hover { background: var(--ok-bg); color: var(--ink); }
.property-card__address { font-size: 1.05rem; margin: 0 0 4px; }
.property-card__meta { color: var(--muted); font-size: .9rem; margin: 0; }

/* ---------- Photo placeholder ---------- */
.photo-placeholder {
  width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center;
  background: repeating-linear-gradient(135deg, #eef0ec, #eef0ec 12px, #e9ebe6 12px, #e9ebe6 24px);
  aspect-ratio: 4 / 3;
}
.photo-placeholder__mark { font-size: 2.4rem; color: #b9c1b8; }

/* ---------- Property detail ---------- */
.detail { padding: 28px 20px 64px; max-width: 900px; }
.detail__back { font-weight: 600; font-size: .95rem; display: inline-block; margin-bottom: 18px; }
.detail__header { margin-bottom: 24px; display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.detail__actions { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }
.detail__heading { min-width: 0; }
.detail__title { font-size: clamp(1.5rem, 4vw, 2.2rem); margin: 0 0 6px; }
.detail__meta { color: var(--ink-soft); margin: 0; font-size: 1.05rem; }
.detail__gallery { display: grid; gap: 16px; margin-bottom: 28px; }
.detail__figure { margin: 0; }
.detail__image { width: 100%; border-radius: var(--radius); box-shadow: var(--shadow); }
.detail__caption { color: var(--muted); font-size: .9rem; margin-top: 8px; }
.detail__placeholder { border-radius: var(--radius); overflow: hidden; margin-bottom: 28px; }
.detail__description { font-size: 1.08rem; color: var(--ink-soft); margin-bottom: 28px; }
.detail__facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px 32px;
  border-top: 1px solid var(--line);
  padding-top: 24px;
  margin: 0;
}
.detail__fact dt { font-size: .8rem; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); margin-bottom: 2px; }
.detail__fact dd { margin: 0; font-weight: 600; font-size: 1.05rem; }

/* ---------- Detail pager (prev / next property) ---------- */
.pager {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin-top: 32px;
  padding-top: 24px;
  border-top: 1px solid var(--line);
}
.pager__link {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;                 /* lets the address ellipsize instead of stretching the grid */
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  text-decoration: none;
  transition: border-color .15s ease, box-shadow .15s ease, transform .15s ease;
}
/* The "next" cell sits on the right and reads right-to-left. When there's no
   previous property an empty cell holds its column, so next never slides left. */
.pager__link--next { grid-column: 2; text-align: right; align-items: flex-end; }
.pager__link--empty { border: 0; background: none; }
a.pager__link:hover { border-color: var(--brand); box-shadow: var(--shadow); transform: translateY(-1px); }
.pager__direction { font-size: .8rem; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); }
.pager__label {
  font-weight: 600;
  color: var(--ink);
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Visible-to-screen-readers-only: "Previous property:" prefixes the address so
   the links aren't announced as two bare street names. */
.pager__sr {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
  a.pager__link:hover { transform: none; }
}

/* ---------- Empty state ---------- */
.empty-state { text-align: center; padding: 64px 20px; color: var(--ink-soft); }
.empty-state__mark { font-size: 3rem; color: #c6cdc4; margin: 0 0 8px; }
.empty-state h2 { margin: 0 0 6px; color: var(--ink); }

/* ---------- Map ---------- */
.map-page { padding: 8px 0 48px; }
.map-page__note { margin: 14px 0 0; color: var(--muted); font-size: .9rem; }

.map-canvas {
  height: clamp(380px, 68vh, 720px);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
  background: var(--bg); /* shown while tiles load */
}

/* Marker: a brand-teal dot drawn in CSS, so no Leaflet image assets are needed. */
.map-pin__dot {
  display: block; width: 18px; height: 18px; border-radius: 50%;
  background: var(--brand); border: 3px solid #fff;
  box-shadow: 0 1px 4px rgba(29,39,51,.45);
  transition: transform .12s ease;
}
.map-pin:hover .map-pin__dot,
.map-pin:focus-visible .map-pin__dot { transform: scale(1.25); }

.map-popup { width: 200px; }
.map-popup__image {
  display: block; width: 100%; aspect-ratio: 4 / 3;
  object-fit: cover; border-radius: var(--radius-sm); margin-bottom: 9px;
}
.map-popup__title { margin: 0; font-weight: 700; font-size: .98rem; color: var(--ink); }
.map-popup__link { display: inline-block; margin-top: 9px; font-weight: 600; font-size: .9rem; }

/* Scouting pins (admin only). Solid = the applicant's own wording says second
   storey; hollow = the score guessed, so the drive is what settles it. */
.map-pin--confirmed .map-pin__dot { background: #9E4527; }
.map-pin--candidate .map-pin__dot { background: transparent; border-color: #254B75; box-shadow: none; }
.map-popup__builder { margin: 4px 0 0; font-weight: 600; font-size: .9rem; color: var(--brand); }
.map-popup__meta { margin: 2px 0 0; font-size: .84rem; color: var(--muted); }
.map-popup__evidence {
  margin: 6px 0 0; font-size: .82rem; color: var(--ink-soft);
  border-left: 2px solid var(--line); padding-left: 7px;
}

/* ---------- Admin permit tracker ---------- */
/* Status is the column that gets scanned, so it carries colour and everything
   else stays quiet.
   The colours track the permit's progress toward a finished house, not how
   interesting it is: In Progress is red because the permit is still in review
   and there is nothing on site yet, Issued is amber because work can start,
   Permit Finaled is green because it's done and walkable. Grey is unknown.
   Class names follow the *status*, so the colour lives here and only here. */
.permit-status {
  display: inline-block; padding: 2px 8px; border-radius: 999px;
  font-size: .8rem; font-weight: 700; white-space: nowrap;
  border: 1px solid transparent;
}
.permit-status--in_progress { background: #FBE3DE; color: #8C2F14; border-color: #E9B7A9; }
.permit-status--issued      { background: #FBF0D0; color: #7A5A05; border-color: #E8D48A; }
.permit-status--finaled     { background: #DCEFE0; color: #1F6135; border-color: #A9D2B6; }
.permit-status--other       { background: #E6E8EA; color: #4A535B; border-color: #CBD1D6; }

.permit-filters { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 16px; }
.permit-chip {
  display: inline-block; padding: 4px 11px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--surface);
  color: var(--ink-soft); font-size: .85rem; font-weight: 600; text-decoration: none;
}
.permit-chip:hover { border-color: var(--ink); color: var(--ink); }
.permit-chip.is-on { background: var(--ink); border-color: var(--ink); color: #fff; }

.permit-table-wrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--radius); }
.permit-table { border-collapse: collapse; width: 100%; min-width: 62rem; font-size: .9rem; }
.permit-table th {
  text-align: left; padding: 10px 12px; background: var(--surface);
  border-bottom: 1px solid var(--line); font-size: .78rem;
  text-transform: uppercase; letter-spacing: .06em; color: var(--muted); font-weight: 700;
}
.permit-table td { padding: 10px 12px; border-bottom: 1px solid var(--line); vertical-align: top; }
.permit-table tbody tr:last-child td { border-bottom: 0; }
.permit-table tbody tr:hover td { background: var(--surface); }
.permit-table__date, .permit-table__record { white-space: nowrap; font-variant-numeric: tabular-nums; }
.permit-table__record { color: var(--muted); font-size: .82rem; }
.permit-table__address { font-weight: 600; }
.permit-table__hood { display: block; font-weight: 400; color: var(--muted); font-size: .82rem; }
.permit-table__scope { color: var(--ink-soft); max-width: 30rem; }
.permit-table__pending { color: var(--muted); font-style: italic; }
.permit-changed { display: block; margin-top: 4px; font-size: .76rem; color: var(--muted); }

/* ---------- The /active gate ---------- */
/* The public permit page shows three columns, not six, so it doesn't need the
   62rem floor the admin table uses to keep its wide "what the applicant wrote"
   column readable. At 34rem it fits a phone without sideways scrolling. */
.permit-table--public { min-width: 34rem; }

.active-page { padding-block: 8px 40px; }
.active-page__note { margin: 14px 0 0; color: var(--muted); font-size: .9rem; }

/* The gate is a <tbody> of the permit table, not a card above it, so the locked
   rows inherit the real columns, padding and borders — them being visibly the
   same table is what says "there is more of this". The blur is honest: these
   rows carry no permit data and the ones they stand for were never queried, so
   there is nothing to recover by switching the filter off. See
   ActivePermitsController.

   The first version of this failed for three compounding reasons, all fixed
   here: the bars were --line (#e7e9e4) on white and near-invisible before the
   blur even touched them, the blur was 5px on a .7rem bar, and a veil at
   rgba(...,.82) covered the whole block including the rows it was teasing. */
.permit-gate__bar {
  display: inline-block; height: .68rem; border-radius: 4px;
  background: #c3c8be;
  filter: blur(3.5px);
}
/* Mirrors how a real address cell stacks .permit-table__hood under the street. */
.permit-gate__bar--sub { display: block; height: .5rem; margin-top: 7px; opacity: .7; }
.permit-gate .permit-status { filter: blur(3.5px); }

.permit-gate td { user-select: none; }
/* .permit-table offers a hover background on every row; a locked row isn't
   something you can interact with, so it doesn't respond. */
.permit-gate tr:hover td { background: transparent; }
/* .permit-table drops the border on its last row, which now also lands on the
   last locked row. Restore it, heavier, to mark where locked ends and free
   begins. */
.permit-gate tr:last-child td { border-bottom: 2px solid var(--line); }

.permit-gate__pitch td {
  text-align: center; padding: 26px 16px;
  /* A shade off the white rows, so the pitch reads as an interruption of the
     table rather than another row of it. */
  background: var(--bg);
}
.permit-gate__pitch h2 { margin: 0 0 6px; font-size: 1.15rem; }
.permit-gate__pitch p {
  margin: 0 auto; max-width: 34rem;
  color: var(--ink-soft); font-size: .92rem;
}
.permit-gate__pitch .btn { margin-top: 12px; }
.permit-gate__aside { margin-top: 10px; color: var(--muted); font-size: .85rem; }

/* ---------- /active on a phone ---------- */
/* Three columns can't hold a date, a status pill and a street address inside
   390px, so .permit-table-wrap's overflow-x took over and the public page met
   visitors sideways-scrolling. Below 640px each row becomes a card instead.

   Scoped to --public throughout: /admin/permits is a desk tool, and its six
   columns (one of them the wide "what the applicant wrote") stay as they are.

   The gate needs no markup of its own here — a locked row is the same <tr>, so
   it stacks into a locked card and goes on standing in for the rows above it.
   Three things in it do need undoing, all of them below: the per-cell borders
   (which become a rule under every field once cells are blocks), the 2px rule
   that marks where locked ends and free begins (it belongs to the row, not to
   three separate cells), and the pitch's own padding (the row's padding would
   otherwise leave its tint floating in a white margin). */
@media (max-width: 640px) {
  .permit-table--public { min-width: 0; font-size: .95rem; }

  /* The header is what the cards replace. Every field is self-evident stacked
     except the date, which gets its label back through ::before. */
  .permit-table--public thead { display: none; }

  .permit-table--public tr {
    display: flex; flex-direction: column; gap: 6px;
    padding: 14px 12px; border-bottom: 1px solid var(--line);
  }
  .permit-table--public tbody tr:last-child { border-bottom: 0; }

  /* On desktop the cell carries the padding and the rule; in a card the row
     owns both, or every field inside it gets a line underneath. */
  .permit-table--public td { display: block; padding: 0; border-bottom: 0; }

  /* Address first — it is what someone scans for — then status, then the date.
     Visual order only; the DOM keeps the column order the <thead> describes.
     None of these cells hold anything focusable, so nothing's tab order moves.
     The status cell is the one without a class, hence nth-child. */
  .permit-table--public .permit-table__address { order: 1; font-size: 1.05rem; }
  .permit-table--public td:nth-child(2) { order: 2; }
  .permit-table--public .permit-table__date { order: 3; font-size: .82rem; color: var(--muted); }
  .permit-table--public .permit-table__date::before { content: "Applied "; }

  /* No pointer to hover with; the row background would light up under a tap. */
  .permit-table--public tbody tr:hover td { background: transparent; }

  /* The rule that separates locked from free belongs to the row now. */
  .permit-table--public .permit-gate tr:last-child td { border-bottom: 0; }
  .permit-table--public .permit-gate tr:last-child { border-bottom: 2px solid var(--line); }

  /* The pitch is an interruption, not a card: its tint has to reach the edges. */
  .permit-table--public .permit-gate__pitch { padding: 0; }
  .permit-table--public .permit-gate__pitch td { padding: 24px 16px; }
}

/* ---------- Admin scouting map ---------- */
.scout-summary {
  display: flex; flex-wrap: wrap; gap: 8px 20px; align-items: baseline;
  margin: 0 0 14px;
}
.scout-summary__figure { font-weight: 700; font-size: 1.4rem; color: var(--ink); }
.scout-summary__label { color: var(--muted); font-size: .92rem; }
.scout-filter { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 0 0 14px; }
.scout-filter select { max-width: 20rem; }
.scout-legend { display: flex; flex-wrap: wrap; gap: 6px 18px; margin: 12px 0 0; color: var(--muted); font-size: .88rem; }
.scout-legend span { display: inline-flex; align-items: center; gap: 7px; }
.scout-legend i { width: 12px; height: 12px; border-radius: 50%; display: inline-block; }
.scout-legend .is-confirmed { background: #9E4527; }
.scout-legend .is-candidate { border: 2px solid #254B75; }

/* Leaflet's popup chrome, pulled toward the site's tokens. */
.leaflet-container { font: inherit; background: var(--bg); }
.leaflet-popup-content-wrapper { border-radius: var(--radius-sm); box-shadow: var(--shadow-lg); }
.leaflet-popup-content { margin: 12px; }

/* ---------- Footer ---------- */
.site-footer {
  flex-shrink: 0;
  border-top: 1px solid var(--line);
  background: var(--surface);
  padding: 28px 0;
  color: var(--ink-soft);
  font-size: .92rem;
}
.site-footer p { margin: 0; }
.site-footer__muted { color: var(--muted); }
/* Underlined rather than brand-coloured: it has to read as a link inside the
   muted copyright line without shouting. */
.site-footer__link { color: var(--ink-soft); text-decoration: underline; }
.site-footer__link:hover { color: var(--ink); }

/* The "prefer your own email app?" line on the contact page. The link text is
   filled in by email_controller at runtime, so give it room even before JS. */
.contact-direct { margin-top: 1.5rem; }
.contact-direct__link { text-decoration: underline; }

/* ---------- Admin ---------- */
.admin-header { background: var(--ink); color: #fff; }
.admin-header__inner { display: flex; align-items: center; justify-content: space-between; min-height: 60px; gap: 12px; flex-wrap: wrap; }
.admin-header .brand, .admin-header .brand:hover { color: #fff; }
.admin-header .brand__mark { color: var(--accent); }
.admin-header .brand__badge { background: rgba(255,255,255,.15); color: #fff; }
.admin-nav__link { color: #c9d0d8; }
.admin-nav__link:hover { color: #fff; background: rgba(255,255,255,.1); }
.admin-main { padding: 32px 0 64px; }

.page-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin-bottom: 24px; }
.page-head h1 { margin: 0; font-size: 1.6rem; }
.page-head__actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* Buttons */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  font-family: inherit; font-weight: 600; font-size: .95rem;
  padding: 9px 16px; border-radius: var(--radius-sm);
  border: 1px solid transparent; cursor: pointer; text-decoration: none;
  transition: background .12s ease, border-color .12s ease;
}
.btn--primary { background: var(--brand); color: #fff; }
.btn--primary:hover { background: var(--brand-dk); color: #fff; }
.btn--ghost { background: var(--surface); color: var(--ink); border-color: var(--line); }
.btn--ghost:hover { background: #f2f3ef; color: var(--ink); }
/* Sits inline in a paragraph rather than starting its own block. */
.btn--inline { display: inline-flex; padding: 4px 12px; font-size: .85rem; }
.btn--inline form, form.button_to { display: inline; }

/* Stat grid */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 16px;
  margin-bottom: 32px;
}
.stat {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 20px; box-shadow: var(--shadow);
  display: flex; flex-direction: column; gap: 4px;
}
.stat__value { font-size: 2rem; font-weight: 700; letter-spacing: -.02em; }
/* A number that is reported but deliberately not claimed as real traffic. */
.stat--muted { background: transparent; box-shadow: none; border-style: dashed; }
.stat--muted .stat__value { color: var(--muted); font-weight: 600; }
.stat__label { color: var(--muted); font-size: .85rem; font-weight: 600; text-transform: uppercase; letter-spacing: .04em; }

/* Panels + tables */
.panel {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 22px; box-shadow: var(--shadow);
  margin-bottom: 24px;
}
.panel__title { margin: 0 0 14px; font-size: 1.15rem; }
.table { width: 100%; border-collapse: collapse; font-size: .95rem; }
.table th { text-align: left; color: var(--muted); font-size: .78rem; text-transform: uppercase; letter-spacing: .05em; padding: 0 12px 10px; border-bottom: 1px solid var(--line); }
.table td { padding: 12px; border-bottom: 1px solid var(--line); vertical-align: middle; }
.table tr:last-child td { border-bottom: 0; }
.table__num { text-align: right; }
/* The featured slot number in the admin property list. */
.badge--featured {
  display: inline-block; min-width: 22px;
  background: var(--brand); color: #fff;
  font-size: .78rem; font-weight: 700;
  padding: 2px 7px; border-radius: 999px;
}
.table__actions { text-align: right; white-space: nowrap; display: flex; gap: 12px; justify-content: flex-end; align-items: center; }
.link-danger { color: var(--danger); background: none; border: 0; cursor: pointer; font: inherit; font-weight: 600; padding: 0; }
.link-danger:hover { text-decoration: underline; }
.muted { color: var(--muted); }

/* Analytics chart */
.panel__head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 14px; }
.panel__head .panel__title { margin: 0; }
.chart__note { margin: 0; color: var(--muted); font-size: .82rem; }
.chart-legend { list-style: none; display: flex; flex-wrap: wrap; gap: 16px; margin: 0 0 12px; padding: 0; }
.chart-legend__item { display: inline-flex; align-items: center; gap: 7px; font-size: .85rem; color: var(--ink-soft); font-weight: 600; }
.chart-legend__swatch { width: 12px; height: 12px; border-radius: 3px; }
.chart { width: 100%; overflow-x: auto; }
.chart__svg { width: 100%; min-width: 560px; height: auto; display: block; }
.chart__grid { stroke: var(--line); stroke-width: 1; }
.chart__axis { fill: var(--muted); font-size: 12px; }
.chart__axis--y { text-anchor: end; }
.chart__axis--x { text-anchor: middle; }
.chart__svg rect:hover { fill: rgba(29,39,51,.04); }
.chart-data { margin-top: 14px; }
.chart-data > summary { cursor: pointer; color: var(--brand); font-weight: 600; font-size: .88rem; }

/* Forms */
.form { max-width: 640px; }
.form__row { margin-bottom: 18px; display: flex; flex-direction: column; gap: 6px; }
.form__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 0 20px; }
.form label { font-weight: 600; font-size: .92rem; }
.form input[type="text"], .form input[type="email"], .form input[type="password"], .form textarea, .form select {
  font-family: inherit; font-size: 1rem;
  padding: 10px 12px; border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink); width: 100%;
}
.form input:focus, .form textarea:focus, .form select:focus {
  outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px rgba(31,122,140,.15);
}
.form__hint, .form__row .form__hint { color: var(--muted); font-size: .85rem; margin: 0; }
.form__actions { display: flex; gap: 10px; margin-top: 8px; }
.form__errors {
  background: var(--alert-bg); color: var(--alert-ink);
  border-radius: var(--radius-sm); padding: 14px 18px; margin-bottom: 20px;
}
.form__errors ul { margin: 8px 0 0; padding-left: 18px; }
.form__warning {
  background: var(--alert-bg); color: var(--alert-ink);
  border-radius: var(--radius-sm); padding: 14px 18px; margin-bottom: 20px;
  display: grid; gap: 10px; justify-items: start;
}
.form__warning p { margin: 0; }
.form__check { display: flex; align-items: center; gap: 8px; }
.form__consent { margin: 14px 0 0; color: var(--muted); font-size: .82rem; line-height: 1.5; }
/* Honeypot field on the sign-up form. Off-screen rather than display:none so a
   script reading the markup can't tell it's hidden; aria-hidden + tabindex="-1"
   on the element itself keep it away from screen readers and the tab order. */
.form__decoy { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* Photo manager */
.photo-manager { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 14px; }
.photo-manager__item { position: relative; border-radius: var(--radius-sm); overflow: hidden; border: 1px solid var(--line); }
.photo-manager__image { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
.photo-manager__remove {
  position: absolute; top: 6px; right: 6px;
  background: rgba(255,255,255,.92); color: var(--danger);
  padding: 4px 9px; border-radius: 999px; font-size: .8rem; box-shadow: var(--shadow);
}
.photo-manager__remove:hover { text-decoration: none; background: #fff; }

/* Auth (sign-in) */
.auth-card {
  max-width: 400px; margin: 56px auto; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 32px; box-shadow: var(--shadow);
}
.auth-card h1 { margin: 0 0 20px; font-size: 1.4rem; text-align: center; }
.auth-card__lead { margin: -8px 0 20px; color: var(--ink-soft); text-align: center; }
.auth-card__aside { margin-top: 18px; text-align: center; font-size: .92rem; }

/* ---------- Favorite notes ---------- */
/* The note is what makes a shared collection worth sending, so it sits inside
   the card rather than behind a disclosure. */
.note { display: block; border-top: 1px solid var(--line); padding: 12px 14px 14px; }
.note__label {
  display: block; color: var(--muted); font-size: .74rem;
  font-weight: 600; text-transform: uppercase; letter-spacing: .04em;
  margin-bottom: 6px;
}
.note__field {
  width: 100%; resize: vertical; font: inherit; font-size: .92rem;
  padding: 8px 10px; border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: #fcfcfb; color: var(--ink);
}
.note__field:focus { outline: 2px solid var(--brand); outline-offset: 1px; }
.note__actions { display: flex; align-items: center; gap: 10px; margin-top: 8px; }
.note__saved { color: var(--brand); font-size: .85rem; font-weight: 600; }
.note__error { color: #b3261e; font-size: .85rem; margin: 6px 0 0; }

/* ---------- Share panel (favorites page) ---------- */
.share-panel {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 20px 22px;
  box-shadow: var(--shadow);
  /* Clear of the hero's bottom edge — flush against it read as a mistake. */
  margin: 32px 0 28px;
}
.share-panel__title { margin: 0 0 6px; font-size: 1.15rem; }
.share-panel__body { margin: 0 0 14px; color: var(--ink-soft); max-width: 62ch; }
.share-panel__link { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.share-panel__url {
  flex: 1 1 260px; min-width: 0; font: inherit; font-size: .9rem;
  padding: 9px 12px; border: 1px solid var(--line);
  border-radius: var(--radius-sm); background: #fcfcfb; color: var(--ink);
}
.share-panel__actions { display: flex; gap: 12px; align-items: center; margin-top: 14px; flex-wrap: wrap; }

/* ---------- Shared collection page ---------- */
.hero--compact { padding: 36px 0 28px; }
.collection { padding-bottom: 48px; }
.collection__list { display: flex; flex-direction: column; gap: 24px; margin: 28px 0; }
.entry {
  display: grid; grid-template-columns: minmax(0, 320px) minmax(0, 1fr); gap: 22px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow);
}
.entry__media { position: relative; }
.entry__body { padding: 18px 20px 20px; }
.entry__address { font-size: 1.15rem; margin: 0 0 4px; }
.entry__meta { color: var(--muted); font-size: .9rem; margin: 0 0 12px; }
/* The sender's own words — set apart from the site's copy so an architect can
   tell at a glance which is which. */
.entry__note {
  margin: 0 0 12px; padding: 10px 14px;
  border-left: 3px solid var(--brand); background: #f4f9fa;
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
.entry__note p { margin: 0; }
.entry__description { color: var(--ink-soft); margin: 0; font-size: .95rem; }
.collection__foot { font-size: .9rem; }

@media (max-width: 640px) {
  .entry { grid-template-columns: 1fr; gap: 0; }
}

/* ---------- Guides (editorial layer) ---------- */
/* The index of guides. */
.guides-index { padding-top: 32px; padding-bottom: 48px; }
.guides-index__header { max-width: 680px; margin-bottom: 28px; }
.guides-index__header h1 { font-size: 2rem; margin: 0 0 10px; }
.guides-index__lead { color: var(--ink-soft); font-size: 1.05rem; margin: 0; }
.guides-index__list { list-style: none; padding: 0; margin: 0; display: grid; gap: 16px; }
.guide-card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 22px 24px; box-shadow: var(--shadow);
}
.guide-card__title { font-size: 1.25rem; margin: 0 0 8px; }
.guide-card__desc { color: var(--ink-soft); margin: 0 0 10px; }
.guide-card__meta { color: var(--muted); font-size: .82rem; margin: 0; }

/* A single guide — a readable measure for long-form prose. */
.guide { max-width: 720px; padding-top: 24px; padding-bottom: 56px; }
.guide__crumbs { font-size: .85rem; color: var(--muted); margin-bottom: 18px; }
.guide__crumb-sep { margin: 0 8px; }
.guide__header { margin-bottom: 28px; }
.guide__title { font-size: 2.1rem; margin: 0 0 8px; }
.guide__meta { color: var(--muted); font-size: .85rem; margin: 0; }

/* Bottom line up front — grey callout with a black border, above the body. */
.guide__bluf {
  background: #f1f2ef;
  border: 2px solid #111418;
  border-radius: var(--radius-sm);
  padding: 16px 20px;
  margin: 0 0 32px;
}
.guide__bluf-label {
  font-size: .78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--ink);
  margin: 0 0 8px;
}
.guide__bluf-text { font-size: 1.02rem; line-height: 1.6; color: var(--ink); margin: 0; }
.guide__bluf-list { margin: 0; padding-left: 22px; }
.guide__bluf-list li { margin-bottom: 6px; line-height: 1.5; }
.guide__bluf-list li:last-child { margin-bottom: 0; }

.guide__body { font-size: 1.06rem; line-height: 1.7; color: var(--ink); }
.guide__body h2 { font-size: 1.5rem; margin: 40px 0 12px; }
.guide__body h3 { font-size: 1.15rem; margin: 28px 0 8px; }
.guide__body p { margin: 0 0 18px; }
.guide__body ul, .guide__body ol { margin: 0 0 18px; padding-left: 22px; }
.guide__body li { margin-bottom: 8px; }
.guide__body strong { font-weight: 700; }
.guide__body a { color: var(--brand); text-decoration: underline; }
.guide__body a:hover { color: var(--brand-dk); }
/* A guide can show one real photo (e.g. the worked example in the zoning guide).
   Cap the width so a tall portrait shot doesn't run the length of the screen. */
.guide__body img { display: block; width: 100%; max-width: 460px; height: auto; margin: 8px 0 6px; border-radius: 10px; }
/* A wide, label-dense diagram (e.g. the bulk-plane illustration) needs the full
   column to stay legible, not the portrait-photo cap above. */
.guide__body img[src*="bulk-plane"] { max-width: 100%; }
.guide__body img + em { display: block; font-size: 0.9rem; color: var(--ink-soft, #667); margin-bottom: 22px; }
.guide__body table {
  width: 100%; border-collapse: collapse; margin: 0 0 24px; font-size: .96rem;
  display: block; overflow-x: auto;
}
.guide__body th { text-align: left; padding: 10px 12px; border-bottom: 2px solid var(--line); font-size: .82rem; text-transform: uppercase; letter-spacing: .03em; color: var(--ink-soft); }
.guide__body td { padding: 10px 12px; border-bottom: 1px solid var(--line); vertical-align: top; }
.guide__body tr:last-child td { border-bottom: 0; }

/* The lead-capture CTA every guide ends in. Visually a distinct block so it
   reads as "the next step", not as more article. */
.lead-form {
  margin-top: 48px; padding: 28px; border-radius: var(--radius);
  background: var(--ok-bg); border: 1px solid var(--line);
}
.lead-form__heading { font-size: 1.4rem; margin: 0 0 8px; }
.lead-form__lead { color: var(--ink-soft); margin: 0 0 20px; }
.lead-form__form { max-width: none; }
.lead-form__form .form__actions { margin-top: 16px; }

@media (max-width: 640px) {
  .guide__title { font-size: 1.7rem; }
  .lead-form { padding: 22px 18px; }
}

/* ---------- Historic-address lookup (embedded in a guide) ---------- */
.hlookup { margin: 26px 0; padding: 20px 22px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); }
/* Out-specify `.guide__body p` (0,1,1) so the widget's own spacing wins. */
.guide__body .hlookup p { margin: 0 0 12px; }
.guide__body .hlookup p:last-child { margin-bottom: 0; }
.hlookup__prompt { font-weight: 700; }
.hlookup__form { max-width: none; }
.hlookup__row { display: flex; gap: 10px; align-items: stretch; flex-wrap: wrap; }
.hlookup__input { flex: 1 1 220px; font-size: 1rem; padding: 10px 12px; border: 1px solid var(--line); border-radius: var(--radius-sm); background: #fff; }
.hlookup__result { margin-top: 14px; padding: 14px 16px; border-radius: var(--radius-sm); border: 1px solid var(--line); background: var(--bg); }
.guide__body .hlookup__result p { margin: 0 0 4px; }
.guide__body .hlookup__result p:last-child { margin-bottom: 0; }
.hlookup__answer { font-weight: 700; }
.hlookup__detail { color: var(--ink-soft); font-size: .95rem; }
.hlookup__result--yes { background: #fdf3e2; border-color: var(--accent); }
.hlookup__result--yes .hlookup__answer { color: #9a5b12; }
.hlookup__result--no { background: var(--ok-bg); border-color: var(--ok-ink); }
.hlookup__result--no .hlookup__answer { color: var(--ok-ink); }
.hlookup__result--parkway { background: #eaf1f7; border-color: #4a739c; }
.hlookup__result--parkway .hlookup__answer { color: #2f5273; }
.hlookup__disclaimer { color: var(--muted); font-size: .82rem; }
.hlookup__notice { color: var(--alert-ink); background: var(--alert-bg); padding: 8px 12px; border-radius: var(--radius-sm); font-size: .9rem; }

/* ---------- Print ---------- */
/* Architects print these and mark them up. Drop the site chrome, let entries
   break sensibly across pages, and spell out the links that survive on paper. */
@media print {
  .site-header, .site-footer, .share-panel, .view-toggle, .permit-gate,
  .property-card__actions, .note, .pager, .collection__foot { display: none !important; }

  body { background: #fff; color: #000; }
  .hero { background: none; border-bottom: 1px solid #ccc; padding: 0 0 16px; }
  .entry {
    box-shadow: none; border: 1px solid #ccc;
    break-inside: avoid; page-break-inside: avoid;
  }
  .entry__note { background: none; border-left: 3px solid #666; }
  /* The photo strip can't be swiped on paper — show the first frame only. */
  .property-card__scroller { overflow: visible; }
  .property-card__slide:not(:first-child) { display: none; }
  .property-card__dots { display: none; }
  .entry__address a::after { content: " (" attr(href) ")"; font-size: .75em; font-weight: 400; }
}
