/* "Neon Soi" — find-a-bar.html
   Night-life directory identity: cool night ground, pink/cyan neon accents,
   amber demoted to a single job (the verified badge). See tokens.css for
   the shared palette this builds on. */

body{display:block;max-width:none;padding:0;background:var(--ink);color:var(--cream);
  font-family:'Plus Jakarta Sans',system-ui,sans-serif;font-weight:500;margin:0;
  -webkit-font-smoothing:antialiased}
.wrap{max-width:1160px;margin:0 auto;padding:0 20px 100px}

/* ── hero band ── a soft neon glow standing in for the old flat marquee */
.marquee{
  position:relative;overflow:hidden;
  background:
    radial-gradient(560px 260px at 10% -15%, var(--pink-soft), transparent 60%),
    radial-gradient(480px 240px at 95% -25%, var(--cyan-soft), transparent 60%),
    linear-gradient(180deg, var(--panel-2), var(--ink) 85%);
  border-bottom:1px solid var(--line-soft);padding:26px 20px 46px;margin:0 0 -26px
}
.marquee-inner{max-width:1160px;margin:0 auto;display:flex;align-items:flex-end;justify-content:space-between;gap:24px;flex-wrap:wrap}
.marquee .brand{margin:0;font-size:12px;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);font-weight:700}
.pagetitle{font-family:'Bebas Neue',sans-serif;font-weight:400;font-size:clamp(32px,6vw,50px);
  line-height:.96;letter-spacing:.5px;margin:6px 0 6px;color:var(--cream);text-wrap:balance}
.pagetitle a{color:inherit;text-decoration:none}
.pagetitle a:hover{text-decoration:underline}
.marquee .tag{color:var(--muted);font-size:14.5px;margin:0;max-width:46ch}
.statstrip{display:flex;gap:20px;flex-wrap:wrap}
.stat{text-align:right}
.stat b{display:block;font-family:'Bebas Neue',sans-serif;font-size:25px;color:var(--cyan);line-height:1;font-variant-numeric:tabular-nums}
.stat span{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.06em}
@media (max-width:640px){ .statstrip{display:none} }

/* ── glass toolbar ── floats over the hero glow, so the blur is doing real
   compositing work rather than sitting on a flat panel for texture */
.toolbar-wrap{position:relative;z-index:2}
.toolbar{
  display:flex;gap:10px;flex-wrap:wrap;align-items:center;
  background:color-mix(in srgb, var(--panel) 70%, transparent);
  backdrop-filter:blur(18px) saturate(160%); -webkit-backdrop-filter:blur(18px) saturate(160%);
  border:1px solid var(--line);border-radius:var(--radius);padding:12px;margin-bottom:14px;
  box-shadow:var(--shadow-2);
}
.searchfield{flex:1 1 240px;display:flex;align-items:center;gap:8px;
  background:var(--ink);border:1px solid var(--line);border-radius:10px;padding:0 6px 0 12px;height:44px}
.searchfield svg{flex-shrink:0;opacity:.6}
.searchfield input{flex:1;background:none;border:none;color:var(--cream);font-size:14.5px;font-family:inherit;height:100%;outline:none}
.searchfield input::placeholder{color:var(--muted)}
.searchfield input:disabled{color:var(--muted);cursor:default}
.locbtn{flex-shrink:0;height:32px;width:32px;border-radius:8px;border:none;background:var(--line-soft);
  color:var(--muted);display:flex;align-items:center;justify-content:center;cursor:pointer;padding:0}
.locbtn:hover{background:var(--cyan-soft);color:var(--cyan)}
.locbtn:disabled{opacity:.5;cursor:wait}
.toolbar .btn{flex-shrink:0;height:44px;padding:0 22px;font-size:14px;border-radius:10px}

/* ── style filter — icon button in the search bar opens a bottom sheet,
   on every viewport size (used to be an inline row on desktop that ended up
   orphaned below the footer — see history) ── */
.filterbtn{position:relative;flex-shrink:0;height:32px;width:32px;border-radius:8px;border:none;
  background:var(--line-soft);color:var(--muted);display:flex;align-items:center;justify-content:center;
  cursor:pointer;padding:0}
.filterbtn:hover{background:var(--blue-soft);color:var(--blue)}
.filterbtn .fcount{position:absolute;top:-5px;right:-5px;background:var(--blue);color:var(--ink);
  font-size:10px;font-weight:800;min-width:15px;height:15px;border-radius:100px;
  display:flex;align-items:center;justify-content:center;padding:0 3px;font-variant-numeric:tabular-nums}
