/* Mirrors packages/shared/src/tokens.ts and apps/merchant/style.css — no
 * bundler here either, so the tokens are duplicated by hand, same rule. */

:root {
  --sun: #ffc93c;
  --tomato: #f2452f;
  --grape: #5b2ecc;
  --mint: #12c48b;
  --ink: #1b1414;
  --surface: #fffbf0;
  --mute: #6e5230;

  /* Text color for anything sitting on a solid --grape background (active
   * chips/pills, primary buttons) — kept as its own token rather than
   * reusing --surface, since a future --surface change (e.g. per-section
   * theming) shouldn't silently affect button-on-grape contrast too. */
  --on-grape: #fffbf0;

  --outline: 2px;
  --offset: 4px;
  --radius-card: 12px;
  --radius-chip: 999px;

  /* Single source of truth for the side inset — every section (header,
   * hero, filter chips, slider headers/tracks, the bottom CTA) uses this,
   * not its own clamp(), so their content lines up pixel-for-pixel. */
  --gutter: clamp(20px, 4vw, 64px);

  --font-display: 'Gabarito', system-ui, sans-serif;
  --font-body: 'Onest', system-ui, sans-serif;
}

/* Deliberately one committed light look, not a dark variant — several
 * ink-on-color combinations (brand purple, hero photo overlays) are tuned
 * for this exact palette and don't have a dark-mode-safe counterpart. */

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  min-height: 100%;
}

body {
  background: var(--sun);
  color: var(--ink);
  font-family: var(--font-body);
  -webkit-tap-highlight-color: transparent;
}

h1,
h2,
h3 {
  font-family: var(--font-display);
  font-weight: 900;
  letter-spacing: -0.03em;
  margin: 0;
}

a {
  color: inherit;
}

button {
  font-family: inherit;
}

/* ---------- sticker mechanics: ink outline + solid offset layer ---------- */

.sticker {
  position: relative;
  border: var(--outline) solid var(--ink);
  border-radius: var(--radius-card);
  background: var(--surface);
}

.sticker::after {
  content: '';
  position: absolute;
  inset: var(--offset) calc(var(--offset) * -1) calc(var(--offset) * -1) var(--offset);
  background: var(--ink);
  border-radius: var(--radius-card);
  z-index: -1;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: var(--outline) solid var(--ink);
  border-radius: var(--radius-chip);
  padding: 8px 14px;
  font-weight: 700;
  font-size: 13.5px;
  background: var(--surface);
  cursor: pointer;
  white-space: nowrap;
  /* .chip is also used on <a> elements (e.g. the "Ver en el mapa" link) —
     without this they'd show the browser's default link underline, which
     no button-styled chip should ever have. */
  text-decoration: none;
}

.chip.active {
  background: var(--grape);
  color: var(--on-grape);
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: var(--outline) solid var(--ink);
  border-radius: var(--radius-card);
  padding: 11px 20px;
  font-weight: 800;
  font-size: 14.5px;
  cursor: pointer;
  box-shadow: var(--offset) var(--offset) 0 var(--ink);
  transition: transform 0.08s ease;
}

.btn:active {
  transform: translate(2px, 2px);
  box-shadow: 2px 2px 0 var(--ink);
}

.btn-primary {
  background: var(--grape);
  color: var(--on-grape);
}

.btn-ghost {
  background: var(--surface);
  color: var(--ink);
}

/* ---------- layout ---------- */

.page {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

header.site {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 20px var(--gutter);
  flex-wrap: wrap;
}

.logo {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 24px;
  white-space: nowrap;
}

.logo strong {
  font-family: var(--font-display);
  font-weight: 900;
  letter-spacing: -0.05em;
}

.logo .tomato {
  color: var(--tomato);
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* Desktop: language + login sit directly in the header, as they always
 * did. Below the breakpoint they don't fit next to the logo (see the
 * .account-menu rules), so they move into the icon's dropdown instead —
 * both containers get rendered, only one is ever shown. */
.header-actions-desktop {
  display: flex;
  align-items: center;
  gap: 10px;
}

.account-menu {
  display: none;
  position: relative;
}

@media (max-width: 640px) {
  .header-actions-desktop {
    display: none;
  }

  .account-menu {
    display: block;
  }
}

.account-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  padding: 0;
  border: var(--outline) solid var(--ink);
  border-radius: 50%;
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
}

