/**
 * Design system tokens — see DESIGN_SYSTEM.md for the documented version
 * (color roles, type scale, component patterns). This is a single fixed
 * light brand look (no dark-mode variant) modeled on an editorial
 * food-app reference: bold display type, a warm full-bleed hero, a
 * white "paper" content sheet, and one black pill surface reserved for
 * the primary floating action (never used for inline buttons — those
 * stay amber).
 */
:root {
  --bg: #ffffff; /* page canvas */
  --sheet-bg: #ffffff; /* content sheet below the hero */
  --content-bg: #f7f7f7; /* the scrollable list/map area, one shade off the sheet's white bars */
  --card: #f7f5f1; /* inset surfaces: inputs, chips at rest */
  --card-border: #eae7e0; /* hairline dividers/borders */
  --text: #14140f; /* ink — primary text */
  --text-dim: #6b6a63; /* secondary/muted text */
  --accent: #e0781f; /* amber — brand accent for badges, tabs, inline buttons */
  --accent-dim: #ffe3c2; /* soft amber tint for icon circles */
  --pill: #14140f; /* black — reserved for the one floating CTA pill/bar */
  --green: #0f9d68; /* live/success status */
  --red: #d64545; /* destructive */
  --radius: 14px;
}

* { box-sizing: border-box; }

.hidden { display: none !important; }

body {
  margin: 0;
  font-family: "Fustat", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: var(--bg);
  color: var(--text);
  min-height: 100vh;
}

.app {
  max-width: 480px;
  margin: 0 auto;
  min-height: 100vh;
  background: var(--sheet-bg);
}

/* ---------- Hero ---------- */

.hero {
  background-image:
    radial-gradient(120% 100% at 15% 0%, rgba(255, 190, 110, 0.25), transparent 55%),
    linear-gradient(180deg, rgba(20, 12, 6, 0.35) 0%, rgba(15, 10, 7, 0.55) 60%, rgba(10, 7, 5, 0.85) 100%),
    url("https://images.unsplash.com/photo-1597290282695-edc43d0e7129?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&q=80&w=1600");
  background-size: auto, auto, cover;
  background-position: center, center, center;
  background-repeat: no-repeat;
  color: #fdf6ee;
  padding: 20px 24px 32px;
  overflow: hidden;
  /* Pinned behind the sheet — as the list scrolls, the opaque sheet rises
     up over this fixed layer instead of the hero scrolling away with it. */
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  max-width: 480px;
  margin: 0 auto;
  z-index: 0;
}

.hero-credit {
  position: absolute;
  bottom: 8px;
  right: 12px;
  font-size: 0.65rem;
  color: rgba(253, 246, 238, 0.6);
  text-decoration: none;
}
.hero-credit:hover {
  color: rgba(253, 246, 238, 0.9);
}

.hero-title {
  margin: 0;
  font-size: clamp(3rem, 15vw, 3.8rem);
  font-weight: 800;
  line-height: 0.92;
  letter-spacing: -0.02em;
  text-transform: uppercase;
}

.hero-dot {
  color: var(--accent);
}

.hero-tagline {
  margin: 12px 0 0;
  font-size: 1rem;
  color: rgba(253, 246, 238, 0.75);
}

/* ---------- Sheet ---------- */

.sheet {
  background: var(--content-bg);
  border-radius: 24px 24px 0 0;
  /* --hero-height is measured in JS (the fixed hero no longer occupies flow
     space) so the sheet starts right below it, then scrolls up to cover it. */
  margin-top: calc(var(--hero-height, 300px) - 18px);
  position: relative;
  z-index: 1;
  padding: 20px 20px 32px;
}

.search-row {
  display: flex;
  gap: 8px;
  margin-bottom: 14px;
}

.search-field {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--card);
  border: 1px solid var(--card-border);
  border-radius: 12px;
  padding: 10px 14px;
}
.search-icon {
  font-size: 0.9rem;
  opacity: 0.7;
}
.search-field input {
  flex: 1;
  min-width: 0;
  border: none;
  background: transparent;
  font-family: inherit;
  font-size: 0.95rem;
  color: var(--text);
  outline: none;
}
.search-field input::placeholder {
  color: var(--text-dim);
}