.filterbtn .fcount:empty{display:none}

.sheet-backdrop{display:block;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:45;
  opacity:0;pointer-events:none;transition:opacity .25s}
.sheet-backdrop.open{opacity:1;pointer-events:auto}

.tagpanel{position:fixed;left:10px;right:10px;bottom:10px;z-index:50;margin:0 auto;max-width:460px;
  background:var(--panel);border:1px solid var(--line);border-radius:var(--radius-lg);
  padding:8px 18px calc(18px + env(safe-area-inset-bottom));
  box-shadow:var(--shadow-2);max-height:65vh;overflow-y:auto;
  transform:translateY(120%);transition:transform .3s cubic-bezier(.32,.72,0,1)}
.tagpanel.open{transform:translateY(0)}
.tagpanel::before{content:"";display:block;width:36px;height:4px;background:var(--line);border-radius:4px;margin:10px auto 14px}
.tagpanel-head{display:flex;justify-content:space-between;align-items:center;margin:0 0 12px;
  font-size:12px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.06em}
.sheet-done{background:none;border:none;color:var(--blue);font-weight:700;font-size:13px;cursor:pointer;
  text-transform:none;letter-spacing:0;padding:4px}

.tagrow{display:flex;flex-wrap:wrap;gap:8px}
.tagchip{background:var(--panel);border:1px solid var(--line);border-radius:100px;padding:7px 14px;
  font-size:13px;font-weight:600;cursor:pointer;user-select:none;color:var(--muted);
  transition:border-color .15s,color .15s,background .15s}
.tagchip:hover:not(.on){border-color:var(--muted)}
.tagchip.on{background:var(--cyan-soft);border-color:var(--cyan);color:var(--cyan)}

/* "Buzzing now" filter chip — same red/pink gradient as the .busychip badge
   (find-a-bar.html's BUSY_FLAME_SVG) so the filter reads as the same signal. */