.account-dropdown[hidden] {
  display: none;
}

.account-dropdown {
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  /* Same fix as .modal-overlay (mapa.html's Leaflet panes/controls go up to
     ~1000) — on the map page this dropdown is the only way to reach "Volver
     al listado" on mobile, and at the old z-index: 10 it rendered behind
     the map instead of over it. */
  z-index: 2000;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 16px;
  min-width: 220px;
  padding: 20px;
  background: var(--surface);
  border: var(--outline) solid var(--ink);
  border-radius: var(--radius-card);
  box-shadow: var(--offset) var(--offset) 0 var(--ink);
}

.account-dropdown .lang-switch {
  justify-content: flex-end;
}

.account-dropdown .user-chip {
  justify-content: space-between;
}

.account-dropdown .btn-ghost,
.account-dropdown .btn-primary {
  width: 100%;
  text-align: center;
}

/* ---------- hero: full-bleed photo carousel, same slide-swap mechanism as
   .showcase (setupCarousel), persistent tagline overlaid on top instead of
   a per-slide caption. Sits on var(--sun) between the header and .content,
   so it needs its own top/bottom borders to read as a distinct band. ---- */

.hero-carousel {
  position: relative;
  height: min(62vh, 560px);
  min-height: 380px;
  overflow: hidden;
  border-top: var(--outline) solid var(--ink);
  border-bottom: var(--outline) solid var(--ink);
}

.hero-track {
  position: absolute;
  inset: 0;
}

.hero-slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 1.4s ease;
  display: flex;
  align-items: center;
  justify-content: center;
}

.hero-slide.active {
  opacity: 1;
}

.hero-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(27, 20, 20, 0.32) 0%, rgba(27, 20, 20, 0.1) 38%, rgba(27, 20, 20, 0.82) 100%);
}

.hero-content {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 0 var(--gutter) 48px;
}

.hero-content h1 {
  color: var(--surface);
  font-size: clamp(32px, 5vw, 56px);
  line-height: 1.05;
  max-width: 760px;
}

.hero-content p {
  color: rgba(255, 251, 240, 0.9);
  font-size: 17px;
  line-height: 1.5;
  max-width: 520px;
  margin: 12px 0 0;
}

.hero-stats {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 20px;
}

.hero-stat {
  background: rgba(255, 251, 240, 0.14);
  border: 1.5px solid rgba(255, 251, 240, 0.55);
  color: var(--surface);
  border-radius: var(--radius-chip);
  padding: 6px 14px;
  font-size: 12.5px;
  font-weight: 700;
  white-space: nowrap;
}

.hero-cta {
  margin-top: 22px;
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

.hero-dots {
  position: absolute;
  bottom: 20px;
  right: var(--gutter);
  z-index: 3;
  display: flex;
  gap: 6px;
}

.hero-dots span {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: rgba(255, 251, 240, 0.5);
  border: 1.5px solid var(--ink);
  cursor: pointer;
}

.hero-dots span.active {
  background: var(--surface);
}

/* Venue detail (local.html) photo gallery — same cross-fade + dot-indicator
 * mechanics as .hero-slide/.hero-dots above (both driven by SR.setupCarousel),
 * just sized to fill the venue's photo box instead of a full-bleed hero. */
.venue-gallery-track {
  position: absolute;
  inset: 0;
}

.venue-gallery-slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 0.9s ease;
}

.venue-gallery-slide.active {
  opacity: 1;
}

