/* =====================================================================
   Bunk-a-Biker map

   Constraints this stylesheet obeys:
     - Light surfaces, dark text, high contrast. Always.
     - Tap targets 44px minimum. Usable with gloves.
     - Mobile first. Desktop is the enhancement, not the baseline.
     - The five pin colours are fixed semantics from the existing
       network. Everything else stays near-neutral so they can shout.
   ===================================================================== */

:root {
  /* Surfaces. Cool grey, not cream -- the map is warm, the chrome is not. */
  --surface:        #f2f3f1;
  --surface-raised: #ffffff;
  --surface-sunk:   #e6e8e5;
  --hairline:       #cfd3ce;

  /* Ink. Primary action is ink, deliberately not a sixth hue, so it
     never competes with pin semantics. */
  --ink:            #14171a;
  --ink-2:          #4a5157;
  --ink-3:          #767f86;

  /* Pin semantics. Fixed by the network, not a design choice. */
  --pin-both:       #6a1b9a;  /* purple: inside and outside */
  --pin-inside:     #c62828;  /* red */
  --pin-outside:    #2e7d32;  /* green */
  --pin-info:       #1565c0;  /* blue: local info / breakdown only */
  --pin-none:       #b58900;  /* amber: unspecified */

  --unavailable:    #9aa3a9;

  --tap:            44px;
  --sheet-radius:   18px;

  --shadow-1: 0 1px 2px rgba(20, 23, 26, .10);
  --shadow-2: 0 6px 24px rgba(20, 23, 26, .16);

  /* No webfonts. A font CDN is a third-party request on every load and a
     blocking fetch on bad rural signal. Personality comes from weight,
     tracking and scale instead. */
  --sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
          "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  overscroll-behavior: none;
  font-family: var(--sans);
  color: var(--ink);
  background: var(--surface);
  -webkit-text-size-adjust: 100%;
}

:root {
  --map-head-h: 56px;
  --map-foot-h: 42px;
}

/* The map fills the space between the bars rather than sitting under
   them. A translucent bar over a map looks fine until someone tries to
   read a place name through it. */
#map {
  position: absolute;
  top: calc(var(--map-head-h) + env(safe-area-inset-top));
  bottom: calc(var(--map-foot-h) + env(safe-area-inset-bottom));
  left: 0;
  right: 0;
}

/* --- Top bar ------------------------------------------------------- */

.topbar {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: 10px;
  height: calc(var(--map-head-h) + env(safe-area-inset-top));
  padding: 0 12px;
  padding-top: env(safe-area-inset-top);
  /* Solid, not a gradient fading into the map. The bar is chrome and
     should read as chrome. */
  background: var(--surface-raised);
  border-bottom: 1px solid var(--hairline);
  pointer-events: auto;
}
.topbar > * { pointer-events: auto; }
/* The menu must never be the thing that gets pushed off-screen. */
.topbar .nav { flex: 0 0 auto; }

/* The nav sits above the map, so it needs to clear the MapLibre canvas
   and its controls. */
.topbar .nav { z-index: 12; }

.wordmark {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  color: var(--ink);
  text-decoration: none;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: -.02em;
  white-space: nowrap;
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* "hosts" is decoration; drop it before anything functional is lost. */
.wordmark span { color: var(--ink-3); font-weight: 500; }
@media (max-width: 560px) { .wordmark span { display: none; } }
/* Below this the mark alone carries the branding; the words would push
   the menu off-screen. */
@media (max-width: 420px) { .wordmark { font-size: 0; gap: 0; } }
.wordmark-logo { display: block; flex: 0 0 auto; }

.count {
  margin-left: auto;
  margin-right: 4px;
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink-2);
  background: var(--surface-raised);
  border: 1px solid var(--hairline);
  border-radius: 999px;
  padding: 6px 10px;
  white-space: nowrap;
}

/* --- Filter rail ---------------------------------------------------
   Horizontally scrollable on phones so it never wraps into two rows
   and eats the map. */

/* Operator information. On a phone the hamburger matters more, so this
   goes first when space runs out. */
.build {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-3);
  padding: 6px 4px;
  white-space: nowrap;
}
@media (max-width: 700px) { .build { display: none; } }

.filters {
  display: flex;
  gap: 8px;
  padding: 0 12px;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.filters::-webkit-scrollbar { display: none; }

/* A fade at the right edge, so a rail with more chips off-screen looks
   scrollable instead of looking finished. */
.filters-wrap {
  position: fixed;
  left: 0; right: 0;
  bottom: calc(var(--map-foot-h) + env(safe-area-inset-bottom) + 12px);
  z-index: 9;
  transition: transform .26s cubic-bezier(.2,.8,.25,1);
}
.filters-wrap::after {
  content: "";
  position: absolute;
  top: 0; bottom: 0; right: 0;
  width: 28px;
  pointer-events: none;
  background: linear-gradient(to right, rgba(242,243,241,0), rgba(242,243,241,.92));
}
body.sheet-open .filters-wrap { transform: translateY(calc(-1 * var(--peek, 96px))); }

body.sheet-open /* Operator information. On a phone the hamburger matters more, so this
   goes first when space runs out. */
.build {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-3);
  padding: 6px 4px;
  white-space: nowrap;
}
@media (max-width: 700px) { .build { display: none; } }