.tagchip.buzzing{display:inline-flex;align-items:center;gap:5px}
.tagchip.buzzing svg{flex-shrink:0}
.tagchip.buzzing.on{background:linear-gradient(135deg,var(--red),var(--pink));border-color:transparent;color:#fff}
.tagchip.promo{display:inline-flex;align-items:center;gap:5px}
.tagchip.promo svg{flex-shrink:0}
.tagchip.promo.on{background:var(--amber);border-color:transparent;color:#1a1204}
/* "Hot Promo" filter chip — same red/pink gradient as the tile badge/busychip
   so all three read as the same "hot" signal. */
.tagchip.hotpromo{display:inline-flex;align-items:center;gap:5px}
.tagchip.hotpromo.on{background:linear-gradient(135deg,var(--red),var(--pink));border-color:transparent;color:#fff}
#specialRow{padding-bottom:10px;margin-bottom:10px;border-bottom:1px solid var(--line)}

.results-head{display:flex;justify-content:space-between;align-items:baseline;gap:10px;margin:18px 0 12px;flex-wrap:wrap}
.results-head h2{font-size:13px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;margin:0}
.results-head .count{font-size:12.5px;color:var(--muted)}

/* ── results grid ── */
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:12px}

/* photo-forward card: the whole card IS the thumbnail — a fixed height with
   the photo/art filling it edge to edge, a bottom scrim, and the bar's own
   identity (name, tags, action) overlaid directly on that scrim. Replaces
   the old photo-strip-plus-grey-panel split so there's no dead space below
   a short name/tag line. */
.barcard{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
  position:relative;overflow:hidden;text-decoration:none;color:inherit;height:230px;
  transition:border-color .15s,transform .15s,box-shadow .15s;box-shadow:var(--shadow-1)}
.barcard:hover{border-color:var(--pink);transform:translateY(-2px);box-shadow:var(--shadow-2)}
/* whole-card click target, sized to cover the card — NOT a wrapping <a>,
   since an <a> can't contain another <a> (the claimlink below) without the
   HTML parser silently splitting it into multiple elements on a full page
   parse (only escaped the client's old innerHTML-assignment path). */
.barcard-hit{position:absolute;inset:0;z-index:1}
.claimlink{position:relative;z-index:2}

/* the nearest bar (only shown when we actually know distance — size here is
   a real signal, not decoration) just gets a taller, full-width version of
   the same overlay card rather than a separate row layout. */
.barcard.featured{grid-column:1/-1;height:300px}
.barcard.featured .name2{font-family:'Bebas Neue',sans-serif;font-weight:400;font-size:28px;letter-spacing:.3px}
@media (max-width:640px){
  .barcard.featured{height:220px}
}

.thumb{position:absolute;inset:0;overflow:hidden}
.thumb-img{width:100%;height:100%;object-fit:cover;display:block}
.thumb-art{position:absolute;inset:0}
.thumb-icon{position:absolute;left:50%;top:36%;transform:translate(-50%,-50%);width:32px;height:32px;
  color:rgba(255,255,255,.5)}
.thumb .dist{position:absolute;top:38px;right:9px;z-index:4;background:rgba(10,14,21,.6);backdrop-filter:blur(8px);
  color:var(--cyan);font-size:11px;font-weight:600;padding:4px 10px;border-radius:100px;font-variant-numeric:tabular-nums}
.thumb .verified{position:absolute;left:9px;top:9px;z-index:4;background:var(--amber-soft);border:1px solid var(--amber);
  color:var(--amber);font-size:9.5px;font-weight:700;padding:3px 9px;border-radius:100px;text-transform:uppercase;letter-spacing:.04em}

/* a claimed bar's own paid Hot Promo — stacked under .verified (left side),
   never competes with .busychip/.dist which stack on the right. */
.thumb .hotpromobadge{position:absolute;left:9px;top:38px;z-index:4;background:linear-gradient(135deg,var(--red),var(--pink));
  color:#fff;font-size:9.5px;font-weight:800;padding:3px 9px;border-radius:100px;text-transform:uppercase;letter-spacing:.03em}

/* bottom-anchored gradient (non-interactive) so overlaid text stays legible
   against any photo, plus the name/tags/action block sitting on top of it.
   Both are scoped INSIDE the default face only (see thumbCycleHtml()) so
   they fade out together with the bar's own photo rather than persisting
   on top of a cycling paid ad. */
.scrim{position:absolute;left:0;right:0;bottom:0;height:78%;z-index:2;pointer-events:none;
  background:linear-gradient(180deg,rgba(10,14,21,0) 0%,rgba(10,14,21,.55) 52%,rgba(10,14,21,.95) 100%)}
.cardinfo{position:absolute;left:0;right:0;bottom:0;z-index:3;padding:12px 14px 13px;
  display:flex;flex-direction:column;gap:5px}
.name2{font-weight:700;font-size:15.5px;line-height:1.25;color:var(--cream)}
.tags2{color:rgba(243,239,231,.68);font-size:12px}
.foot2{display:flex;justify-content:space-between;align-items:center;gap:8px;margin-top:3px;font-size:12px;min-height:26px}
.claimlink{color:#fff;background:var(--pink);text-decoration:none;font-weight:800;font-size:11.5px;
  padding:7px 13px;border-radius:8px;box-shadow:0 4px 14px var(--pink-soft)}
.claimlink:hover{filter:brightness(1.08)}
.contact-icons{display:flex;gap:6px;position:relative;z-index:2}
.contact-icons a{width:27px;height:27px;border-radius:8px;background:rgba(255,255,255,.12);color:var(--cream);
  display:flex;align-items:center;justify-content:center;flex-shrink:0}
.contact-icons a:hover{background:rgba(255,255,255,.22)}
.contact-icons svg{width:13px;height:13px}

/* "🔥 Busy now" — real QR check-ins (see db/repositories/checkins.js), not a
   hotlinked GIF. Top-right of the thumb (adbadge/verified share top-left,
   dist sits just under this chip). Pulsing glow for a bit of "banging" energy; a
   static badge for anyone who's asked their OS to reduce motion. */
.thumb .busychip, .busychip{position:absolute;right:9px;top:9px;z-index:3;display:inline-flex;align-items:center;gap:4px;
  background:linear-gradient(135deg,var(--red),var(--pink));color:#fff;font-size:9.5px;font-weight:800;
  padding:3px 9px 3px 7px;border-radius:100px;text-transform:uppercase;letter-spacing:.03em;
  box-shadow:0 0 0 0 rgba(255,61,120,.55);animation:busyPulse 1.8s ease-in-out infinite}
.busychip svg{flex-shrink:0;animation:busyFlicker 1.8s ease-in-out infinite}
@keyframes busyPulse{0%,100%{box-shadow:0 0 0 0 rgba(255,61,120,.5)}50%{box-shadow:0 0 8px 2px rgba(255,61,120,.5)}}
@keyframes busyFlicker{0%,100%{transform:scale(1) rotate(0deg)}50%{transform:scale(1.15) rotate(-4deg)}}
@media (prefers-reduced-motion: reduce){
  .busychip, .busychip svg{animation:none}
}

/* a paid ad filling an unclaimed bar's thumbnail (see api/server.js
   pickAdForSlug()) — sits above .barcard-hit (z-index:1) the same way
   .claimlink already does, so a click on the ad itself goes to the
   advertiser rather than the bar's own page. .dist/.verified above are
   bumped to z-index:3 so they still show on top of this when they coincide
   (a "near me" distance badge can appear on an unclaimed bar's ad). */
.thumb-ad-link, .thumb-photo-link{position:absolute;inset:0;z-index:2;display:block}
.thumb .adbadge{position:absolute;left:9px;top:9px;background:rgba(10,14,21,.65);backdrop-filter:blur(6px);
  color:var(--muted);font-size:9px;font-weight:700;padding:3px 8px;border-radius:100px;text-transform:uppercase;letter-spacing:.05em}

/* an unclaimed bar's thumbnail cycles between its own default face (real
   photo, or the tag-tinted art below) and every live ad, one at a time —
   default, ad 1, default, ad 2, default, ad 3, … looping. Pure CSS crossfade
   (opacity keyframes), no JS timer: each layer is stacked full-bleed and
   independently animated, using ONE shared cycleDefault keyframe for the
   default face (its on/off rhythm — 15s shown, 1s fade, 32s period — never
   changes) and a per-page cycleAd keyframe whose period scales with however
   many live ads there are right now (see api/server.js adCycleKeyframesCss()
   / find-a-bar.html's client copy, injected via <!-- DIRECTORY_AD_KEYFRAMES
   -->). A layer's own animation-delay places it in its slot; every card also
   gets a per-slug stagger added on top (see thumbCycleHtml()) so a grid full
   of cards doesn't cycle in lockstep. pointer-events rides along in the same
   keyframes so only the currently-visible layer is ever clickable — no dead
   clicks, no click-through to the wrong ad mid-fade. */
.thumb-cycle{position:absolute;inset:0;z-index:2}
.thumb-cycle-layer{position:absolute;inset:0;overflow:hidden;opacity:0;pointer-events:none;
  animation-timing-function:ease-in-out;animation-iteration-count:infinite}
.thumb-cycle-layer.default{animation-name:cycleDefault;animation-duration:32s}
.thumb-cycle-layer.ad{animation-name:cycleAd}
@keyframes cycleDefault{
  0%,46.875%{opacity:1;pointer-events:auto}
  50%,96.875%{opacity:0;pointer-events:none}
  100%{opacity:1;pointer-events:auto}
}
@media (prefers-reduced-motion: reduce){
  .thumb-cycle-layer{animation:none}
  .thumb-cycle-layer.default{opacity:1;pointer-events:auto}
}

/* a claimed bar's own photo gallery (2-5 uploaded photos, see /manage's
   Photos card) crossfades the same way as the default/ad cycle above, but
   against ONE of these fixed keyframes rather than a per-page-injected one:
   ad count is the same for every card on a page, so cycleAd can be computed
   once per page, but a listing's own photo count varies card-to-card, so no
   single page-wide keyframe could fit every card's cycle at once. Each
   .thumb-cycle-layer.photo picks the right one via an inline
   animation-name override (see api/views/adCycle.js photoCycleLayers) —
   there are only 4 possible counts (MAX_LISTING_PHOTOS = 5, and a single
   photo never cycles at all), so these are precomputed here rather than
   generated at request time. */
@keyframes cyclePhoto2{0%,46.8750%{opacity:1;pointer-events:auto}50.0000%,96.8750%{opacity:0;pointer-events:none}100%{opacity:1;pointer-events:auto}}
@keyframes cyclePhoto3{0%,31.2500%{opacity:1;pointer-events:auto}33.3333%,97.9167%{opacity:0;pointer-events:none}100%{opacity:1;pointer-events:auto}}
@keyframes cyclePhoto4{0%,23.4375%{opacity:1;pointer-events:auto}25.0000%,98.4375%{opacity:0;pointer-events:none}100%{opacity:1;pointer-events:auto}}
@keyframes cyclePhoto5{0%,18.7500%{opacity:1;pointer-events:auto}20.0000%,98.7500%{opacity:0;pointer-events:none}100%{opacity:1;pointer-events:auto}}

/* house ad — fills an unclaimed bar's ad slot whenever there are no live
   paid ads to show instead (see api/server.js directoryCardThumb()), so an
   empty slot promotes /add-your-bar rather than just sitting on the tag-art
   forever. Single cyan wash (not the marquee's full pink+cyan glow) so it
   reads as a real card in the grid rather than competing with actual paid
   ads for attention. */
.thumb-promo{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;
  justify-content:center;text-align:center;text-decoration:none;padding:10px;
  background:radial-gradient(150% 170% at 50% 0%, var(--cyan-soft), transparent 65%), var(--panel-2)}
.thumb-promo-icon{width:28px;height:28px;color:var(--cyan);margin-bottom:8px}
.thumb-promo-head{font-family:'Bebas Neue',sans-serif;font-weight:400;letter-spacing:.3px;
  font-size:20px;color:var(--cream);line-height:1.05}
.thumb-promo-sub{font-size:11.5px;color:var(--muted);margin:4px 0 10px}
.thumb-promo-btn{display:inline-flex;align-items:center;gap:4px;background:var(--pink);color:#fff;
  font-size:12px;font-weight:800;padding:7px 14px;border-radius:100px;box-shadow:0 4px 14px var(--pink-soft)}
.thumb-promo:hover .thumb-promo-btn{filter:brightness(1.08)}

/* category-tinted art behind the icon when there's no real photo yet —
   same 8 style tags used for filtering, so the thumbnail is doing
   information work instead of sitting empty */
.thumb-art.g-beach-bar{background:radial-gradient(120% 140% at 20% 0%, #17414a, #0c1c22 70%)}
.thumb-art.g-gogo{background:radial-gradient(120% 140% at 80% 0%, #451233, #170c1c 70%)}
.thumb-art.g-craft-beer{background:radial-gradient(120% 140% at 30% 0%, #3a2c13, #1a1509 70%)}
.thumb-art.g-rooftop{background:radial-gradient(120% 140% at 70% 0%, #12324a, #0b1a26 70%)}
.thumb-art.g-sports-bar{background:radial-gradient(120% 140% at 40% 0%, #2c1a10, #170f0a 70%)}
.thumb-art.g-late-night{background:radial-gradient(120% 140% at 60% 0%, #241a3c, #100c1c 70%)}
.thumb-art.g-live-music{background:radial-gradient(120% 140% at 50% 0%, #123a2e, #0b1c17 70%)}
.thumb-art.g-cocktails{background:radial-gradient(120% 140% at 35% 0%, #3a1420, #190a10 70%)}
.thumb-art.g-bar-restaurant{background:radial-gradient(120% 140% at 45% 0%, #1a3a1c, #0c1c0e 70%)}
.thumb-art.g-default{background:radial-gradient(120% 140% at 50% 0%, #202632, #0e141c 70%)}

/* ── grid pager ── the default/searched grid pages through 8 cards at a time
   (2 on mobile, see find-a-bar.html PAGE_SIZE_*) rather than dumping every
   matching bar into one long scroll. display:none by default so it never
   flashes visible before setupPager() decides whether paging is even needed
   (a short result set just shows every card, no pager at all). */
.pager{display:none;align-items:center;justify-content:center;gap:14px;margin-top:16px}
.pagerbtn{flex-shrink:0;width:34px;height:34px;border-radius:100px;border:1px solid var(--line);
  background:var(--panel);color:var(--cream);display:flex;align-items:center;justify-content:center;cursor:pointer;padding:0}
.pagerbtn:hover{border-color:var(--pink);color:var(--pink)}
.pagerdots{display:flex;align-items:center;gap:6px}
.pagerdot{width:6px;height:6px;padding:0;border-radius:100px;border:none;background:var(--line);cursor:pointer;transition:background .15s,width .15s}
.pagerdot:hover{background:var(--muted)}
.pagerdot.on{background:var(--pink);width:18px}

.empty{color:var(--muted);text-align:center;padding:30px 10px;font-size:14px}
.empty a{color:var(--pink);font-weight:700;text-decoration:none}
.empty a:hover{text-decoration:underline}

.footerband{margin-top:8px;padding:20px;background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
  display:flex;justify-content:space-between;align-items:center;gap:16px;flex-wrap:wrap}
.footerband .msg2 b{display:block;font-size:15px;color:var(--cream);margin-bottom:2px}
.footerband .msg2 span{font-size:12.5px;color:var(--muted)}
.footerband .btn{flex-shrink:0}

@media (prefers-reduced-motion: reduce){
  .tagpanel, .sheet-backdrop, .barcard{transition:none}
}