.venue-gallery-slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.venue-gallery-dots {
  position: absolute;
  bottom: 12px;
  right: 12px;
  z-index: 3;
  display: flex;
  gap: 6px;
}

.venue-gallery-dots span {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: rgba(255, 251, 240, 0.5);
  border: 1.5px solid var(--ink);
  cursor: pointer;
}

.venue-gallery-dots span.active {
  background: var(--surface);
}

/* Venue detail — desktop "tetris" grid (Airbnb-style: one big photo + a
 * stacked column of the next few), used instead of the slider above 900px
 * per the client feedback that a slider "doesn't look right" at that width.
 * Below 900px the slider stays — a grid this dense doesn't fit a phone
 * screen legibly. Clicking either one opens the full photo set in the
 * lightbox below. */
.venue-gallery-grid {
  /* #body has no max-width, so on a wide desktop viewport this box's width
     is whatever's left after the gutters — often 1400px+. A vw-based fixed
     height (the old min(46vw, 380px), same value the single-photo hero
     used) stayed capped at 380px regardless, producing a ~4:1 banister
     that cropped every photo down to a thin center strip. Sizing off the
     box's own (already-known) width instead keeps proportions sane
     whatever that width turns out to be. */
  width: 100%;
  aspect-ratio: 2.2 / 1;
  max-height: 460px;
  display: grid;
  grid-template-columns: 2fr 1fr;
  /* Explicit (not implicit/auto) row — an auto row sizes to content, which
     is circular here (.venue-gallery-side's own height:100% images depend
     on a row height that would depend on those same images), so it was
     growing to each photo's natural aspect ratio (~792px) instead of
     filling this box. An explicit `1fr` row distributes the container's
     already-definite height instead, breaking the cycle. */
  grid-template-rows: 1fr;
  gap: 6px;
}

.venue-gallery-main,
.venue-gallery-thumb {
  /* Grid items default to an automatic min-height equal to their content's
     min-content size (same rule as flex items) — without this, each
     thumbnail's <img> refused to shrink below its own natural aspect-ratio
     height, blowing the whole grid way past the intended box height. */
  min-height: 0;
  cursor: pointer;
  overflow: hidden;
  position: relative;
}

.venue-gallery-main img,
.venue-gallery-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.venue-gallery-side {
  display: grid;
  min-height: 0;
  /* Set inline per-render (style="--cols: C; --rows: R"): a plain 1-column
     stack for 1-3 thumbnails, but 4 switches to a 2x2 sub-grid instead of
     4 stacked bands — 4 thin horizontal strips in a column this narrow
     came out so flattened only the center of each photo was visible. 2x2
     keeps each cell closer to square. */
  grid-template-columns: repeat(var(--cols), 1fr);
  grid-template-rows: repeat(var(--rows), 1fr);
  gap: 6px;
}

.venue-gallery-more-overlay {
  position: absolute;
  inset: 0;
  background: rgba(27, 20, 20, 0.55);
  color: var(--surface);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 22px;
}

/* Photo lightbox — opened from either the gallery grid or the slider.
 * Reuses .modal-overlay's fixed/centered/click-outside-closes plumbing,
 * darkened further (.lightbox-overlay) since it's showing a photo, not a
 * form. A persistent <img id="lightboxImage"> has its src swapped on
 * navigate instead of rebuilding markup — simpler and sidesteps needing to
 * escape a URL that never becomes a string in the DOM. */
.lightbox-overlay {
  background: rgba(27, 20, 20, 0.92);
}

.lightbox-content {
  position: relative;
  width: 100%;
  max-width: 1100px;
  height: min(85vh, 800px);
  display: flex;
  align-items: center;
  justify-content: center;
}

.lightbox-content img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border-radius: var(--radius-card);
}

.lightbox-close {
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 2;
  background: rgba(27, 20, 20, 0.5);
  border: none;
  color: var(--surface);
  width: 34px;
  height: 34px;
  border-radius: 50%;
  font-size: 16px;
  cursor: pointer;
}