.filter-toggle-btn {
  position: relative;
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  border-radius: 12px;
  background: var(--card);
  border: 1px solid var(--card-border);
  font-size: 1.1rem;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.filter-toggle-btn.has-active {
  background: var(--accent);
  border-color: var(--accent);
}
.filter-count {
  position: absolute;
  top: -6px;
  right: -6px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--pill);
  color: #fff;
  font-size: 0.65rem;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
}

.filter-toggle-list {
  display: flex;
  flex-direction: column;
}
.filter-toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  font-family: inherit;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--card-border);
  padding: 16px 4px;
  font-size: 0.98rem;
  color: var(--text);
  cursor: pointer;
  text-align: left;
}
.filter-toggle-check {
  width: 22px;
  height: 22px;
  border-radius: 6px;
  border: 1.5px solid var(--card-border);
  flex-shrink: 0;
}
.filter-toggle-row.active .filter-toggle-check {
  background: var(--accent);
  border-color: var(--accent);
  position: relative;
}
.filter-toggle-row.active .filter-toggle-check::after {
  content: "✓";
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #1a1200;
  font-size: 0.8rem;
  font-weight: 700;
}

/* Persistent bottom List/Map switcher — replaces the old inline .view-tabs.
   Always visible (both views), fixed to the bottom of the screen. */
.bottom-nav {
  position: fixed;
  left: 50%;
  bottom: 20px;
  transform: translateX(-50%);
  z-index: 1300;
  display: flex;
  gap: 2px;
  background: var(--pill);
  border-radius: 999px;
  padding: 4px;
  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.3);
}
.bottom-nav .view-tab {
  font-family: inherit;
  border: none;
  background: transparent;
  color: rgba(253, 246, 238, 0.75);
  padding: 10px 22px;
  border-radius: 999px;
  font-size: 0.9rem;
  font-weight: 600;
  cursor: pointer;
}
.bottom-nav .view-tab.active {
  background: #fff;
  color: var(--pill);
}

/* Filter tabs: a full-bleed white bar with one hairline bottom border —
   plain text, not filled pill chips or a per-tab underline. Active vs.
   inactive reads entirely through weight/color (color is otherwise reserved
   for the live/upcoming status dots, not the filter UI). */
.filters {
  display: flex;
  align-items: center;
  gap: 16px;
  margin: 0 -20px 20px;
  padding: 16px 20px;
  background: #fff;
  border-bottom: 0.5px solid #000;
  overflow-x: auto;
  scrollbar-width: none;
}
.filters::-webkit-scrollbar {
  display: none;
}
.filter-btn {
  flex-shrink: 0;
  font-family: inherit;
  background: transparent;
  border: none;
  color: var(--text-dim);
  padding: 0;
  font-size: 0.875rem;
  font-weight: 400;
  cursor: pointer;
  white-space: nowrap;
}
.filter-btn.active {
  color: #000;
  font-weight: 600;
}

/* ---------- Venue list: rows grouped by status ----------
   "Happening now" / "Upcoming" sections, each a vertical stack of
   full-width rows (photo thumbnail + name/address + status & time). */

.venue-list {
  display: flex;
  flex-direction: column;
  gap: 24px;
  padding-bottom: 70px; /* clears the fixed bottom-nav pill */
}

.status-group-label {
  font-size: 0.9375rem;
  font-weight: 700;
  margin: 0 0 12px;
}