.filters { transform: translateY(calc(-1 * var(--peek, 96px))); }

.chip {
  flex: 0 0 auto;
  min-height: var(--tap);
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 0 14px;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  background: var(--surface-raised);
  color: var(--ink-2);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .01em;
  box-shadow: var(--shadow-1);
  cursor: pointer;
  transition: background .12s, color .12s, border-color .12s;
}
.chip:focus-visible { outline: 3px solid var(--ink); outline-offset: 2px; }
.chip[aria-pressed="true"] {
  background: var(--ink);
  color: #fff;
  border-color: var(--ink);
}
.chip .dot {
  width: 11px; height: 11px;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.28);
}
/* Swatches carry the network's fixed pin semantics, so they are named
   after meaning rather than colour. R15: no inline styles. */
.dot--inside  { background: var(--pin-inside); }
.dot--outside { background: var(--pin-outside); }
.dot--both    { background: var(--pin-both); }
.dot--info    { background: var(--pin-info); }

/* --- Bottom sheet ---------------------------------------------------
   Three detents: peek, half, full. Peek shows the name and a call
   button, so a tapped pin is one tap from a phone call. That is the
   whole point -- the current map takes many more. */

.sheet {
  position: fixed;
  left: 0; right: 0;
  bottom: calc(var(--map-foot-h) + env(safe-area-inset-bottom));
  z-index: 20;
  background: var(--surface-raised);
  border-radius: var(--sheet-radius) var(--sheet-radius) 0 0;
  box-shadow: var(--shadow-2);
  transform: translateY(100%);
  transition: transform .26s cubic-bezier(.2,.8,.25,1);
  max-height: calc(100vh - var(--map-head-h) - var(--map-foot-h)
                   - env(safe-area-inset-top) - env(safe-area-inset-bottom)
                   - 8px);
  display: flex;
  flex-direction: column;
  padding-bottom: env(safe-area-inset-bottom);
}
.sheet.is-peek { transform: translateY(calc(100% - var(--peek, 96px))); }
.sheet.is-half { transform: translateY(45%); }
.sheet.is-full { transform: translateY(0); }

.grabber {
  flex: 0 0 auto;
  width: 100%;
  min-height: 28px;
  border: 0;
  background: transparent;
  display: grid;
  place-items: center;
  cursor: grab;
  touch-action: none;
}
.grabber::after {
  content: "";
  width: 40px; height: 4px;
  border-radius: 2px;
  background: var(--hairline);
}

.sheet-head {
  flex: 0 0 auto;
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 2px 16px 12px;
}