.lightbox-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  background: rgba(27, 20, 20, 0.5);
  border: 1.5px solid rgba(255, 251, 240, 0.6);
  color: var(--surface);
  width: 40px;
  height: 40px;
  border-radius: 50%;
  font-size: 20px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.lightbox-nav[hidden] {
  display: none;
}

.lightbox-prev {
  left: 12px;
}

.lightbox-next {
  right: 12px;
}

.lightbox-counter {
  position: absolute;
  bottom: 12px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  color: var(--surface);
  background: rgba(27, 20, 20, 0.5);
  padding: 4px 12px;
  border-radius: 999px;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 12.5px;
}

.content {
  background: var(--surface);
  border-top: var(--outline) solid var(--ink);
  flex: 1;
  padding: 32px 0 64px;
  display: flex;
  flex-direction: column;
  gap: 40px;
}

.slider-section[hidden] {
  display: none;
}

.slider-section {
  display: flex;
  flex-direction: column;
  gap: 14px;
  position: relative;
}

/* Same width as the section's own side gutter (matches .steps-grid's
   padding) — doubles as both "the track lines up with the rest of the
   page" and a fade hinting there's more to scroll, instead of the last
   card just butting up against the viewport edge with no cue. */
.slider-section::after {
  content: '';
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: var(--gutter);
  background: linear-gradient(to right, transparent, var(--surface));
  pointer-events: none;
}

.how-it-works {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.steps-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 18px;
  padding: 0 var(--gutter);
}

.step-card {
  position: relative;
  padding: 24px 20px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.step-num {
  position: absolute;
  top: -14px;
  left: -14px;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--tomato);
  border: var(--outline) solid var(--ink);
  box-shadow: 3px 3px 0 var(--ink);
  color: var(--surface);
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
  transform: rotate(-8deg);
}

.step-icon {
  font-size: 34px;
  line-height: 1;
}

.step-card h3 {
  font-size: 18px;
  margin-top: 4px;
}

.step-card p {
  font-size: 14.5px;
  color: var(--mute);
  line-height: 1.5;
  margin: 0;
}

.slider-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding: 0 var(--gutter);
}

.slider-header .mute {
  font-size: 13px;
  color: var(--mute);
  font-weight: 700;
}

.slider-track {
  display: flex;
  gap: 18px;
  overflow-x: auto;
  scroll-snap-type: x proximity;
  /* scroll-snap-align:start on the cards makes the browser snap the
   * *first card* flush to the scrollport edge at rest, which skips right
   * past this padding — scroll-padding is what tells the snap algorithm
   * to treat the scrollport as inset by the gutter instead. Both are
   * needed together; padding alone (or a flex spacer instead of it)
   * still gets snapped past. */
  scroll-padding-inline: var(--gutter);
  padding: 4px var(--gutter) 12px;
  scrollbar-width: thin;
}

/* Signed-in home: the full catalogue as one wide row per venue (not a
   grid of cards) — see .venue-row below. Filters sit in a left sidebar on
   desktop (a horizontal bar above the list left too much of the wide
   viewport as blank space); below the breakpoint there's no room for a
   sidebar, so they go back to a wrapping horizontal bar on top. */
/* Desktop: title left, "Cerca de mi" + "Ver en el mapa" right, same one
   row as before. Below the breakpoint there's no room for that, so the
   title moves to its own row and the buttons wrap below it — #filtersToggle
   (still living in .venue-filters below on desktop) is relocated in here
   by JS (see index.html) only on that same narrow layout, so all three
   listing controls sit together instead of the toggle being stranded alone
   at the top of a collapsed sidebar. */
@media (max-width: 900px) {
  .venue-listing-header {
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
  }
}

.venue-listing-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.venue-layout {
  display: flex;
  align-items: flex-start;
  gap: 28px;
  padding: 0 var(--gutter);
}

.venue-filters {
  flex: 0 0 200px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  position: sticky;
  top: 20px;
}