.status-group-rows {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.list-row {
  display: flex;
  align-items: center;
  gap: 14px;
  padding-right: 16px;
  border: 0.5px solid #000;
  border-radius: 8px;
  overflow: hidden;
  cursor: pointer;
}
.list-row:active {
  opacity: 0.85;
}

.list-row-photo {
  position: relative;
  flex-shrink: 0;
  width: 74px;
  height: 74px;
  background-color: var(--accent-dim);
  background-size: cover;
  background-position: center;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.4rem;
}

.list-row-edit {
  position: absolute;
  top: 4px;
  left: 4px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: none;
  background: rgba(255, 255, 255, 0.85);
  backdrop-filter: blur(6px);
  color: #1c1b1a;
  font-size: 0.7rem;
  line-height: 1;
  cursor: pointer;
}

.list-row-main {
  flex: 1;
  min-width: 0;
}

.list-row-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.list-row-name {
  font-weight: 700;
  font-size: 1rem;
  color: #000;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.list-row-time {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: "Space Mono", "SF Mono", Menlo, monospace;
  font-size: 1rem;
  color: #000;
}
.list-row-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--green);
  flex-shrink: 0;
}
.list-row-dot.upcoming {
  background: var(--accent);
}

.list-row-address {
  margin-top: 8px;
  font-size: 0.75rem;
  color: var(--text-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.empty-state {
  text-align: center;
  color: var(--text-dim);
  padding: 40px 20px;
}

/* ---------- Map view ----------
   Full-bleed and full-viewport when active — no hero/search/filter chrome,
   just the map. body.map-fullscreen hides the rest of the header (see
   below); .map-view escapes the sheet's layout entirely via position:fixed
   so it covers the whole screen regardless of scroll position. */

.map-view {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  /* dvh accounts for the mobile browser's address bar collapsing/expanding —
     inset:0 alone leaves the bottom of the map hidden behind it on iOS Safari. */
  height: 100vh;
  height: 100dvh;
  z-index: 30;
  display: flex;
  flex-direction: column;
}

.map-frame {
  position: relative;
  flex: 1;
  min-height: 0;
}

#map {
  height: 100%;
  width: 100%;
  background: var(--card);
}

/* Solid header bar (search + filter tabs) pinned to the top of the map —
   same content/behaviour as the list's, kept in sync via shared state in
   app.js, but its own DOM since the list's header stays hidden in map mode. */
.map-header {
  flex-shrink: 0;
  background: var(--sheet-bg);
  padding: 16px 20px 0;
  z-index: 1100;
}
.map-header .filters {
  margin: 0;
  padding: 0 0 16px;
  background: transparent;
  border-bottom: none;
  /* .filters scrolls horizontally, and an overflow container clips its
     children's shadows. These three pills always fit, so drop the scroll
     here rather than padding the box out — padding a transparent fixed
     overlay just enlarges the region that swallows map drags. */
  overflow: visible;
}

body.map-fullscreen .hero,
body.map-fullscreen .sheet > .search-row,
body.map-fullscreen .sheet > .filters {
  display: none;
}
body.map-fullscreen .sheet {
  padding: 0;
  margin-top: 0;
  border-radius: 0;
}

/* ---------- Map card carousel ----------
   A persistent swipeable strip of every located venue, kept in sync with
   the map pins in both directions: tapping a pin scrolls the carousel to
   its card (scrollIntoView), and swiping a card into view pans the map to
   it and highlights its pin (IntersectionObserver — see app.js). */

.map-locate-btn {
  position: fixed;
  right: 16px;
  /* fallback; renderMap sets the real offset from the carousel's height */
  bottom: 236px;
  z-index: 1100;
  width: 46px;
  height: 46px;
  border: none;
  border-radius: 50%;
  background: #fff;
  color: #1c1c24;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.22);
  cursor: pointer;
}

.map-locate-btn:active {
  transform: scale(0.94);
}

.map-locate-btn.locating svg {
  animation: locate-pulse 1s ease-in-out infinite;
}

.map-locate-btn.located {
  color: #2f7cf6;
}

@keyframes locate-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

/* "You are here": blue dot with a white ring, plus a soft accuracy halo
   drawn separately as an L.circle. */
.user-loc-dot span {
  display: block;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #2f7cf6;
  border: 3px solid #fff;
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.35);
}

.map-toast {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  /* sits below the top filter pills, clear of the carousel */
  top: 124px;
  z-index: 1300;
  background: var(--pill);
  color: #fdf6ee;
  padding: 10px 18px;
  border-radius: 999px;
  font-size: 0.85rem;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.25);
  max-width: 80vw;
  text-align: center;
}

