/*
 * 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, .admin-nav { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.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; }

/* ---------- 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; }

/* ---------- 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; }

/* ---------- 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); }

/* ---------- 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; }
}

/* ---------- 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; }
}