.venue-filters .chip {
  width: 100%;
  justify-content: flex-start;
  text-align: left;
}

.venue-filters-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  background: none;
  border: none;
  padding: 0 0 2px;
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 16px;
  color: var(--ink);
  cursor: pointer;
}

/* Below the breakpoint, index.html's JS relocates #filtersToggle out of
 * the sidebar into .venue-listing-actions, next to "Cerca de mi" — it
 * needs to look like the chips around it there instead of the plain
 * sidebar-heading style above. mapa.html's toggle never moves, but its
 * sidebar is a horizontal wrapping bar at this width too (see its own
 * .venue-filters override), so the same chip look reads fine there. */
@media (max-width: 900px) {
  .venue-filters-toggle {
    width: auto;
    font-family: var(--font-body);
    font-weight: 700;
    font-size: 13.5px;
    color: var(--ink);
    background: var(--surface);
    border: var(--outline) solid var(--ink);
    border-radius: var(--radius-chip);
    padding: 8px 14px;
  }
}

.venue-filters-toggle-icon {
  transition: transform 0.15s ease;
}

.venue-filters-toggle.is-collapsed .venue-filters-toggle-icon {
  transform: rotate(-90deg);
}

.venue-filters-body {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.venue-filters-body[hidden] {
  display: none;
}

.venue-filter-group {
  border: var(--outline) solid var(--ink);
  border-radius: var(--radius-card);
  padding: 12px 14px;
  background: var(--surface);
}

.venue-filter-group-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  background-color: transparent;
  border: none;
  border-radius: 0;
  box-shadow: none;
  padding: 0;
  font-family: inherit;
  font-weight: 800;
  font-size: 13px;
  color: var(--ink);
  margin-bottom: 8px;
  cursor: pointer;
}

.venue-filter-group-title-icon {
  transition: transform 0.15s ease;
}

.venue-filter-group-title.is-collapsed .venue-filter-group-title-icon {
  transform: rotate(-90deg);
}

.venue-filter-group-title.is-collapsed {
  margin-bottom: 0;
}

.venue-filter-checkboxes {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: 260px;
  overflow-y: auto;
}

.venue-filter-checkboxes[hidden] {
  display: none;
}

.venue-filter-checkbox {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
}

.venue-filter-checkbox input {
  accent-color: var(--grape);
  width: 15px;
  height: 15px;
  cursor: pointer;
}

/* "Abierto ahora" — a single checkbox, not a list, but still boxed like a
   .venue-filter-group so it carries the same visual weight instead of
   looking like a plain, easy-to-miss line of text next to the others. */
.venue-filter-standalone {
  border: var(--outline) solid var(--ink);
  border-radius: var(--radius-card);
  padding: 10px 14px;
  background: var(--surface);
}

.venue-filter-extra {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 8px;
}

.venue-filter-extra[hidden] {
  display: none;
}

.venue-filter-more {
  display: block;
  margin-top: 8px;
  background: none;
  border: none;
  padding: 0;
  font-family: var(--font-body);
  font-weight: 800;
  font-size: 12.5px;
  color: var(--grape);
  text-decoration: underline;
  cursor: pointer;
}

@media (max-width: 900px) {
  .venue-filter-group {
    flex: 0 0 100%;
  }

  .venue-filter-checkboxes,
  .venue-filter-extra {
    flex-direction: row;
    flex-wrap: wrap;
    max-height: none;
  }

  .venue-filter-checkbox {
    background: var(--surface);
    border: var(--outline) solid var(--ink);
    border-radius: var(--radius-chip);
    padding: 6px 12px;
  }
}