.map-toast.hidden {
  display: none;
}

.map-card-carousel {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1200;
  /* One card, centred. This was a horizontal scroller back when it held a
     card per pin; with a single card on demand there is nothing to scroll. */
  display: flex;
  justify-content: center;
  padding: 16px 16px 82px; /* bottom clears the fixed bottom-nav pill */
  pointer-events: none;    /* the gap either side stays map, not dead space */
}
.map-card-carousel > * {
  pointer-events: auto;
}
.map-card-carousel::-webkit-scrollbar {
  display: none;
}
.map-detail-card.lifting {
  transition: none;
}
@keyframes map-card-in {
  from { transform: translateY(12px); opacity: 0; }
  to   { transform: translateY(0);    opacity: 1; }
}
.map-card-carousel.hidden {
  display: none;
}

.map-detail-card {
  /* vertical touches feed the swipe-up-to-open gesture; horizontal panning
     stays the browser's native carousel scroll */
  /* vertical touches feed the swipe-up-to-open gesture */
  touch-action: pan-y;
  transition: transform 0.22s ease, opacity 0.22s ease;
  flex: 0 0 auto;
  width: calc(100vw - 64px);
  max-width: 400px;
  animation: map-card-in 0.18s ease-out;
  background: #fff;
  border-radius: 16px;
  padding: 16px;
  display: flex;
  align-items: center;
  gap: 12px;
  box-shadow: 0 12px 28px rgba(0, 0, 0, 0.35);
  cursor: pointer;
}

.map-detail-body {
  flex: 1;
  min-width: 0;
}

.map-detail-name {
  margin: 0 0 4px;
  font-family: "Space Mono", "SF Mono", Menlo, monospace;
  font-size: 0.95rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: #1c1b1a;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.map-detail-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 6px;
}
.map-detail-status {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 0.7rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  padding: 3px 8px;
  border-radius: 999px;
  background: #9a9aa5;
  color: #fff;
}
.map-detail-status.live {
  background: var(--green);
}
.map-detail-status.upcoming {
  background: var(--accent);
  color: #1a1200;
}
.map-detail-time {
  font-size: 0.85rem;
  font-weight: 700;
  color: #1c1b1a;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.map-detail-address {
  font-size: 0.78rem;
  color: #706c66;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-bottom: 12px;
}

.map-detail-actions {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.map-detail-action {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.85rem;
  font-weight: 600;
  color: #1c1b1a;
  text-decoration: none;
}

.map-detail-deal-name {
  /* long deal names give way to the price */
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-weight: 500;
}

.map-detail-deal-price {
  flex-shrink: 0;
  font-weight: 700;
  color: #b4551e;
}

.map-detail-nodeals {
  font-size: 0.8rem;
  font-weight: 500;
  color: var(--text-dim);
}
.map-detail-action-icon {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: #f7f5f1;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.85rem;
  flex-shrink: 0;
}

.map-detail-arrow-btn {
  flex-shrink: 0;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: var(--pill);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.2rem;
  text-decoration: none;
}
.map-detail-arrow-btn:active {
  transform: scale(0.96);
}

.map-pin span {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  border: 2px solid #fff;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
  color: #fff;
  font-size: 12px;
  line-height: 1;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.map-pin.map-pin-active span {
  transform: scale(1.35);
  box-shadow: 0 0 0 5px rgba(26, 26, 26, 0.18), 0 2px 8px rgba(0, 0, 0, 0.35);
}

.map-detail-rating {
  color: #b8860b;
  font-weight: 700;
}

/* ---------- Generic buttons (modal) ---------- */

.btn-primary, .btn-secondary, .btn-danger, .btn-icon {
  font-family: inherit;
  font-size: 0.95rem;
  border: none;
  border-radius: 10px;
  padding: 10px 16px;
  cursor: pointer;
  transition: transform 0.08s ease, opacity 0.15s ease;
}
.btn-primary:active, .btn-secondary:active, .btn-danger:active { transform: scale(0.97); }

.btn-primary {
  background: var(--accent);
  color: #1a1200;
  font-weight: 700;
  border-radius: 999px;
}
.btn-secondary {
  background: transparent;
  color: var(--text);
  border: 1px solid var(--card-border);
}
.btn-danger {
  background: transparent;
  color: var(--red);
  border: 1px solid var(--red);
}
.btn-icon {
  background: transparent;
  color: var(--text-dim);
  font-size: 1.4rem;
  line-height: 1;
  padding: 4px 10px;
}

/* ---------- Modal ---------- */

.modal {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.5);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  z-index: 50;
}
.modal.hidden { display: none; }

.modal-content {
  background: var(--bg);
  border: 1px solid var(--card-border);
  border-radius: 24px 24px 0 0;
  width: 100%;
  max-width: 480px;
  max-height: 90vh;
  overflow-y: auto;
  padding: 20px;
}

@media (min-width: 480px) {
  .modal { align-items: center; }
  .modal-content { border-radius: 24px; }
}

.modal-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
}
.modal-header h2 {
  margin: 0;
  font-size: 1.4rem;
  font-weight: 800;
  letter-spacing: -0.01em;
}

