/* Design refresh (Oct 2026): tokens below are grouped so dark mode only
   ever has to redefine THIS block, never touch a component rule. Two
   overrides follow --cream/--ink/--line/--muted/--surface/--cat-* for a
   system dark preference (@media, guarded so an explicit light choice can
   still win) and for an explicit manual toggle ([data-theme]) — see the
   theme-toggle button in the appbar, wired up in app.js. --terracotta is
   deliberately NOT redefined: it was checked against both the dark page
   background and white button text (contrast scripts/validate_palette.js
   ships, not eyeballed) and clears both as-is, so one accent color works
   for both themes. --cat-* (the five category colors used for pins, card
   swatches, the legend, and the sheet's category pill) ARE redefined —
   see the comment above CATEGORY_COLORS in data.js for how those two sets
   were chosen and validated. */
:root {
  --cream: #F2ECE1;
  --ink: #1B1712;
  --terracotta: #C1502E;
  --line: #E0D6C4;
  --muted: #7A6F5F;
  --surface: #FFFFFF;
  --cat-agency: #8B4B00;
  --cat-shopping: #55458B;
  --cat-culture: #00895D;
  --cat-cafe: #C06C9C;
  --cat-venue: #009DD4;
  --cat-stay: #005FE0;
  --cat-eat: #95004C;
  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --cream: #17140F;
    --ink: #EDE6D9;
    --line: #332C22;
    --muted: #A89A85;
    --surface: #221D16;
    --cat-agency: #A15D00;
    --cat-shopping: #7357C2;
    --cat-culture: #188B68;
    --cat-cafe: #D861A7;
    --cat-venue: #00A0E0;
    --cat-stay: #BB47FD;
    --cat-eat: #B80040;
    color-scheme: dark;
  }
}

:root[data-theme="dark"] {
  --cream: #17140F;
  --ink: #EDE6D9;
  --line: #332C22;
  --muted: #A89A85;
  --surface: #221D16;
  --cat-agency: #A15D00;
  --cat-shopping: #7357C2;
  --cat-culture: #188B68;
  --cat-cafe: #D861A7;
  --cat-venue: #00A0E0;
  --cat-stay: #BB47FD;
  --cat-eat: #B80040;
  color-scheme: dark;
}

/* RTL (Arabic, Oct 2026 14-language pass): most of the layout mirrors for
   free under dir="rtl" — every row here is a flexbox with flex-direction:
   row, which the spec already mirrors automatically (appbar__row, .card,
   .legend-row, .tab, .sheet__actions, .chips, etc. all need nothing extra).
   The only things that don't auto-flip are hardcoded physical values —
   these three `text-align: left` declarations are the only ones in this
   file. (The legend-row arrow glyph itself flips in app.js/renderLegend(),
   since it's a literal character, not something CSS can mirror.) This is
   a good-faith pass, not a native-speaker-reviewed one. */
[dir="rtl"] .lang-option,
[dir="rtl"] .card,
[dir="rtl"] .legend-row {
  text-align: right;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  background: var(--cream);
  color: var(--ink);
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
  overflow: hidden;
}

h1, h2, h3 { font-family: 'Lora', serif; margin: 0; }

.appbar {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 20;
  background: var(--cream);
  border-bottom: 1px solid var(--line);
  padding: 14px 16px 10px;
  padding-top: calc(14px + env(safe-area-inset-top));
}
.appbar__row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.appbar__title { display: flex; align-items: center; gap: 10px; min-width: 0; }
.appbar__mark {
  width: 34px; height: 34px; border-radius: 50%;
  background: var(--terracotta);
  /* Literal white, not var(--cream) — terracotta doesn't change between
     themes, so its label shouldn't either; var(--cream) flips to a near-
     black page-background color in dark mode and would vanish here. */
  color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-family: 'Lora', serif; font-weight: 700; font-size: 16px;
  flex-shrink: 0;
}
.appbar h1 { font-size: 18px; }
.appbar__sub { margin: 1px 0 0; font-size: 11px; color: var(--muted); letter-spacing: .02em; }