.venue-list {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

@media (max-width: 900px) {
  .venue-layout {
    flex-direction: column;
    gap: 14px;
  }

  .venue-filters {
    position: static;
    width: 100%;
    /* The base rule's flex: 0 0 200px sizes the *width* of a row-direction
       sidebar — .venue-layout is column here instead, so that same
       flex-basis was forcing a 200px *height* regardless of content,
       leaving a blank gap under the (now default-collapsed) filters. */
    flex: 0 1 auto;
  }

  /* .venue-filters itself stays a column (index.html's JS relocates the
     toggle button out into .venue-listing-actions at this width, mapa.html's
     never moves) — it's the body's own children (the filter groups + the
     "abierto ahora" chip) that go row/wrap here. */
  .venue-filters-body {
    flex-direction: row;
    flex-wrap: wrap;
  }

  .venue-filters-body .chip {
    width: auto;
  }
}

.venue-row {
  display: flex;
  overflow: hidden;
  text-decoration: none;
  color: inherit;
}

.venue-row-photo {
  flex: 0 0 200px;
  position: relative;
  overflow: hidden;
}

.venue-row-photo img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.venue-row-photo .initial {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: 56px;
  color: var(--ink);
  opacity: 0.15;
}

.venue-row-body {
  flex: 1;
  min-width: 0;
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  justify-content: center;
}

.venue-row-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}

.venue-row-top h3 {
  font-size: 19px;
}

.venue-new-badge {
  display: inline-block;
  margin-left: 8px;
  vertical-align: middle;
  font-family: var(--font-body);
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.04em;
  padding: 3px 8px;
  background: var(--tomato);
  color: var(--surface);
  border-color: var(--ink);
}

.venue-row-badges {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  flex: none;
}

.venue-row-chips {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

@media (max-width: 640px) {
  .venue-row-photo {
    flex-basis: 110px;
  }
  .venue-row-top h3 {
    font-size: 16px;
  }
}

.venue-card {
  flex: 0 0 260px;
  scroll-snap-align: start;
  overflow: hidden;
  cursor: pointer;
  text-decoration: none;
  color: inherit;
  display: block;
}

.venue-photo {
  height: 150px;
  position: relative;
  display: flex;
  align-items: flex-start;
  justify-content: flex-end;
  padding: 8px;
  overflow: hidden;
}

.venue-photo img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.venue-photo .initial {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: 72px;
  color: var(--ink);
  opacity: 0.15;
}

.venue-badge {
  position: relative;
  transform: rotate(-6deg);
  background: var(--surface);
  border: var(--outline) solid var(--ink);
  border-radius: 10px;
  box-shadow: 3px 3px 0 var(--ink);
  padding: 5px 9px;
  text-align: center;
  max-width: 130px;
}

.venue-badge .punch {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 17px;
  line-height: 1;
  color: var(--ink);
}

/* "CAFÈ" above "GRATIS", "menú" above a bare price — without this a punch
 * like "GRATIS" or "15,00 €" doesn't say what it's for (see SR.badgeLabel). */
.venue-badge-item {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 9px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink);
  margin-bottom: 2px;
}

/* Generic "this offer has restrictions, check the ficha" flag — one mark
 * for day/time/minimum-spend alike, since a compact badge has no room to
 * spell out which (see SR.hasConditions/conditionsText). */
.venue-badge-star {
  color: var(--tomato);
}

/* venueCardHtml only shows the single featured benefit — this is its one
 * way to signal there's more without listing them all (venueRowHtml lists
 * every benefit instead, so it never needs this). */
.venue-badge-extra {
  position: absolute;
  bottom: -6px;
  right: -6px;
  background: var(--ink);
  color: var(--surface);
  border-radius: 999px;
  width: 20px;
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-body);
  font-size: 10px;
  font-weight: 800;
  border: 1.5px solid var(--surface);
}

.venue-card-cta,
.venue-row-cta {
  margin-top: 8px;
  font-size: 12.5px;
  font-weight: 800;
  color: var(--grape);
}

.venue-badge.locked .punch {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.venue-body {
  padding: 12px 14px 14px;
}

.venue-body h3 {
  font-size: 19px;
}

.venue-body .meta,
.venue-row-body .meta {
  font-size: 13.5px;
  color: var(--mute);
}

.venue-row-address {
  font-size: 12.5px;
  opacity: 0.8;
}

.meta-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin-top: 3px;
}