#venueForm label {
  display: block;
  font-size: 0.85rem;
  color: var(--text-dim);
  margin: 14px 0 6px;
}

#venueForm input[type="text"],
#venueForm input[type="time"] {
  width: 100%;
  font-family: inherit;
  font-size: 1rem;
  background: var(--card);
  color: var(--text);
  border: 1px solid var(--card-border);
  border-radius: 10px;
  padding: 10px 12px;
}

.day-picker {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}
.day-btn {
  font-family: inherit;
  background: var(--card);
  color: var(--text-dim);
  border: 1px solid var(--card-border);
  border-radius: 8px;
  padding: 8px 10px;
  font-size: 0.8rem;
  cursor: pointer;
}
.day-btn.selected {
  background: var(--accent);
  border-color: var(--accent);
  color: #1a1200;
  font-weight: 700;
}

.time-row {
  display: flex;
  gap: 12px;
}
.time-row > div { flex: 1; }

.deals-edit-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.deal-edit-row {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--card-border);
}
.deal-edit-row-main {
  display: flex;
  gap: 8px;
}
.deal-edit-row-extra {
  display: flex;
  gap: 8px;
}
.deal-edit-row input,
.deal-edit-row select {
  font-family: inherit;
  background: var(--card);
  color: var(--text);
  border: 1px solid var(--card-border);
  border-radius: 8px;
  padding: 8px 10px;
  font-size: 0.9rem;
}
.deal-edit-row .deal-name { flex: 2; }
.deal-edit-row .deal-price { flex: 1; }
.deal-edit-row .deal-category { flex: 0 0 auto; }
.deal-edit-row .deal-description { flex: 1; }
.deal-edit-row-main button {
  background: transparent;
  border: none;
  color: var(--red);
  font-size: 1.2rem;
  cursor: pointer;
  padding: 0 6px;
}

.modal-actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 22px;
  padding-top: 16px;
  border-top: 1px solid var(--card-border);
}
.modal-actions-right {
  display: flex;
  gap: 10px;
}

.site-footer {
  text-align: center;
  padding: 18px 0 28px;
  font-size: 0.8rem;
}
.site-footer a {
  color: var(--text-dim);
}

/* Leaflet's zoom animation runs a 250ms CSS transition. The animation itself
   is not optional — it is what keeps the existing tiles on screen while their
   replacements load, and zooming with animate:false turned the map white. But
   250ms is long enough that the map visibly trails the trackpad, which is the
   sluggishness that replaced the blanking. 80ms keeps the tiles and cuts the
   lag behind the fingers from 0.49 zoom levels to 0.13 (measured against the
   live site: 313KB of a 317KB at-rest frame stays painted mid-gesture). */
.leaflet-zoom-anim .leaflet-zoom-animated {
  transition: transform 80ms cubic-bezier(0, 0, 0.25, 1);
}