/* Groups the language picker + theme toggle on the right so appbar__row's
   space-between still has exactly two items (title, this group) — adding
   the language picker (Oct 2026) alongside the pre-existing lone
   theme-toggle button needed a wrapper rather than a third top-level item. */
.appbar__actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }

.theme-toggle {
  width: 32px; height: 32px; border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.theme-toggle svg { width: 16px; height: 16px; display: block; }

/* Language picker (Oct 2026): a globe button that opens a small dropdown
   of the four supported languages. Positioned the same way as other
   dropdowns on the page (.lang-picker is the positioning context,
   .lang-menu is absolutely placed under the button) rather than a native
   <select>, so it can match the app's own button/card styling. */
.lang-picker { position: relative; flex-shrink: 0; }
.lang-toggle {
  height: 32px;
  padding: 0 10px 0 8px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  display: flex; align-items: center; gap: 4px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.lang-toggle svg { width: 15px; height: 15px; display: block; flex-shrink: 0; }
.lang-toggle span:last-child { font-size: 11px; font-weight: 700; letter-spacing: .02em; }

.lang-menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 30;
  min-width: 168px;
  /* 14 languages don't fit in a short dropdown the way the original 4
     did — cap the height and let it scroll instead of running off the
     bottom of the screen. */
  max-height: min(360px, calc(100vh - 100px));
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 12px;
  box-shadow: 0 4px 14px rgba(0,0,0,.14);
  padding: 4px;
  display: flex; flex-direction: column; gap: 2px;
}
.lang-menu[hidden] { display: none; }
.lang-option {
  border: none; background: none;
  border-radius: 8px;
  padding: 8px 10px;
  font: inherit; font-size: 13px; font-weight: 500;
  color: var(--ink);
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.lang-option:active { background: var(--cream); }
.lang-option--active { color: var(--terracotta); font-weight: 700; }

.view {
  position: absolute;
  top: calc(66px + env(safe-area-inset-top));
  bottom: calc(64px + env(safe-area-inset-bottom));
  left: 0; right: 0;
  display: none;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}
.view--active { display: block; }

/* Map view: toggle + chips sit in normal document flow ABOVE the map
   (not floated on top of it). Leaflet repaints/pans its tile layer
   continuously, and overlaying absolute/fixed controls directly on top
   of that turned out to render unreliably on some browsers — stacking
   them above the map container sidesteps that entirely.
   NOTE: this must be gated on .view--active — an ID selector like
   #view-map beats the .view--active CLASS selector on specificity, so
   an unconditional `#view-map { display: flex }` would keep the map
   view visible (overlapping other tabs) even when .view--active was
   removed from it. Scoping to #view-map.view--active keeps the base
   .view { display: none } rule in control when this tab isn't active. */
#view-map.view--active {
  padding: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
#view-map .city-toggle,
#view-map .search-bar,
#view-map .chips {
  flex-shrink: 0;
}
#view-map .city-toggle { margin: 10px 14px 0; }
#view-map .search-bar { margin: 8px 14px 0; }
#view-map .chips { padding: 8px 14px; }
#map { position: relative; flex: 1; min-height: 0; }

.city-toggle {
  display: flex;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 3px;
  box-shadow: 0 1px 3px rgba(0,0,0,.08);
}
#view-list .city-toggle { margin: 12px 14px 0; }
#view-list .search-bar { margin: 10px 14px 0; }

.search-bar {
  display: flex; align-items: center; gap: 8px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 9px 12px;
  box-shadow: 0 1px 3px rgba(0,0,0,.08);
}
.search-bar__icon { font-size: 14px; flex-shrink: 0; opacity: .55; }
.search-bar__input {
  flex: 1; min-width: 0;
  border: none; outline: none; background: transparent;
  font-family: 'Inter', sans-serif; font-size: 14px; color: var(--ink);
}
.search-bar__input::placeholder { color: var(--muted); }
.search-bar__clear {
  flex-shrink: 0;
  width: 18px; height: 18px; border-radius: 50%;
  border: none; background: var(--line); color: var(--muted);
  font-size: 10px; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.search-bar__clear[hidden] { display: none; }

.search-bar__offline {
  flex-shrink: 0;
  width: 26px; height: 26px; border-radius: 50%;
  border: none; background: var(--line); color: var(--muted);
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  -webkit-tap-highlight-color: transparent;
}
.search-bar__offline svg { width: 14px; height: 14px; display: block; }
.search-bar__offline:disabled { opacity: .5; cursor: default; }
.search-bar__offline.offline-save--busy svg { animation: ktrail-spin 0.9s linear infinite; }
@keyframes ktrail-spin { to { transform: rotate(360deg); } }

.city-btn {
  flex: 1;
  border: none; background: none;
  padding: 7px 0;
  border-radius: 999px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--muted);
}
.city-btn--active { background: var(--terracotta); color: #fff; }

.chips {
  display: flex; gap: 8px;
  overflow-x: auto;
  scrollbar-width: none;
}
.chips::-webkit-scrollbar { display: none; }
#view-list .chips { padding: 12px 14px 0; }

.chip {
  flex-shrink: 0;
  padding: 7px 14px;
  border-radius: 999px;
  background: var(--surface);
  border: 1px solid var(--line);
  font-size: 12.5px;
  font-weight: 500;
  color: var(--ink);
  box-shadow: 0 1px 3px rgba(0,0,0,.08);
  white-space: nowrap;
}
.chip--active { background: var(--ink); color: var(--cream); border-color: var(--ink); }

.list { padding: 12px 14px 20px; display: flex; flex-direction: column; gap: 10px; }

/* Saved tab: cards grouped by city (fixed CITIES order), each group
   sorted by category then by most-recently-saved — see renderSaved() in
   app.js. Same card markup/styling as .list, just wrapped one level
   deeper so each city gets its own heading. */
.saved-groups { padding: 12px 14px 20px; display: flex; flex-direction: column; gap: 22px; }
.saved-section { display: flex; flex-direction: column; gap: 10px; }
.saved-section__header {
  margin: 0;
  display: flex; align-items: baseline; gap: 7px;
  font-family: 'Lora', serif;
  font-size: 15px;
  font-weight: 700;
}
.saved-section__count {
  font-family: 'Inter', sans-serif;
  font-size: 11.5px; font-weight: 600;
  color: var(--muted);
}

.card {
  display: flex; gap: 12px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 12px;
  text-align: left;
  cursor: pointer;
}
.card__swatch {
  width: 44px; height: 44px; border-radius: 10px;
  flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  color: #fff; font-size: 18px;
}
.card__body { flex: 1; min-width: 0; }
.card__name { font-family: 'Lora', serif; font-size: 15px; font-weight: 600; margin: 0 0 2px; }
.card__cat { font-size: 11px; color: var(--terracotta); font-weight: 600; text-transform: uppercase; letter-spacing: .03em; }
.card__blurb { font-size: 12.5px; color: var(--muted); margin: 4px 0 0; line-height: 1.4; }

.empty-state {
  display: none;
  text-align: center;
  color: var(--muted);
  font-size: 13px;
  padding: 60px 30px 0;
}

.about { padding: 20px 20px 20px; }
.about h2 { font-size: 20px; margin-bottom: 14px; }
.about h2:not(:first-child) { margin-top: 6px; }
/* var(--ink), not the old hardcoded #3a342c — that literal brown stayed
   dark in dark mode and went unreadable against the dark page background. */
.about p { font-size: 14px; line-height: 1.6; color: var(--ink); margin: 0 0 14px; }

.legend { display: flex; flex-direction: column; gap: 8px; margin-bottom: 18px; }
.legend-row {
  display: flex; align-items: center; gap: 10px;
  width: 100%;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 8px 12px;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.legend-row:active { background: var(--cream); }
.legend-row__icon {
  width: 30px; height: 30px; border-radius: 50%;
  flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 14px;
  color: #fff;
}
.legend-row__label { flex: 1; font-size: 13.5px; font-weight: 500; }
.legend-row__arrow { font-size: 18px; color: var(--muted); flex-shrink: 0; }

.about__badge {
  display: inline-block;
  font-size: 11px; font-weight: 600; letter-spacing: .03em; text-transform: uppercase;
  color: var(--terracotta);
  border: 1px solid var(--terracotta);
  border-radius: 999px;
  padding: 6px 12px;
}

.tabbar {
  position: fixed; left: 0; right: 0; bottom: 0;
  z-index: 20;
  display: flex;
  background: var(--surface);
  border-top: 1px solid var(--line);
  padding-bottom: env(safe-area-inset-bottom);
}
.tab {
  flex: 1;
  border: none; background: none;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 9px 0 8px;
  font-size: 10.5px; font-weight: 500;
  color: var(--muted);
}
.tab__icon { font-size: 18px; line-height: 1; }
.tab--active { color: var(--terracotta); }
.tab__count {
  display: inline-block;
  margin-left: 3px;
  font-size: 9.5px; font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.tab__count[hidden] { display: none; }

.sheet-backdrop {
  position: fixed; inset: 0;
  background: rgba(27,23,18,.35);
  z-index: 1002;
  opacity: 0; pointer-events: none;
  transition: opacity .2s ease;
}
.sheet-backdrop--open { opacity: 1; pointer-events: auto; }

.sheet {
  position: fixed; left: 0; right: 0; bottom: 0;
  z-index: 1003;
  background: var(--cream);
  border-radius: 20px 20px 0 0;
  padding: 10px 20px calc(24px + env(safe-area-inset-bottom));
  transform: translateY(100%);
  transition: transform .25s cubic-bezier(.2,.8,.3,1);
  box-shadow: 0 -8px 30px rgba(0,0,0,.15);
}
.sheet--open { transform: translateY(0); }
.sheet__handle {
  width: 36px; height: 4px; border-radius: 2px;
  background: var(--line);
  margin: 0 auto 14px;
}
.sheet__category {
  display: inline-block;
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .03em;
  color: #fff;
  border-radius: 999px;
  padding: 4px 10px;
  margin-bottom: 8px;
}
.sheet h3 { font-size: 19px; margin-bottom: 4px; }
.sheet__address { font-size: 12px; color: var(--muted); margin: 0 0 10px; }
.sheet__blurb { font-size: 13.5px; line-height: 1.55; margin: 0 0 18px; }
.sheet__actions { display: flex; gap: 8px; }

.btn {
  flex: 1;
  min-width: 0;
  border: none; border-radius: 12px;
  padding: 12px 8px;
  font-size: 13.5px; font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  /* .btn is also used on an <a> (#sheet-link, added Oct 2026) — these three
     make the anchor variant render identically to the <button> ones. */
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  text-decoration: none;
}
/* Added Oct 2026: .btn sets display, which overrides the hidden attribute on
   #sheet-link, so spots without a linkUrl showed an empty button. */
.btn[hidden] { display: none; }
.btn--primary { background: var(--terracotta); color: #fff; }
.btn--ghost { background: var(--surface); border: 1px solid var(--line); color: var(--ink); }
.btn--ghost.saved { background: var(--ink); color: var(--cream); border-color: var(--ink); }

.toast {
  position: fixed;
  left: 50%;
  bottom: calc(76px + env(safe-area-inset-bottom));
  transform: translateX(-50%) translateY(10px);
  background: var(--ink); color: var(--cream);
  font-size: 12.5px; font-weight: 500;
  padding: 9px 16px;
  border-radius: 999px;
  box-shadow: 0 4px 14px rgba(0,0,0,.25);
  z-index: 1004;
  opacity: 0; pointer-events: none;
  transition: opacity .2s ease, transform .2s ease;
  white-space: nowrap;
}
.toast--show { opacity: 1; transform: translateX(-50%) translateY(0); }

/* Bug fix (Oct 2026) — the install banner was invisible on the Map tab
   until you switched to another tab, reported live on a real iPhone.
   Root cause: Leaflet's own CSS gives its internal panes z-index values
   up to 1000 (tile pane 200, tooltip pane 650, .leaflet-top/-bottom
   control containers 1000) — see leaflet.min.css. Neither #map nor any
   ancestor between it and <body> sets its own z-index, so none of them
   establish a stacking context; Leaflet's panes end up competing
   directly against OUR page-level z-index values in the SAME (root)
   stacking context. The appbar/tabbar never collided with this because
   the view's top/bottom offsets keep #map's box from ever reaching into
   their strip of the screen — but a fixed overlay like this banner (or
   the sheet/backdrop/toast below) floats ON TOP of the view content, so
   it DOES spatially overlap the map, and at z-index 25 it was losing to
   the map tiles at z-index 200. Fix: push every one of this app's own
   floating-over-the-map overlays (install banner, sheet, its backdrop,
   toast) comfortably above Leaflet's highest value (1000) instead of
   the low two-digit range that was fine everywhere else in the app.
   Kept in the same relative order as before (banner < backdrop < sheet
   < toast) so nothing about how they stack AMONG THEMSELVES changes. */
/* PWA install banner — see the install-prompt block in app.js for when
   this shows (beforeinstallprompt on Chrome/Edge/Android, static iOS
   instructions elsewhere, never once installed or dismissed). Placed
   well above the tabbar AND above where .toast appears (same bottom
   anchor as the sheet actions) so a toast firing while this is visible
   (e.g. tapping Share right after install is offered) doesn't overlap it. */
.install-banner {
  position: fixed;
  left: 14px; right: 14px;
  bottom: calc(130px + env(safe-area-inset-bottom));
  z-index: 1001;
  display: flex; align-items: center; gap: 10px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 10px 10px 10px 12px;
  box-shadow: 0 4px 16px rgba(0,0,0,.18);
}
.install-banner[hidden] { display: none; }
.install-banner__icon {
  flex-shrink: 0;
  width: 30px; height: 30px; border-radius: 9px;
  background: var(--terracotta);
  color: #fff;
  display: flex; align-items: center; justify-content: center;
}
.install-banner__icon svg { width: 16px; height: 16px; display: block; }
.install-banner__text { flex: 1; min-width: 0; margin: 0; font-size: 12.5px; line-height: 1.35; color: var(--ink); }
.install-banner__action {
  flex-shrink: 0;
  border: none; border-radius: 999px;
  background: var(--terracotta); color: #fff;
  font-size: 12px; font-weight: 600;
  padding: 8px 14px;
  cursor: pointer;
  white-space: nowrap;
}
.install-banner__action[hidden] { display: none; }
.install-banner__dismiss {
  flex-shrink: 0;
  width: 22px; height: 22px; border-radius: 50%;
  border: none; background: var(--line); color: var(--muted);
  font-size: 10px; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  -webkit-tap-highlight-color: transparent;
}

.leaflet-popup, .leaflet-control-attribution { font-family: 'Inter', sans-serif; font-size: 11px; }

/* Permanent name label shown next to each map pin (see renderMarkers in
   app.js) — overrides Leaflet's default tooltip chrome (white box + arrow)
   with a small pill so it reads as a map label, not a hover popup. */
/* Deliberately literal colors, not var(--line)/var(--ink) — this label
   sits on top of the Leaflet map tiles, which are always light regardless
   of app theme, so it must stay a light label with dark text in both
   modes. Using the flipping tokens here would turn it into unreadable
   light-on-near-white text the moment dark mode is on. */
.leaflet-tooltip.map-label {
  background: rgba(255,255,255,.95);
  border: 1px solid #E0D6C4;
  border-radius: 6px;
  box-shadow: 0 1px 3px rgba(0,0,0,.15);
  padding: 2px 7px;
  font-family: 'Inter', sans-serif;
  font-size: 11px;
  font-weight: 600;
  color: #1B1712;
  white-space: nowrap;
  pointer-events: none;
}
.leaflet-tooltip.map-label::before { display: none; }

.pin-marker {
  width: 28px; height: 28px;
  border-radius: 50% 50% 50% 0;
  transform: rotate(-45deg);
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 2px 6px rgba(0,0,0,.3);
  border: 2px solid #fff;
}
.pin-marker span { transform: rotate(45deg); font-size: 13px; color: #fff; }

/* Category icons (pin glyph, list-card swatch, About-page legend) are
   inline SVG now, not emoji — see CATEGORY_ICONS in data.js. No
   width/height on the <svg> itself; sizing it in em keeps it tied to
   each container's own font-size, same as the emoji glyphs it replaced. */
.pin-marker span svg,
.card__swatch svg,
.legend-row__icon svg {
  width: 1em;
  height: 1em;
  display: block;
}