.venue-rating {
  flex: none;
  display: flex;
  align-items: baseline;
  gap: 4px;
  font-weight: 800;
  font-size: 14.5px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Google Places' terms require this attribution wherever a rating sourced
 * from them is shown (see migration 0006_google_places.sql) — kept small
 * and muted rather than dropped, since the review count next to it (not
 * required by Google) was the actually-confusing part. */
.google-attr {
  font-weight: 600;
  font-size: 10px;
  color: var(--mute);
}

.venue-open {
  position: absolute;
  left: 10px;
  bottom: 10px;
  background: var(--surface);
  color: var(--ink);
  border: var(--outline) solid var(--ink);
  border-radius: var(--radius-chip);
  padding: 3px 10px;
  font-weight: 700;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.venue-open.is-open {
  background: var(--mint);
}

.venue-caveat {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--mute);
  margin-top: 6px;
}

.empty-note {
  padding: 0 var(--gutter);
  color: var(--mute);
  font-size: 14px;
}

/* ---------- download showcase: a slide-swapping "hero" strip, since no
   venue has a real photo yet (fb-2 is a business task) — see app.js
   showcaseSlideHtml for why it uses the same placeholder tone+initial as
   the venue cards, ready to swap to real photos the day they exist. ---- */

.showcase {
  position: relative;
  margin-top: 8px;
  height: 380px;
  border-top: var(--outline) solid var(--ink);
  border-bottom: var(--outline) solid var(--ink);
  overflow: hidden;
}

.showcase-track {
  position: absolute;
  inset: 0;
}

.showcase-slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 1.1s ease;
  display: flex;
  align-items: center;
  justify-content: center;
}

.showcase-slide.active {
  opacity: 1;
}

.showcase-initial {
  font-family: var(--font-display);
  font-size: 160px;
  color: var(--ink);
  opacity: 0.15;
}

.showcase-caption {
  position: absolute;
  top: 16px;
  left: 16px;
  background: var(--surface);
  border: var(--outline) solid var(--ink);
  border-radius: var(--radius-chip);
  padding: 6px 14px;
  font-size: 12.5px;
  font-weight: 700;
}

.showcase-dots {
  position: absolute;
  bottom: 18px;
  right: var(--gutter);
  display: flex;
  gap: 6px;
  z-index: 2;
}

.showcase-dots span {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: rgba(255, 251, 240, 0.5);
  border: 1.5px solid var(--ink);
  cursor: pointer;
}

.showcase-dots span.active {
  background: var(--surface);
}

.showcase-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 6px;
  padding: 28px var(--gutter);
  background: linear-gradient(0deg, rgba(27, 20, 20, 0.82) 0%, rgba(27, 20, 20, 0.35) 55%, rgba(27, 20, 20, 0) 100%);
}

.showcase-overlay h2 {
  color: var(--surface);
  font-size: 26px;
  max-width: 480px;
}

.showcase-overlay p {
  color: rgba(255, 251, 240, 0.8);
  margin: 0;
  font-size: 14px;
  max-width: 440px;
}

.showcase-overlay .store-badges {
  margin-top: 8px;
}