.sheet-title { min-width: 0; }
.sheet-title h2 {
  margin: 0;
  font-size: 20px;
  line-height: 1.2;
  letter-spacing: -.02em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sheet-title p {
  margin: 3px 0 0;
  font-size: 13px;
  color: var(--ink-2);
}

.call {
  flex: 0 0 auto;
  min-height: var(--tap);
  min-width: var(--tap);
  padding: 0 18px;
  border: 0;
  border-radius: 12px;
  background: var(--ink);
  color: #fff;
  font: inherit;
  font-size: 14px;
  font-weight: 700;
  cursor: pointer;
}
.call:focus-visible { outline: 3px solid var(--pin-info); outline-offset: 2px; }
.call[disabled] { background: var(--surface-sunk); color: var(--ink-3); cursor: default; }

.sheet-body {
  flex: 1 1 auto;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 0 16px 20px;
}

/* --- Offering tags -------------------------------------------------- */

.tags { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 14px; }
.tag {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  padding: 5px 9px;
  border-radius: 6px;
  background: var(--surface-sunk);
  color: var(--ink-2);
}
.tag.is-warn { background: #fdf1d8; color: #7a5600; }

/* --- Detail rows ---------------------------------------------------- */

.rows { margin: 0 0 16px; }
.row {
  display: grid;
  grid-template-columns: 104px 1fr;
  gap: 12px;
  padding: 9px 0;
  border-top: 1px solid var(--hairline);
  font-size: 14px;
  line-height: 1.45;
}
.row dt {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding-top: 2px;
}
.row dd { margin: 0; }

.desc {
  white-space: pre-wrap;
  font-size: 14px;
  line-height: 1.55;
  color: var(--ink);
  margin: 0 0 16px;
}

/* --- Availability notice -------------------------------------------- */

.notice {
  display: flex;
  gap: 10px;
  padding: 12px 14px;
  border-radius: 12px;
  background: var(--surface-sunk);
  font-size: 13px;
  line-height: 1.45;
  margin: 0 0 14px;
}
.notice strong { display: block; margin-bottom: 2px; }

/* --- Contact gate ---------------------------------------------------
   Contact details are never in the public payload. This is the seam
   where the account wall goes. */

.gate {
  border: 1px dashed var(--hairline);
  border-radius: 12px;
  padding: 16px;
  text-align: center;
  font-size: 13px;
  color: var(--ink-2);
  line-height: 1.5;
}
.gate strong { display: block; color: var(--ink); margin-bottom: 4px; font-size: 14px; }

/* --- Empty state ----------------------------------------------------- */

.empty {
  position: fixed;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  z-index: 8;
  max-width: 300px;
  text-align: center;
  background: var(--surface-raised);
  border: 1px solid var(--hairline);
  border-radius: 14px;
  padding: 20px 22px;
  box-shadow: var(--shadow-2);
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink-2);
}
.empty strong { display: block; color: var(--ink); margin-bottom: 6px; font-size: 15px; }
.empty[hidden] { display: none; }

/* --- Desktop --------------------------------------------------------
   The sheet becomes a fixed left panel. Plan on a computer, use on the
   phone -- same code, different shape. */

@media (min-width: 860px) {
  .sheet {
    left: 16px;
    top: 64px;
    bottom: 16px;
    right: auto;
    width: 380px;
    max-height: none;
    border-radius: 16px;
    transform: translateX(calc(-100% - 24px));
    transition: transform .26s cubic-bezier(.2,.8,.25,1);
  }
  .sheet.is-peek,
  .sheet.is-half,
  .sheet.is-full { transform: translateX(0); }
  .grabber { display: none; }
  .sheet-head { padding-top: 16px; }
  /* Operator information. On a phone the hamburger matters more, so this
   goes first when space runs out. */
.build {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-3);
  padding: 6px 4px;
  white-space: nowrap;
}
@media (max-width: 700px) { .build { display: none; } }

.filters { bottom: 16px; left: 412px; right: 16px; padding: 0; }
  body.sheet-open /* Operator information. On a phone the hamburger matters more, so this
   goes first when space runs out. */
.build {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-3);
  padding: 6px 4px;
  white-space: nowrap;
}
@media (max-width: 700px) { .build { display: none; } }

.filters { transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .sheet   { transition: none; }
  .chip    { transition: none; }
  /* Operator information. On a phone the hamburger matters more, so this
   goes first when space runs out. */
.build {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-3);
  padding: 6px 4px;
  white-space: nowrap;
}
@media (max-width: 700px) { .build { display: none; } }

.filters { transition: none; }
}


/* MapLibre's own controls sit inside the map container, which now ends
   above the footer. Nudge the attribution clear of the filter rail. */
.maplibregl-ctrl-bottom-left,
.maplibregl-ctrl-bottom-right { bottom: 4px; }

/* --- Map footer ---------------------------------------------------------
   The same site navigation as every other page. Without it the map was
   a dead end: no way to reach the content pages without going back to
   the home page first.
   ------------------------------------------------------------------- */

.map-foot {
  position: fixed;
  bottom: 0; left: 0; right: 0;
  z-index: 40;
  min-height: calc(var(--map-foot-h) + env(safe-area-inset-bottom));
  display: flex;
  align-items: center;
  padding: 0 12px;
  padding-bottom: env(safe-area-inset-bottom);
  background: var(--surface-raised);
  border-top: 1px solid var(--hairline);
  overflow-x: auto;
  scrollbar-width: none;
}
.map-foot::-webkit-scrollbar { display: none; }
.map-foot .foot-nav {
  display: flex;
  flex-wrap: nowrap;
  gap: 0 16px;
  white-space: nowrap;
  font-size: 13px;
}
.map-foot .foot-nav a {
  color: var(--ink-2);
  text-decoration: none;
  min-height: 34px;
  display: inline-flex;
  align-items: center;
}

@media (min-width: 860px) {
  /* The sheet is a left panel on desktop; it must clear both bars. */
  .sheet {
    top: calc(var(--map-head-h) + 16px);
    bottom: calc(var(--map-foot-h) + 16px);
  }
  .filters-wrap { bottom: calc(var(--map-foot-h) + 16px); }
}

/* --- Logged-out approximate-location banner -------------------------
   Shown only to anonymous viewers. Sits below the topbar, over the map.
   Light surface, dark text; a sign-in nudge, not an obstruction. */
.map-approx-banner {
  position: absolute;
  top: 64px;
  left: 12px;
  right: 12px;
  z-index: 11;
  margin: 0 auto;
  max-width: 640px;
  padding: 10px 14px;
  border-radius: 12px;
  background: var(--surface-raised, #fff);
  border: 1px solid var(--hairline, #d9d5cd);
  box-shadow: 0 2px 10px rgba(0,0,0,.12);
  font-size: 13px;
  line-height: 1.4;
  color: var(--ink, #16181c);
  text-align: center;
  pointer-events: auto;
}
.map-approx-banner a { color: var(--accent, #23357a); font-weight: 600; }