.store-badges {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

.store-badge {
  border: var(--outline) solid rgba(255, 251, 240, 0.4);
  border-radius: 10px;
  padding: 10px 16px;
  font-size: 12.5px;
  font-weight: 700;
  color: rgba(255, 251, 240, 0.6);
}

.store-badge .soon {
  display: block;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 800;
  color: var(--mint);
  margin-top: 2px;
}

/* ---------- venue sign-up: businesses asking to join, not a guest flow —
   deliberately plain (no carousel, no stickers-on-stickers) so it reads as
   the "serious" moment on an otherwise playful page. ---------- */

.venue-signup {
  padding: 8px var(--gutter) 0;
}

.venue-signup-inner {
  padding: 32px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 32px;
}

.venue-signup-copy h2 {
  font-size: 26px;
  max-width: 380px;
}

.venue-signup-copy p {
  font-size: 14.5px;
  color: var(--mute);
  line-height: 1.55;
  margin-top: 10px;
  max-width: 380px;
}

.venue-signup-form {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.venue-signup-form input,
.venue-signup-form textarea {
  border: var(--outline) solid var(--ink);
  border-radius: var(--radius-card);
  padding: 11px 14px;
  font-family: var(--font-body);
  font-size: 15px;
  background: var(--surface);
  color: var(--ink);
  resize: vertical;
}

.venue-signup-form button {
  align-self: flex-start;
  margin-top: 4px;
}

.signup-success {
  color: var(--mint);
  font-weight: 700;
  font-size: 13.5px;
  margin: 0;
}

@media (max-width: 800px) {
  .venue-signup-inner {
    grid-template-columns: 1fr;
  }
}

footer.site {
  padding: 24px var(--gutter) 40px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  color: var(--mute);
  font-size: 13.5px;
}

.footer-links {
  display: flex;
  gap: 18px;
  flex-wrap: wrap;
}

.footer-links a {
  color: var(--mute);
  font-weight: 700;
  text-decoration: none;
}

.footer-links a:hover {
  text-decoration: underline;
}

/* ---------- login modal ---------- */

.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(27, 20, 20, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  /* Above Leaflet's own stacking (mapa.html) — its panes/controls go up to
     ~1000 by default, well past this overlay's old z-index of 50. */
  z-index: 2000;
}

.modal-overlay[hidden] {
  display: none;
}

.modal {
  background: var(--surface);
  border: var(--outline) solid var(--ink);
  border-radius: var(--radius-card);
  box-shadow: 6px 6px 0 var(--ink);
  padding: 28px;
  width: 100%;
  max-width: 360px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* Between the login modal's 360px and a full-bleed sheet — used by prompts
   that need room for two CTAs side by side (e.g. the sign-in-or-download
   gate on venue cards). */
.modal--medium {
  max-width: 460px;
}

.modal h2 {
  font-size: 22px;
}

.modal input {
  border: var(--outline) solid var(--ink);
  border-radius: var(--radius-card);
  padding: 11px 14px;
  font-family: var(--font-body);
  font-size: 15px;
  background: var(--surface);
  color: var(--ink);
}

.password-field {
  position: relative;
  display: flex;
}

.password-field input {
  flex: 1;
  padding-right: 40px;
}

.password-toggle {
  position: absolute;
  right: 4px;
  top: 0;
  bottom: 0;
  width: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  cursor: pointer;
  font-size: 16px;
  padding: 0;
}

.modal .close {
  align-self: flex-end;
  font-weight: 700;
  font-size: 13.5px;
  color: var(--mute);
  cursor: pointer;
  background: none;
  border: none;
  padding: 0;
}

.modal .error {
  color: var(--tomato);
  font-size: 13.5px;
}

.user-chip {
  display: flex;
  align-items: center;
  gap: 10px;
}

.user-chip .name {
  font-weight: 800;
  font-size: 14px;
}

.user-chip .signout {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--mute);
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
}

.lang-switch {
  display: flex;
  gap: 4px;
}

.lang-switch a {
  padding: 6px 10px;
  border-radius: var(--radius-chip);
  font-size: 12.5px;
  font-weight: 800;
  text-decoration: none;
  border: var(--outline) solid var(--ink);
}

.lang-switch a.active {
  background: var(--grape);
  color: var(--on-grape);
  border-color: var(--ink);
}

@media (max-width: 900px) {
  .steps-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 640px) {
  .venue-card {
    flex-basis: 220px;
  }
  .showcase {
    height: 420px;
  }
  .showcase-initial {
    font-size: 100px;
  }
  .hero-carousel {
    height: 72vh;
    min-height: 460px;
  }
  .steps-grid {
    grid-template-columns: 1fr;
  }
}
