/* Nittany Nights site CSS — source of truth lives at
 * nittany_nights/themes/modern_v2/app.css; the renderer copies it to the
 * site root and cache-busts via ?v=<content-hash> in index.html. */
:root {
  --bg: #040810;
  --bg2: #080f1e;
  --card: #0b1220;
  --card-hover: #111c30;
  --border: rgba(255,255,255,0.07);
  --border-strong: rgba(255,255,255,0.14);
  --accent: #1e407c;
  --accent2: #4a7bc4;
  --neon: #85aee0;
  --text: #eef3fb;
  --text-dim: #b7c6db;
  --muted: #8ba4be;
  --dimmer: #5a7a9e;
  --green: #10b981;
  --amber: #f59e0b;
  --red: #f43f5e;

  --music: #38bdf8;
  --drinks: #f2b04a;
  --food: #4ade80;
  --sports: #fb923c;
  --events: #b794f4;
  --gold: #d4af37;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  background: var(--bg);
  color: var(--text);
  font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, sans-serif;
  font-size: 15px;
  min-height: 100vh;
  overflow-x: hidden;
  line-height: 1.5;
  /* Clear the gesture nav bar when running edge-to-edge (app/PWA). 0 in browsers. */
  padding-bottom: env(safe-area-inset-bottom);
}
/* Opaque fill behind the transparent edge-to-edge status bar so scrolled
   content never shows through behind the system clock/wifi/battery icons.
   (body::before is the noise texture, so the scrim lives on ::after.) */
body::after {
  content: ''; position: fixed; top: 0; left: 0; right: 0;
  height: env(safe-area-inset-top);
  background: var(--bg); z-index: 30; pointer-events: none;
}
body::before {
  content: ''; position: fixed; inset: 0; pointer-events: none; z-index: 0;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='0.035'/%3E%3C/svg%3E");
  opacity: 0.4;
}
.glow { position: fixed; border-radius: 50%; filter: blur(130px); opacity: 0.16; pointer-events: none; z-index: 0; }
.glow-1 { width: 600px; height: 600px; background: #1e407c; top: -220px; left: -180px;
  animation: drift1 18s ease-in-out infinite alternate; }
.glow-2 { width: 500px; height: 500px; background: #6d28d9; bottom: -100px; right: -150px; opacity: 0.09;
  animation: drift2 14s ease-in-out infinite alternate; }
.glow-3 { width: 380px; height: 380px; background: #4a7bc4; top: 30%; left: 45%; opacity: 0.06;
  animation: drift3 22s ease-in-out infinite alternate; }

@keyframes drift1 { from { transform: translate(0,0); } to { transform: translate(40px,30px); } }
@keyframes drift2 { from { transform: translate(0,0); } to { transform: translate(-30px,-20px); } }
@keyframes drift3 { from { transform: translate(0,0); } to { transform: translate(20px,-30px); } }

header {
  position: relative; z-index: 10;
  background: rgba(7,10,18,0.85);
  backdrop-filter: blur(20px);
  border-bottom: 1px solid var(--border);
  /* Push header content below the status bar when running edge-to-edge. */
  padding-top: env(safe-area-inset-top);
}
.header-inner {
  max-width: 820px; margin: 0 auto;
  padding: 0.55rem calc(1.25rem + env(safe-area-inset-right)) 0.55rem calc(1.25rem + env(safe-area-inset-left));
  display: flex; align-items: center; justify-content: space-between;
  gap: 0.75rem;
}
.brand { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }
.brand-row { display: flex; align-items: baseline; gap: 0.55rem; min-width: 0; }
.wordmark { font-family: 'Bebas Neue', sans-serif; font-size: 1.85rem; letter-spacing: 0.04em; color: #fff; line-height: 1; }
.wordmark .accent {
  color: var(--wm-accent, #22d3ff);
  text-shadow:
    0 0 4px var(--wm-glow-strong, rgba(34,211,255,0.9)),
    0 0 10px var(--wm-glow-mid, rgba(34,211,255,0.55)),
    0 0 22px var(--wm-glow-soft, rgba(34,211,255,0.35));
}
.tagline {
  font-family: 'DM Mono', monospace;
  font-size: 0.56rem; color: var(--accent2);
  letter-spacing: 0.16em; text-transform: uppercase; white-space: nowrap;
}
.logo-seo {
  font-family: 'DM Sans', sans-serif;
  font-size: 0.72rem; color: var(--text-dim);
  opacity: 0.85;
  line-height: 1.1;
}
.header-meta { display: flex; align-items: center; gap: 0.65rem; flex-shrink: 0; }
.weather-pill {
  display: flex; align-items: center; gap: 0.35rem;
  background: var(--card); border: 1px solid var(--border);
  border-radius: 100px; padding: 0.3rem 0.7rem;
  font-size: 0.78rem; color: var(--muted);
  text-decoration: none;
}
.weather-pill:hover { text-decoration: none; }
.weather-pill span { color: var(--text); font-weight: 600; }
.header-icon {
  color: var(--muted);
  width: 1.9rem; height: 1.9rem;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 100px; text-decoration: none;
  font-size: 0.95rem; transition: all 0.15s;
}
.header-icon:hover { color: var(--text); background: var(--card); }
.header-icon svg { width: 1rem; height: 1rem; fill: currentColor; }
.header-icon-ig svg path { fill: url(#ig-grad); }
.header-icon-ig:hover { background: var(--card); }

.ts-bar {
  text-align: center;
  font-family: 'DM Mono', monospace;
  font-size: 0.62rem; color: var(--dimmer);
  letter-spacing: 0.14em;
  padding: 0.3rem 0.5rem;
  border-bottom: 1px solid var(--border);
  background: rgba(7,10,18,0.6);
  position: relative; z-index: 10;
  text-transform: uppercase;
}
.ts-bar a, .ts-bar a:link, .ts-bar a:visited {
  color: inherit; text-decoration: underline;
}
/* App promo cycle in the updated bar (see app.js). .ts-fade is an inner
   wrapper injected only for eligible Android/iOS visitors; fading it keeps
   the bar's border/background solid during the content swap. The .ts-promo
   rule out-specifies the generic .ts-bar a underline rule above. */
.ts-fade { transition: opacity 0.3s ease; }
.ts-bar a.ts-promo, .ts-bar a.ts-promo:link, .ts-bar a.ts-promo:visited {
  color: var(--text-dim); text-decoration: none;
}
.promo-play {
  width: 10px; height: 10px; margin-right: 6px;
  vertical-align: middle; position: relative; top: -1px;
}
.promo-appstore {
  width: 11px; height: 11px; margin-right: 6px;
  vertical-align: middle; position: relative; top: -1px;
  color: var(--wm-accent, #22d3ff);
}
.live-dot {
  display: inline-block; width: 6px; height: 6px;
  background: var(--green); border-radius: 50%; margin-right: 6px;
  animation: pulse 2s ease-in-out infinite;
  vertical-align: middle; position: relative; top: -1px;
  box-shadow: 0 0 8px rgba(16,185,129,0.6);
}
@keyframes pulse { 0%,100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.4; transform: scale(0.75); } }

/* ANNOUNCE — slim one-line ticker, styled to match .ts-bar.
   Purpose: context for why town is busy tonight (game day, farmers market, etc.)
   Auto-scrolls horizontally (stock-ticker style); pauses on hover. */
.announce {
  position: relative; z-index: 10;
  max-width: 820px; margin: 0 auto;
  font-family: 'DM Mono', monospace;
  font-size: 0.62rem; color: var(--muted);
  letter-spacing: 0.12em; text-transform: uppercase;
  border-bottom: 1px solid var(--border);
  background: rgba(7,10,18,0.55);
  display: flex; align-items: stretch;
  height: 26px;
}
.announce-lead {
  flex-shrink: 0;
  display: flex; align-items: center;
  color: #fcd34d;
  font-weight: 600;
  padding: 0 0.5rem 0 1.25rem;
  border-right: 1px solid var(--border);
  background: #060b16;
  z-index: 2;
}
.announce-mask {
  flex: 1;
  overflow: hidden;
  position: relative;
  display: flex; align-items: center;
  padding-left: 0.8rem;
}
/* DESIRED BEHAVIOR — DO NOT "FIX" THIS:
   The ticker MUST start with items just off the right edge of the mask
   (mobile-first: items slide in from the right, traverse the bar, exit left).
   This is achieved via `padding-left: 100%` on the track, which shifts the
   first item to start at x = mask_width (off-screen right). The animation
   then translates the entire track by -100% of its own width so every item
   eventually exits off the left.

   Side effect on wide desktop: because items (~337px each, banner-dependent)
   are narrower than the desktop mask (~733px), there are stretches of the
   cycle where the bar appears empty. That is acceptable — the slide-in-from-
   right entrance is the priority. Do NOT switch to a seamless `translateX(-50%)`
   marquee or remove the `padding-left: 100%`; doing so eliminates the
   off-screen-right entrance the user explicitly wants.

   If desktop emptiness ever needs addressing, the right lever is to add MORE
   banners (so the duplicated stream fills the wider mask), not to change
   this animation. */
.announce-track {
  display: inline-flex;
  white-space: nowrap;
  padding-left: 100%;
  animation: announce-scroll 120s linear infinite;
  will-change: transform;
}
/* Pause-on-hover is applied via JS (app.js), NOT CSS. A CSS `:hover` rule —
   even gated behind `@media (hover: hover)` — still fires on touch in the
   Android WebView (it reports hover:hover), where a tap leaves a sticky
   :hover that froze the ticker until you tapped elsewhere. JS gates the
   pause on `pointerType === 'mouse'`, so touch taps can never freeze it. */
.announce-track.is-paused { animation-play-state: paused; }
.announce-card {
  display: inline-block;
  color: var(--text-dim);
  padding-right: 2.2rem; /* gap between items; sep rendered via ::after */
  position: relative;
}
.announce-card::after {
  content: '·';
  position: absolute;
  right: 1rem;
  color: var(--dimmer);
}
.announce-card:last-child::after { content: ''; }
.announce-card a { color: var(--neon); text-decoration: none; font-weight: 600; }
.announce-card a:hover { text-decoration: underline; }
@keyframes announce-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-100%); }
}
/* Intentionally NOT gated on `prefers-reduced-motion: reduce`. On Windows,
   Chrome reports `reduce` whenever the OS "Animation effects" toggle is off
   (Settings > Accessibility > Visual effects), a perf/preference switch many
   users flip for reasons unrelated to motion sensitivity (and commonly off on
   VMs, RDP, corporate images). The old `.announce-track { animation: none }`
   rule froze the ticker for those users and, because the track rests at
   `padding-left: 100%`, parked every card off-screen right so the bar rendered
   EMPTY, not merely static. The ticker is decorative and already pauses on
   hover/tap (WCAG 2.2.2 Pause/Stop/Hide), so by design it scrolls everywhere.
   See lessons.md: "Windows Chrome froze the ticker via prefers-reduced-motion." */

.day-nav-wrapper {
  position: sticky; top: env(safe-area-inset-top); z-index: 20;
  background: rgba(7,10,18,0.92); backdrop-filter: blur(20px);
  border-bottom: 1px solid var(--border);
}
.day-nav {
  max-width: 820px; margin: 0 auto;
  display: flex; gap: 0.625rem;
  padding: 0.4rem calc(1.25rem + env(safe-area-inset-right)) 0.4rem calc(1.25rem + env(safe-area-inset-left));
  overflow-x: auto; scrollbar-width: none;
  scroll-snap-type: x proximity;
  scroll-padding-inline-start: 1.25rem;
}
.day-nav::-webkit-scrollbar { display: none; }
.day-tab {
  flex-shrink: 0; padding: 0.3rem 0.9rem;
  min-width: 72px; text-align: center;
  border-radius: 100px;
  font-size: 0.78rem; font-weight: 500;
  cursor: pointer; border: 1px solid var(--border);
  background: transparent; color: var(--muted);
  transition: all 0.15s; white-space: nowrap;
  font-family: inherit;
  scroll-snap-align: start;
}
.day-tab:hover { color: var(--text); border-color: var(--border-strong); }
.day-tab.today { border-color: var(--accent2); color: var(--neon); }
.day-tab.active { background: var(--accent2); border-color: var(--accent2); color: #fff; font-weight: 600; }
/* App-only Live view pill (left of Today; 2026-07-27 spec). Green idle
   accents; filled green when the live-sorted view is active. Static dot
   (no pulse) keeps reduced-motion trivial. */
.day-tab.live-tab { color: var(--green); border-color: rgba(16, 185, 129, 0.45); }
.day-tab.live-tab:hover { color: var(--green); border-color: var(--green); }
.day-tab.live-tab .live-tab-dot {
  display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: var(--green); margin-right: 6px; vertical-align: 1px;
}
.day-tab.live-tab.active {
  background: var(--green); border-color: var(--green);
  color: #04120c; font-weight: 600;
}
.day-tab.live-tab.active .live-tab-dot { background: #04120c; }

.filters {
  max-width: 820px; margin: 0 auto;
  display: flex; gap: 0.625rem;
  padding: 0.45rem 1.25rem 0.1rem;
  flex-wrap: wrap;
  justify-content: flex-start;
}
.filter-pill {
  display: inline-flex; align-items: center; gap: 0.4rem;
  padding: 0.55rem 0.9rem;
  min-height: 40px;
  border-radius: 100px;
  font-size: 0.8rem; font-weight: 500;
  cursor: pointer; border: 1px solid var(--border);
  background: var(--card); color: var(--muted);
  transition: all 0.15s; font-family: inherit;
}
.filter-pill:hover { color: var(--text); border-color: var(--border-strong); }
.filter-pill.active { color: var(--text); border-color: var(--border-strong); background: var(--card-hover); }
.dot { width: 7px; height: 7px; border-radius: 50%; display: inline-block; }
.dot.all { background: rgba(255,255,255,0.55); box-shadow: 0 0 5px rgba(255,255,255,0.25); }
.dot.music { background: var(--music); box-shadow: 0 0 6px rgba(56,189,248,0.7); }
.dot.drinks { background: var(--drinks); box-shadow: 0 0 6px rgba(242,176,74,0.7); }
.dot.food { background: var(--food); box-shadow: 0 0 6px rgba(74,222,128,0.7); }
.dot.sports { background: var(--sports); box-shadow: 0 0 6px rgba(251,146,60,0.7); }
.dot.events { background: var(--events); box-shadow: 0 0 6px rgba(183,148,244,0.7); }

main {
  position: relative; z-index: 5;
  max-width: 820px; margin: 0 auto;
  padding: 0.6rem 1.25rem 3rem;
}
.day-section { display: none; }
.day-section.visible { display: block; }

.day-header {
  display: flex; align-items: flex-end; gap: 1rem;
  margin: 0.2rem 0 calc(0.3rem + 4px);
  flex-wrap: wrap;
}
.day-label {
  font-family: 'Bebas Neue', sans-serif;
  font-size: 2.3rem; letter-spacing: 0.04em;
  color: #fff; line-height: 0.9;
}
.day-weather {
  margin-left: auto;
  align-self: flex-end;
  display: flex; align-items: center; gap: 0.45rem;
  color: var(--text-dim); font-size: 0.82rem;
  padding: 0.4rem 0.7rem;
  background: rgba(255,255,255,0.025);
  border: 1px solid rgba(255,255,255,0.05);
  border-radius: 10px;
}
.day-weather .day-weather-icon { font-size: 1.1rem; }
.day-weather .day-weather-info { display: flex; flex-direction: column; line-height: 1.25; }
.day-weather .day-weather-top { font-size: 0.72rem; }
.day-weather .day-weather-temps { font-family: 'DM Mono', monospace; font-size: 0.62rem; color: var(--dimmer); }

/* TONIGHT HOURLY FORECAST — slim, below venues, before pricing */
.tonight-forecast-wrap {
  position: relative; z-index: 5;
  max-width: 820px; margin: 0 auto;
  padding: 0 1.25rem;
}
.tonight-forecast {
  background: rgba(255,255,255,0.015);
  border: 1px solid rgba(255,255,255,0.05);
  border-radius: 12px;
  padding: 0.4rem 0.65rem 0.45rem;
  margin-bottom: 0.55rem;
  scroll-margin-top: calc(120px + env(safe-area-inset-top)); /* clear the sticky day-nav when scrolled to via #tonight-forecast */
}
html { scroll-behavior: smooth; }
.tonight-label {
  font-family: 'DM Mono', monospace;
  font-size: 0.58rem; letter-spacing: 0.18em;
  color: var(--dimmer); text-transform: uppercase;
  margin-bottom: 0.4rem;
}
.tonight-hours {
  display: flex; gap: 0.2rem;
  overflow-x: auto; scrollbar-width: none;
  justify-content: space-between;
}
.tonight-hours::-webkit-scrollbar { display: none; }
.th-hour {
  flex: 1; min-width: 40px;
  text-align: center;
  display: flex; flex-direction: column;
  align-items: center; gap: 0.12rem;
}
.th-time { font-family: 'DM Mono', monospace; font-size: 0.58rem; color: var(--dimmer); text-transform: uppercase; }
.th-emoji { font-size: 1rem; line-height: 1.1; }
.th-temp { font-family: 'DM Mono', monospace; font-size: 0.72rem; color: var(--text); font-weight: 500; }
.th-precip { font-family: 'DM Mono', monospace; font-size: 0.54rem; color: var(--accent2); }

/* VENUE CARD */
.venue-card {
  position: relative;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 0.65rem 0.9rem 0.65rem;
  margin-bottom: 0.75rem;
  transition: background 0.18s, border-color 0.18s, transform 0.18s, box-shadow 0.18s;
  /* Cascade-in: fade + slide up on load */
  opacity: 0;
  transform: translateY(8px);
  animation: card-in 0.45s ease-out forwards;
  animation-delay: var(--card-delay, 0s);
}
@keyframes card-in {
  to { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .venue-card { animation: none; opacity: 1; transform: none; }
}
.venue-card:hover {
  background: var(--card-hover);
  border-color: var(--border-strong);
  transform: translateY(-1px);
  box-shadow: 0 10px 40px rgba(0,0,0,0.35);
}
/* LIVE NOW — green-tinted border, subtle green glow */
.venue-card.live-now {
  border-color: rgba(16,185,129,0.35);
  box-shadow: 0 0 0 1px rgba(16,185,129,0.08), 0 8px 28px rgba(16,185,129,0.05);
}
.venue-card.live-now:hover {
  border-color: rgba(16,185,129,0.55);
  box-shadow: 0 0 0 1px rgba(16,185,129,0.15), 0 10px 36px rgba(16,185,129,0.1);
}

.venue-head {
  display: flex; align-items: baseline;
  column-gap: 0.6rem; row-gap: 0.3rem;
  flex-wrap: wrap;
  margin-bottom: 0.35rem;
}
.venue-name {
  font-family: 'DM Sans', sans-serif;
  font-size: 1.18rem; font-weight: 700;
  color: #fff; letter-spacing: -0.01em;
  line-height: 1.15; text-decoration: none;
}
.venue-name:hover { color: var(--neon); }
.venue-arrow {
  display: inline-block; color: var(--dimmer);
  transition: all 0.15s;
  font-size: 0.8em; margin-left: 0.2em;
}
.venue-name:hover .venue-arrow { color: var(--neon); transform: translateX(3px); }
.venue-meta {
  display: flex; align-items: center; gap: 0.5rem;
  font-size: 0.78rem; color: var(--muted);
  font-family: 'DM Mono', monospace; letter-spacing: 0.05em;
}
.venue-meta .sep { opacity: 0.5; }
.age-badge {
  font-family: 'DM Mono', monospace;
  font-size: 0.56rem; font-weight: 600;
  letter-spacing: 0.08em;
  padding: 0.08rem 0.35rem;
  border-radius: 3px;
  border: 1px solid var(--border-strong);
  color: var(--muted);
  text-transform: uppercase;
}
.downtown-badge {
  font-family: 'DM Mono', monospace;
  font-size: 0.56rem; font-weight: 600;
  letter-spacing: 0.06em;
  padding: 0.08rem 0.4rem;
  border-radius: 3px;
  border: 1px solid rgba(34, 211, 255, 0.45);
  background: rgba(34, 211, 255, 0.12);
  color: #22d3ff;
  white-space: nowrap;
}

/* LIVE / UPCOMING pills — injected into .status-slot by JS */
.status-slot { display: inline-flex; }
.live-badge, .upcoming-badge {
  display: inline-flex; align-items: center; gap: 0.35rem;
  font-family: 'DM Mono', monospace;
  font-size: 0.58rem; font-weight: 600;
  letter-spacing: 0.1em; text-transform: uppercase;
  padding: 0.15rem 0.45rem;
  border-radius: 4px;
  line-height: 1;
}
.live-badge {
  color: var(--green);
  border: 1px solid rgba(16,185,129,0.45);
  background: rgba(16,185,129,0.12);
}
.live-badge::before {
  content: ''; width: 5px; height: 5px; border-radius: 50%;
  background: var(--green);
  box-shadow: 0 0 6px rgba(16,185,129,0.9);
  animation: pulse 1.6s ease-in-out infinite;
}
.upcoming-badge {
  color: #f472b6;
  border: 1px solid rgba(236,72,153,0.5);
  background: rgba(236,72,153,0.12);
  animation: up-blink 2.4s ease-in-out infinite;
}
.upcoming-badge::before {
  content: ''; width: 5px; height: 5px; border-radius: 50%;
  background: #ec4899;
  box-shadow: 0 0 8px rgba(236,72,153,0.95);
}
@keyframes up-blink {
  0%,100% { opacity: 1; }
  50%     { opacity: 0.55; }
}

/* Premier + live-now: a restrained light sweep across the LIVE pill.
   Cycle: 8s with a long dormant tail so it reads as periodic, not strobe. */
@keyframes premier-live-shimmer {
  0%        { transform: translateX(-150%) skewX(-18deg); }
  45%, 100% { transform: translateX(380%)  skewX(-18deg); }
}
/* Premier cards keep their gold frame even when live — the LIVE pill,
   green dot, and shimmer carry the live signal. Avoids a green/gold
   border clash on premier+live-now cards. */
.venue-card.premier.live-now,
.venue-card.premier.live-now:hover {
  border-color: var(--gold);
}
.venue-card.premier.live-now .live-badge {
  position: relative; overflow: hidden;
}
.venue-card.premier.live-now .live-badge::after {
  content: ''; position: absolute; inset: 0; left: 0;
  width: 35%;
  background: linear-gradient(90deg,
    rgba(255,255,255,0)    0%,
    rgba(255,255,255,0.38) 50%,
    rgba(255,255,255,0)    100%);
  animation: premier-live-shimmer 8s ease-in-out infinite;
  pointer-events: none;
}

/* BUSYNESS */
.busyness-strip {
  display: grid;
  grid-template-rows: auto auto;
  grid-template-columns: auto 1fr;
  grid-template-areas:
    "bars label"
    "ticks label";
  gap: 0 0.6rem;
  align-items: end;
  margin: 0.1rem 0 0.4rem;
  padding: 0.35rem 0.55rem 0.3rem;
  background: rgba(255,255,255,0.02);
  border: 1px solid rgba(255,255,255,0.04);
  border-radius: 8px;
}
.bs-bars { grid-area: bars; display: flex; align-items: flex-end; gap: 3px; height: 22px; }
.bs-bar {
  width: 7px;
  height: max(calc(var(--v, 0) * 22px), 3px);
  background: linear-gradient(to top, rgba(74,123,196,0.45), rgba(133,174,224,0.75));
  border-radius: 1.5px 1.5px 0 0;
  opacity: 0.55;
  position: relative;
}
.bs-bar.zero {
  opacity: 0.22;
  background: linear-gradient(to top, rgba(148,163,184,0.35), rgba(148,163,184,0.5));
}
.bs-bar.peak {
  background: linear-gradient(to top, rgba(244,63,94,0.6), rgba(251,113,133,0.95));
  opacity: 0.9;
}
.bs-bar.now {
  opacity: 1;
  background: linear-gradient(to top, rgba(34,197,94,0.9), rgba(134,239,172,1));
  box-shadow: 0 0 8px rgba(74,222,128,0.75);
  outline: 1px solid rgba(220,252,231,0.35);
}
.bs-bar.now::after {
  content: ''; position: absolute; top: -6px; left: 50%;
  transform: translateX(-50%);
  width: 4px; height: 4px; border-radius: 50%;
  background: #dcfce7; box-shadow: 0 0 6px rgba(134,239,172,0.95);
  animation: bs-pulse 2s ease-in-out infinite;
}
.bs-bar.now.peak {
  background: linear-gradient(to top, rgba(34,197,94,0.95), rgba(251,113,133,1));
  box-shadow: 0 0 10px rgba(244,63,94,0.85);
}
@keyframes bs-pulse {
  0%,100% { opacity: 1; transform: translateX(-50%) scale(1); }
  50%     { opacity: 0.5; transform: translateX(-50%) scale(0.6); }
}
.bs-ticks { grid-area: ticks; display: flex; gap: 3px; margin-top: 3px; }
.bs-tick {
  width: 7px; text-align: center;
  font-family: 'DM Mono', monospace;
  font-size: 0.52rem; color: var(--dimmer);
  line-height: 1; white-space: nowrap; overflow: visible;
}
.bs-label { grid-area: label; align-self: center; font-size: 0.72rem; color: var(--text-dim); line-height: 1.3; }
.bs-label b { color: var(--text); font-weight: 600; }

/* EVENT ROWS */
.events { display: flex; flex-direction: column; gap: 0; }
.event {
  display: flex; align-items: flex-start; gap: 0.7rem;
  padding: 0.55rem 0;
  border-top: 1px solid rgba(255,255,255,0.06);
  transition: opacity 0.2s;
}
.event:first-child { border-top: none; padding-top: 0.4rem; }

/* Event states (toggled by JS for today's venues) */
.event.past {
  opacity: 0.38;
}
.event.past .event-type { filter: saturate(0.2); }
.event.live .event-title { color: #fff; font-weight: 600; }
.event.live .event-type {
  box-shadow: -3px 0 0 rgba(16,185,129,0.6);
}
.event.live .event-time .time-text {
  color: var(--green);
  font-weight: 600;
}

.event-type {
  flex-shrink: 0;
  width: 54px;
  font-family: 'DM Mono', monospace;
  font-size: 0.58rem; font-weight: 600;
  letter-spacing: 0.1em; text-transform: uppercase;
  padding: 0.12rem 0 0.12rem 0.55rem;
  border-left: 2px solid;
  margin-top: 0.1rem;
}
.event-type.music { color: var(--music); border-color: var(--music); }
.event-type.drinks { color: var(--drinks); border-color: var(--drinks); }
.event-type.food { color: var(--food); border-color: var(--food); }
.event-type.sports { color: var(--sports); border-color: var(--sports); }
.event-type.events { color: var(--events); border-color: var(--events); }

.event-body { flex: 1; min-width: 0; }
.event-title { font-size: 0.9rem; font-weight: 500; color: var(--text); line-height: 1.35; }
.event-time {
  flex-shrink: 0;
  font-family: 'DM Mono', monospace;
  font-size: 0.7rem; color: var(--muted);
  padding-top: 0.22rem;
  white-space: nowrap;
  text-align: right;
  display: flex; flex-direction: column; align-items: flex-end; gap: 0.1rem;
}
.ends-soon {
  font-size: 0.62rem;
  color: var(--amber);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  display: none;
}
.ends-soon.visible { display: inline; }

/* PILLS */
.venue-pills {
  display: flex; gap: 0.35rem; flex-wrap: wrap;
  align-items: center;
  margin-top: 0.5rem;
  padding-top: 0.4rem;
  border-top: 1px dashed rgba(255,255,255,0.05);
}
.pill {
  display: inline-flex; align-items: center; gap: 0.4rem;
  font-size: 0.82rem; font-weight: 500;
  padding: 0.55rem 0.95rem;
  min-height: 40px;
  border-radius: 100px;
  border: 1px solid var(--border-strong);
  background: transparent;
  color: var(--muted);
  text-decoration: none;
  transition: all 0.15s;
}
.pill:hover { color: var(--text); background: var(--card-hover); }
.pill.lineleap { color: #93c5fd; border-color: rgba(96,165,250,0.28); }
.pill.lineleap:hover { color: #bfdbfe; border-color: rgba(96,165,250,0.55); background: rgba(96,165,250,0.08); }
.pill.ig { color: #f0abfc; border-color: rgba(232,121,249,0.22); }
.pill.ig:hover { color: #f5d0fe; border-color: rgba(232,121,249,0.45); background: rgba(232,121,249,0.06); }
/* Icon-only link bubbles (labels dropped 2026-07-27 to keep the row on one
   line). IG is exactly the header icon — same path, same shared #ig-grad
   gradient (fill lives on the path attribute; no fill here or it would
   override the gradient). LineLeap is its double-L monogram in the pill's
   blue accent. */
.pill.ig, .pill.lineleap { padding: 0.55rem 0.75rem; }
.pill.ig svg, .pill.lineleap svg { width: 1.05rem; height: 1.05rem; }
.pill.lineleap svg { fill: currentColor; }

/* SPONSORED — Premier
   Framed editorial treatment: 3px gold left spine + 1px gold hairline on
   the remaining three sides + a 1px inner hairline (inset shadow) for a
   double-frame "luxury catalog plate" look. Elevation shadow is DARK
   (depth), not gold (no haze). Reads as "this slot was paid for" without
   the Vegas marquee. */
.venue-card.premier {
  position: relative;
  background: var(--card);
  border: 1px solid var(--gold);
  border-left: 3px solid var(--gold);
  box-shadow:
    inset 0 0 0 1px rgba(212,175,55,0.10),   /* inner hairline frame */
    inset 0 1px 0 rgba(212,175,55,0.22),     /* top bevel highlight */
    0 0 0 1px rgba(212,175,55,0.18),         /* tight halo hugging the edge */
    0 0 12px -2px rgba(212,175,55,0.22),     /* short controlled bloom */
    0 6px 22px -10px rgba(0,0,0,0.8);        /* lift */
  padding-top: 1rem;
  transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
}
.venue-card.premier:hover {
  transform: translateY(-2px);
  box-shadow:
    inset 0 0 0 1px rgba(212,175,55,0.22),
    inset 0 1px 0 rgba(212,175,55,0.4),
    0 0 0 2px rgba(212,175,55,0.35),
    0 0 24px 0 rgba(212,175,55,0.45),
    0 12px 32px -8px rgba(0,0,0,0.9);
}
.venue-card.featured {
  border: 1px solid rgba(74,123,196,0.35);
  border-left: 3px solid var(--accent2);
  background: linear-gradient(135deg, rgba(74,123,196,0.05) 0%, var(--card) 55%);
}
.badge {
  position: absolute; top: -0.55rem; left: 1rem;
  font-family: 'DM Mono', monospace;
  font-size: 0.58rem; font-weight: 600;
  letter-spacing: 0.12em; text-transform: uppercase;
  border-radius: 4px;
  padding: 0.12rem 0.45rem;
  background: var(--card); z-index: 1;
}
.badge.premier {
  color: #e8c855;
  border: 1px solid rgba(212,175,55,0.55);
  letter-spacing: 0.18em;
  padding: 0.14rem 0.55rem;
}
.badge.featured { color: var(--accent2); border: 1px solid rgba(74,123,196,0.4); }

/* SPONSOR LOGO — top-right of premier card header.
   Reserves padding on the venue-head so the venue name never runs under
   the logo on narrow widths. Per-sponsor data-URI rules are generated at
   compile time from assets/sponsors/<venue-id>.png and injected below. */
.sponsor-logo {
  position: absolute;
  top: 0.7rem;
  right: 0.9rem;
  height: 32px;
  width: 80px;
  background-repeat: no-repeat;
  background-position: right center;
  background-size: contain;
  opacity: 0.92;
  pointer-events: none;
  z-index: 1;
}
.venue-card.premier:has(> .sponsor-logo) .venue-head {
  padding-right: 92px;
}
@media (max-width: 480px) {
  .sponsor-logo { height: 26px; width: 64px; top: 0.6rem; right: 0.8rem; }
  .venue-card.premier:has(> .sponsor-logo) .venue-head { padding-right: 72px; }
}


/* NO RESULTS */
.no-results {
  display: none;
  text-align: center;
  padding: 2rem 1rem;
  color: var(--muted);
  font-size: 0.88rem;
  border: 1px dashed var(--border);
  border-radius: 12px;
  margin-top: 1rem;
}
.no-results.visible { display: block; }

/* QUIET TONIGHT */
.quiet-tonight {
  margin-top: 1.3rem;
  background: rgba(255,255,255,0.018);
  border: 1px dashed rgba(255,255,255,0.1);
  border-radius: 14px;
  overflow: hidden;
}
.quiet-tonight > summary {
  list-style: none;
  cursor: pointer;
  padding: 0.8rem 1rem;
  display: flex; align-items: center; gap: 0.6rem;
  font-size: 0.82rem; color: var(--text-dim);
  transition: background 0.15s;
}
.quiet-tonight > summary::-webkit-details-marker { display: none; }
.quiet-tonight > summary:hover { background: rgba(255,255,255,0.015); }
.qt-chev {
  display: inline-block;
  color: var(--dimmer);
  font-size: 0.7rem;
  transition: transform 0.2s;
}
.quiet-tonight[open] > summary .qt-chev { transform: rotate(90deg); }
.qt-head {
  display: inline-flex; align-items: center; gap: 0.35rem;
  font-family: 'Bebas Neue', sans-serif;
  font-size: 1.1rem; letter-spacing: 0.05em;
  color: var(--text);
}
.qt-head .moon { font-size: 0.9rem; }
.qt-sub {
  margin-left: auto;
  font-family: 'DM Mono', monospace;
  font-size: 0.66rem; color: var(--muted);
  letter-spacing: 0.05em;
}
.qt-grid {
  display: flex; flex-direction: column; gap: 0.3rem;
  padding: 0 0.7rem 0.7rem;
}
.qt-venue {
  display: block;
  padding: 0.5rem 0.7rem;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 0.82rem;
}
.qt-venue.has-week {
  padding: 0;
}
.qt-venue.has-week > summary {
  list-style: none; cursor: pointer;
  padding: 0.5rem 0.7rem;
}
.qt-row {
  display: flex; align-items: center; gap: 0.6rem;
}
.qt-venue .busyness-strip {
  margin: 0.4rem 0 0;
  padding: 0.25rem 0.45rem;
}
.qt-venue .bs-bars { height: 16px; }
.qt-venue .bs-bar {
  width: 6px;
  height: max(calc(var(--v, 0) * 16px), 2px);
}
.qt-venue .bs-tick { width: 6px; }
.qt-venue.has-week > summary::-webkit-details-marker { display: none; }
.qt-venue-name { color: var(--text); font-weight: 500; }
.qt-venue.empty .qt-venue-name a { color: var(--text-dim); text-decoration: none; }
.qt-venue.empty .qt-venue-name a:hover { color: var(--text); }
.qt-count {
  margin-left: auto;
  font-family: 'DM Mono', monospace;
  font-size: 0.68rem;
  color: var(--muted);
}
.qt-venue.empty .qt-count { color: var(--dimmer); }
.qt-caret {
  color: var(--dimmer); font-size: 0.7rem;
  transition: transform 0.2s;
}
.qt-venue[open] .qt-caret { transform: rotate(180deg); }
.qt-venue-body {
  padding: 0.25rem 0.7rem 0.7rem;
  border-top: 1px dashed rgba(255,255,255,0.05);
}
.qt-links {
  display: flex; gap: 0.6rem;
  font-size: 0.72rem;
  padding: 0.35rem 0 0.5rem;
}
.qt-site { color: var(--accent2); text-decoration: none; }
.qt-site:hover { color: var(--neon); }
.qt-map { color: var(--dimmer); text-decoration: none; }
.qt-map:hover { color: var(--text); }
.qt-week {
  display: flex; flex-direction: column;
  gap: 0.15rem;
  font-size: 0.78rem;
}
.qt-event {
  display: grid;
  grid-template-columns: 48px auto 1fr auto;
  align-items: center;
  gap: 0.5rem;
  padding: 0.25rem 0;
  border-top: 1px solid rgba(255,255,255,0.03);
}
.qt-event:first-child { border-top: none; }
.qt-date {
  font-family: 'DM Mono', monospace;
  font-size: 0.68rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.qt-dot { display: inline-flex; align-items: center; }
.qt-title { color: var(--text-dim); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.qt-time {
  font-family: 'DM Mono', monospace;
  font-size: 0.68rem; color: var(--muted);
  white-space: nowrap;
}

/* Venue week preview: "N ▾" toggle at the bottom right of each venue
   card, expanding to the venue's other events this week using the .qt-*
   row styles above. The TOGGLE is visible on every surface (2026-07-27;
   native-app-only before that), but expansion is still app-exclusive:
   outside the app (data-nn-app unset) tapping shows an it's-an-app-
   feature toast with a store link instead of opening the panel (app.js).
   display:contents so the toggle button and the panel participate in the
   pills flex row as independent items: the pill-shaped button holds its
   spot in the row while the hidden panel, when revealed, wraps to its
   own full-width line (flex-basis: 100%) below. This is why the toggle
   is a <button> + sibling div rather than <details>/<summary> — a
   details element cannot keep its summary on one flex line while its
   content spans another. */
.venue-week { display: contents; }
/* Toggle is a pill bubble matching .pill geometry (40px touch target)
   but keeps the muted week-preview palette so it stays secondary to the
   branded link pills. The .share-btn before it owns the pills row's
   right-alignment (margin-left:auto below is a fallback for a row with
   no share button). */
.vw-toggle {
  display: flex; align-items: center;
  width: fit-content; margin-left: auto;
  gap: 0.3rem; cursor: pointer;
  padding: 0.55rem 0.95rem; min-height: 40px;
  border-radius: 100px;
  border: 1px solid var(--border-strong);
  background: none; font: inherit; font-size: 0.8rem;
  margin-top: 0.35rem;
  transition: all 0.15s;
}
.venue-pills .vw-toggle { margin-top: 0; }
.vw-toggle:active { background: var(--card-hover); }
.vw-count {
  font-family: 'DM Mono', monospace;
  font-size: 0.78rem; color: var(--muted);
}
.vw-toggle[aria-expanded="true"] .vw-count { color: var(--text-dim); }
.vw-caret {
  color: var(--dimmer); font-size: 0.7rem;
  transition: transform 0.2s;
}
.vw-toggle[aria-expanded="true"] .vw-caret { transform: rotate(180deg); }
.vw-panel { flex-basis: 100%; }
.venue-week .qt-week { margin-top: 0.25rem; }

/* Venue share button, ALL surfaces (web + app, 2026-07-27; app-only at
   birth): right cluster of the pills row, after the link pills and before
   the week toggle so the toggle's full-width .vw-panel stays the row's
   last flex item. app.js owns the click: native share sheet when
   available, else copy to clipboard + toast. Cyan accent matches the app
   fabs: an action, not an outbound link pill. */
.share-btn {
  display: inline-flex;
  margin-left: auto;
  padding: 0.55rem 0.75rem;  /* icon-only: near-circular */
  cursor: pointer;
  font: inherit;
  color: #22d3ff;
  border-color: rgba(34,211,255,0.35);
}
.share-btn:hover, .share-btn:active { background: var(--card-hover); color: #7fe3ff; }
.share-btn svg { width: 1.05rem; height: 1.05rem; fill: currentColor; }
/* Share owns the row's right-alignment; a week toggle after it sits flush. */
.share-btn ~ .venue-week .vw-toggle { margin-left: 0; }

.no-events {
  text-align: center; color: var(--muted);
  padding: 3rem 1rem; font-size: 0.92rem;
}

/* PRICING */
.pricing-section {
  position: relative; z-index: 5;
  max-width: 820px; margin: 2.5rem auto 0;
  padding: 2rem 1.25rem 2.5rem;
  border-top: 1px solid var(--border);
}
.pricing-eyebrow {
  text-align: center;
  font-family: 'DM Mono', monospace;
  font-size: 0.62rem; letter-spacing: 0.2em;
  color: var(--dimmer); text-transform: uppercase;
  margin-bottom: 0.4rem;
}
.pricing-header h2 {
  text-align: center;
  font-family: 'Bebas Neue', sans-serif;
  font-size: 1.6rem; letter-spacing: 0.04em;
  color: var(--text); font-weight: 400;
  margin-bottom: 0.4rem;
}
.pricing-header p {
  text-align: center;
  font-size: 0.82rem; color: var(--muted);
  max-width: 480px; margin: 0 auto 1.5rem;
}
.pricing-grid {
  display: grid; grid-template-columns: repeat(2,1fr); gap: 0.7rem;
  max-width: 520px; margin: 0 auto 1.2rem;
}
.pricing-card {
  background: var(--card); border: 1px solid var(--border);
  border-radius: 12px; padding: 1.1rem 1rem;
  text-align: center;
}
.pricing-card.premier-pricing { border-color: rgba(212,175,55,0.3); }
.pricing-card.featured-pricing { border-color: rgba(74,123,196,0.3); }
.pricing-tier {
  font-family: 'DM Mono', monospace;
  font-size: 0.6rem; letter-spacing: 0.16em;
  text-transform: uppercase; margin-bottom: 0.5rem;
}
.pricing-card.premier-pricing .pricing-tier { color: var(--gold); }
.pricing-card.featured-pricing .pricing-tier { color: var(--accent2); }
.pricing-price { font-family: 'Bebas Neue', sans-serif; font-size: 1.9rem; color: #fff; line-height: 1; }
.pricing-period { font-family: 'DM Mono', monospace; font-size: 0.58rem; color: var(--dimmer); letter-spacing: 0.1em; margin-bottom: 0.7rem; }
.pricing-features { list-style: none; font-size: 0.74rem; color: var(--muted); text-align: left; line-height: 1.75; }
.pricing-features li::before { content: '→ '; color: var(--dimmer); }
.pricing-slots {
  margin-top: 0.75rem;
  font-family: 'DM Mono', monospace;
  font-size: 0.6rem;
  letter-spacing: 0.1em;
  padding: 0.3rem 0.6rem;
  border-radius: 100px;
  display: inline-block;
}
.pricing-card.premier-pricing .pricing-slots {
  color: var(--gold);
  border: 1px solid rgba(212,175,55,0.25);
  background: rgba(212,175,55,0.05);
}
.pricing-card.featured-pricing .pricing-slots {
  color: var(--accent2);
  border: 1px solid rgba(74,123,196,0.25);
  background: rgba(74,123,196,0.05);
}
.pricing-cta-wrap { text-align: center; }
.pricing-cta {
  display: inline-block;
  padding: 0.55rem 1.6rem;
  border-radius: 100px;
  font-size: 0.82rem; font-weight: 600;
  text-decoration: none; color: #fff;
  background: var(--accent); border: 1px solid rgba(74,123,196,0.5);
  transition: all 0.15s;
}
.pricing-cta:hover { background: var(--accent2); transform: translateY(-1px); }
.pricing-note { text-align: center; font-size: 0.72rem; color: var(--dimmer); margin-top: 0.8rem; line-height: 1.5; }

footer {
  text-align: center; color: var(--dimmer);
  font-size: 0.72rem; padding: 1.5rem 1rem 2.5rem;
  font-family: 'DM Mono', monospace; letter-spacing: 0.08em;
}
footer a { color: var(--muted); text-decoration: none; }
footer a:hover { color: var(--text); }

.staging-banner {
  /* bottom-left so it never overlaps the bottom-right .settings-fab in-app */
  position: fixed; bottom: 1rem; left: 1rem;
  background: rgba(239,68,68,0.15);
  border: 1px solid rgba(239,68,68,0.5);
  color: #fca5a5;
  font-family: 'DM Mono', monospace;
  font-size: 0.68rem; letter-spacing: 0.14em;
  padding: 0.45rem 0.8rem; border-radius: 100px;
  text-transform: uppercase;
  z-index: 100;
  backdrop-filter: blur(6px);
}

@media (max-width: 640px) {
  .header-inner { padding: 0.5rem 1rem; }
  .wordmark { font-size: 1.55rem; }
  .tagline { display: none; }
  .logo-seo { font-size: 0.62rem; max-width: 230px; }
  .day-label { font-size: 1.9rem; }
  .event-type { width: 48px; font-size: 0.54rem; }
  .event-title { font-size: 0.86rem; }
  .event-time { font-size: 0.66rem; }
  .qt-sub { display: none; }

  /* Day header: redundant weather box hidden on mobile (already in top bar) */
  .day-weather { display: none; }

  /* Unified left/right rail = 16px across header, day-nav, filters, main, announce strip */
  main { padding: 0.6rem 1rem 3rem; }
  .day-nav { padding: 0.4rem 1rem; scroll-padding-inline-start: 1rem; }
  .announce-lead { padding: 0 0.5rem 0 1rem; }

  /* Filter pills: fit all 5 on one row at 360w, distributed across width */
  .filters { gap: 0.25rem; padding: 0.4rem 1rem 0.2rem; justify-content: space-between; }
  .filter-pill {
    min-height: 36px;
    padding: 0.35rem 0.55rem;
    font-size: 0.7rem;
    gap: 0.3rem;
  }

  /* Venue-card action pills — slightly smaller but still tappable */
  .pill {
    min-height: 36px;
    padding: 0.4rem 0.7rem;
    font-size: 0.74rem;
  }
  /* Week-preview toggle and icon-only bubbles (IG, share) shrink with the
     pills so a LineLeap + IG + Map + share + count row stays on one line
     on phone widths. Extra specificity so these beat the base .pill.ig /
     app-gated .share-btn padding. */
  .vw-toggle {
    min-height: 36px;
    padding: 0.4rem 0.7rem;
  }
  .vw-toggle .vw-count { font-size: 0.7rem; }
  .pill.pill.ig, .pill.pill.lineleap, .pill.pill.share-btn { padding: 0.4rem 0.55rem; }
}
/* Narrow phones (360dp Galaxys etc.): the full 5-item row (LineLeap + IG +
   Map + share + week toggle) needs a few more px than the ≤640 sizes give.
   Same touch-target min-heights, tighter chrome. */
@media (max-width: 400px) {
  .venue-pills { gap: 0.25rem; }
  .pill { padding: 0.35rem 0.5rem; font-size: 0.7rem; }
  .pill.pill.ig, .pill.pill.lineleap, .pill.pill.share-btn { padding: 0.35rem 0.45rem; }
  .vw-toggle { padding: 0.35rem 0.5rem; }
}
@keyframes iosArrowBounce {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(10px); }
}

/* PRESENTER SPONSOR — day-header "Brought to you by" + mid-list strip.
   Only emitted when an active row exists in sponsorships.md ## Presenter Sponsors. */
.day-header.has-presenter {
  display: grid !important;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  column-gap: 1rem;
  margin: 0.2rem 0 calc(0.5rem + 4px);
}
.day-presenter {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  line-height: 1.15;
  min-width: 0;
}
.dp-eyebrow {
  font-family: 'DM Mono', monospace;
  font-size: 0.5rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--dimmer);
  margin-bottom: 2px;
}
.dp-name {
  font-family: 'Fraunces', serif;
  font-style: italic;
  font-weight: 400;
  font-size: 1.2rem;
  color: rgba(229,200,120,0.92);
  text-decoration: none;
  letter-spacing: 0.005em;
  transition: color 0.15s;
}
.dp-name:hover { color: #f5e9c8; text-decoration: underline; }
@media (max-width: 560px) {
  .day-header.has-presenter { column-gap: 0.5rem; grid-template-columns: auto 1fr; }
  .day-header.has-presenter .day-weather { display: none; }
  .dp-eyebrow { font-size: 0.4rem; letter-spacing: 0.14em; }
  .dp-name { font-size: 0.95rem; line-height: 1.15; }
}
@media (max-width: 380px) {
  .dp-eyebrow { font-size: 0.36rem; letter-spacing: 0.12em; }
  .dp-name { font-size: 0.85rem; }
}

.whiskey-sponsor {
  position: relative;
  display: block;
  margin: 0.4rem 0 1.4rem;
  padding: 0.75rem 1rem 0.85rem;
  border-radius: 14px;
  background: #1a130a;
  border: 1px solid rgba(212,175,55,0.22);
  box-shadow:
    inset 0 1px 0 rgba(255,235,180,0.06),
    0 6px 22px rgba(0,0,0,0.35);
  text-decoration: none;
  color: var(--text);
  overflow: visible;
  transition: border-color 0.25s, box-shadow 0.25s, transform 0.25s;
}
.whiskey-sponsor::before {
  content: "";
  position: absolute; top: 0; left: 12px; right: 12px;
  height: 1px;
  background: linear-gradient(90deg,
    transparent 0%, rgba(212,175,55,0.0) 4%,
    rgba(212,175,55,0.55) 30%, rgba(229,200,120,0.85) 50%,
    rgba(212,175,55,0.55) 70%, rgba(212,175,55,0.0) 96%, transparent 100%);
  opacity: 0.9;
}
.whiskey-sponsor:hover {
  border-color: rgba(229,200,120,0.55);
  box-shadow:
    inset 0 1px 0 rgba(255,235,180,0.10),
    0 10px 36px rgba(212,175,55,0.18),
    0 6px 22px rgba(0,0,0,0.45);
  transform: translateY(-1px);
}
.whiskey-tag-corner {
  position: absolute;
  bottom: -7px;
  left: 50%;
  transform: translateX(-50%);
  font-family: 'DM Mono', monospace;
  background: var(--bg);
  padding: 2px 10px;
  letter-spacing: 0.28em;
  font-size: 0.44rem;
  text-transform: uppercase;
  border: 1px solid rgba(229,200,120,0.4);
  border-radius: 3px;
  color: rgba(229,200,120,0.78);
  pointer-events: none;
  z-index: 3;
}
.whiskey-row { display: flex; align-items: center; gap: 0.95rem; }
.whiskey-logo {
  flex: 0 0 auto;
  height: 46px;
  width: auto;
  filter: drop-shadow(0 1px 6px rgba(212,175,55,0.18));
}
.whiskey-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 0.1rem; }
.whiskey-tag {
  font-family: 'Fraunces', 'DM Sans', serif;
  font-style: italic;
  font-weight: 400;
  font-size: 1.18rem;
  line-height: 1.1;
  letter-spacing: -0.005em;
  color: #f5e9c8;
  text-shadow: 0 1px 0 rgba(0,0,0,0.4);
}
.whiskey-sub {
  font-family: 'DM Mono', monospace;
  font-size: 0.62rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(229,200,120,0.65);
}
.whiskey-cta {
  flex: 0 0 auto;
  font-family: 'DM Mono', monospace;
  font-size: 0.66rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #f5e9c8;
  padding: 0.42rem 0.7rem;
  border: 1px solid rgba(229,200,120,0.45);
  border-radius: 999px;
  white-space: nowrap;
  transition: background 0.2s, border-color 0.2s, color 0.2s;
}
.whiskey-sponsor:hover .whiskey-cta {
  background: rgba(229,200,120,0.12);
  border-color: rgba(229,200,120,0.85);
  color: #fff7e0;
}
@media (max-width: 480px) {
  .whiskey-row { gap: 0.7rem; }
  .whiskey-logo { height: 36px; }
  .whiskey-tag { font-size: 1.02rem; }
  .whiskey-sub { font-size: 0.56rem; letter-spacing: 0.14em; }
  .whiskey-cta { font-size: 0.58rem; padding: 0.36rem 0.6rem; }
}
/* end presenter sponsor */

.app-only { display: none; }
html[data-nn-app="true"] .app-only { display: inline; }
@media (display-mode: standalone) { .app-only { display: inline; } }

/* Inverse of .app-only: visible in ordinary browser tabs, hidden inside the
   native app and installed PWAs (where advertising the app is pointless).
   !important so the gate wins over any element-specific display rule. */
html[data-nn-app="true"] .browser-only { display: none !important; }
@media (display-mode: standalone) { .browser-only { display: none !important; } }

/* Footer store badges (browser-only): the official "Download on the App
   Store" and "Get it on Google Play" badge art (data-URI SVGs in the
   template; sources in tools/badges/). Same aspect ratio, so equal heights
   render as a uniform pair; the row wraps on narrow phones. */
.play-badge-row {
  margin: 14px 0 0;
  display: flex; justify-content: center; align-items: center;
  gap: 10px; flex-wrap: wrap;
}
.play-badge-row a { display: block; line-height: 0; }
.play-badge-row img { height: 44px; width: auto; display: block; }

/* App-only floating Settings button. Hidden in normal browser tabs (where
   push/settings aren't relevant), shown in the installed app / standalone PWA
   — mirrors the .app-only gating above but needs display:flex for centering. */
.settings-fab {
  display: none;
  position: fixed;
  bottom: calc(1rem + env(safe-area-inset-bottom));
  right: calc(1rem + env(safe-area-inset-right));
  width: 3rem; height: 3rem;
  align-items: center; justify-content: center;
  border-radius: 100px;
  background: var(--card);
  border: 1px solid rgba(34,211,255,0.35);
  color: #22d3ff;
  text-decoration: none;
  box-shadow: 0 4px 16px rgba(0,0,0,0.45), 0 0 12px rgba(34,211,255,0.12);
  backdrop-filter: blur(6px);
  z-index: 90;
  transition: transform 0.15s, box-shadow 0.15s;
}
.settings-fab:hover, .settings-fab:active {
  transform: scale(1.05);
  box-shadow: 0 6px 20px rgba(0,0,0,0.55), 0 0 16px rgba(34,211,255,0.25);
}
/* The Material bell path spans y=2.5–22 in its 24x24 viewBox (center ≈12.25),
   close enough to true center that no nudge is needed. */
.settings-fab svg { width: 1.4rem; height: 1.4rem; fill: currentColor; }
html[data-nn-app="true"] .settings-fab { display: flex; }
@media (display-mode: standalone) { .settings-fab { display: flex; } }

/* Transient toast (share button's clipboard fallback; week-preview app
   teaser). Bottom-center, above the fab z-index. Non-interactive by
   default; .tappable (set by app.js when the content carries a link)
   re-enables pointer events so the store link can be tapped. */
.nn-toast {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  bottom: calc(4.75rem + env(safe-area-inset-bottom));
  background: var(--card);
  color: var(--text);
  border: 1px solid rgba(34,211,255,0.35);
  border-radius: 100px;
  padding: 0.6rem 1.1rem;
  font-size: 0.85rem;
  box-shadow: 0 4px 16px rgba(0,0,0,0.45);
  z-index: 95;
  opacity: 0;
  transition: opacity 0.25s;
  pointer-events: none;
}
.nn-toast.show { opacity: 1; }
.nn-toast.tappable { pointer-events: auto; }
.nn-toast a { color: #22d3ff; font-weight: 600; }

/* App-only find-in-page. The circular find button mirrors .settings-fab and
   sits directly above it (1rem edge + 3rem bell + 0.75rem gap). Gated on
   data-nn-find, which app.js sets only when CSS.highlights is available, in
   addition to the same app/standalone gating as the settings bell. */
.find-fab {
  display: none;
  position: fixed;
  bottom: calc(1rem + 3rem + 0.75rem + env(safe-area-inset-bottom));
  right: calc(1rem + env(safe-area-inset-right));
  width: 3rem; height: 3rem;
  align-items: center; justify-content: center;
  border-radius: 100px;
  background: var(--card);
  border: 1px solid rgba(34,211,255,0.35);
  color: #22d3ff;
  cursor: pointer;
  padding: 0;
  box-shadow: 0 4px 16px rgba(0,0,0,0.45), 0 0 12px rgba(34,211,255,0.12);
  backdrop-filter: blur(6px);
  z-index: 90;
  transition: transform 0.15s, box-shadow 0.15s;
}
.find-fab:hover, .find-fab:active {
  transform: scale(1.05);
  box-shadow: 0 6px 20px rgba(0,0,0,0.55), 0 0 16px rgba(34,211,255,0.25);
}
.find-fab svg { width: 1.4rem; height: 1.4rem; fill: currentColor; }
html[data-nn-app="true"][data-nn-find="true"] .find-fab { display: flex; }
@media (display-mode: standalone) { html[data-nn-find="true"] .find-fab { display: flex; } }

/* Chrome-style find bar, pinned top center. Above the sticky day-nav (20)
   and the fabs (90), below the pull-to-refresh spinner. */
.find-bar {
  display: none;
  position: fixed;
  top: calc(0.5rem + env(safe-area-inset-top));
  left: 50%;
  transform: translateX(-50%);
  width: min(26rem, calc(100vw - 1rem));
  align-items: center;
  gap: 0.15rem;
  padding: 0.35rem 0.5rem;
  border-radius: 12px;
  background: var(--card);
  border: 1px solid rgba(34,211,255,0.35);
  box-shadow: 0 4px 16px rgba(0,0,0,0.45), 0 0 12px rgba(34,211,255,0.12);
  backdrop-filter: blur(6px);
  z-index: 95;
}
.find-bar.open { display: flex; }
.find-input {
  flex: 1;
  min-width: 0;
  background: transparent;
  border: 0;
  outline: none;
  color: var(--text);
  /* 16px floor: smaller inputs make iOS zoom the page on focus */
  font-size: 16px;
  padding: 0.25rem 0.35rem;
}
.find-input::placeholder { color: var(--dimmer); }
/* Hide the WebKit/Blink built-in clear button; the bar has its own ✕ */
.find-input::-webkit-search-cancel-button { display: none; }
.find-count {
  font-size: 0.72rem;
  color: var(--text-dim);
  min-width: 2.6rem;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.find-bar button {
  display: flex; align-items: center; justify-content: center;
  width: 2.1rem; height: 2.1rem;
  background: transparent;
  border: 0;
  border-radius: 8px;
  color: #22d3ff;
  cursor: pointer;
  padding: 0;
}
.find-bar button:disabled { opacity: 0.35; cursor: default; }
.find-bar button svg { width: 1.3rem; height: 1.3rem; fill: currentColor; }

/* Match highlights (CSS Custom Highlight API): all matches translucent cyan,
   the current one gold with dark text — Chrome's yellow/orange pattern in
   site colors. */
::highlight(nn-find) { background-color: rgba(34,211,255,0.35); }
::highlight(nn-find-current) { background-color: #d4af37; color: #070a12; }

/* Push notification CTA state machine */
/* Push CTA row: PWA-only by default. The whole row is hidden in regular
   browser tabs; only inside an installed PWA (display-mode: standalone) or
   in iOS Safari (where we surface the Settings link) does anything appear. */
.nn-push-row { display: none; }
@media (display-mode: standalone) { .nn-push-row { display: block; } }
html[data-nn-ios-web="true"] .nn-push-row { display: block; }
.nn-push-cta { display: none; }
html[data-nn-push="unprompted"] .nn-push-cta { display: inline-block; }
.nn-push-cta-on, .nn-push-cta-blocked { display: none; }
html[data-nn-push="on"] .nn-push-cta-on { display: inline-block; }

/* --- Fixed-event guide card (Arts Fest, etc.) --- */
.venue-card.guide {
  border: 1px solid rgba(34, 211, 255, 0.55);
  box-shadow: 0 0 0 1px rgba(34, 211, 255, 0.25), 0 8px 30px rgba(34, 211, 255, 0.12);
  background: linear-gradient(180deg, rgba(34, 211, 255, 0.06), rgba(7, 10, 18, 0));
}
/* When live, guide cards keep their cyan border (this .venue-card.guide rule
   out-orders .venue-card.live-now); only the Live Now pill and the row-level
   green time/title states apply. Intentional — do not add a green override. */
/* Cyan tab on the card's top border line — same treatment as the sponsor
   badges on venue cards (inherits the absolute positioning, size, and spacing
   from the base .badge), so the title sits with normal venue spacing below. */
.badge.guide {
  color: #22d3ff;
  border: 1px solid rgba(34, 211, 255, 0.5);
}
.guide-blurb {
  margin: 2px 0 10px;
  color: rgba(230, 240, 255, 0.78);
  font-size: 0.9rem;
}
.guide-teaser {
  margin-top: 4px;
  color: rgba(230, 240, 255, 0.92);
  font-size: 0.95rem;
  line-height: 1.4;
}
/* Small "Map" bubble that sits next to the guide title in the header. */
.guide-map-link {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  align-self: center;
  margin-left: auto;   /* right-justify the bubble in the header row */
  padding: 2px 9px;
  border-radius: 999px;
  background: rgba(34, 211, 255, 0.16);
  border: 1px solid rgba(34, 211, 255, 0.4);
  color: #eaf6fb;
  font-size: 0.72rem;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  line-height: 1.4;
}
.guide-map-link:hover { background: rgba(34, 211, 255, 0.30); }
/* Location sits on its own line under the event title, left-aligned and
   wrapping — never clipped, unlike the right-hand time column. */
.guide-loc {
  display: block;
  margin-top: 0.12rem;
  font-size: 0.72rem;
  line-height: 1.3;
  color: rgba(230, 240, 255, 0.6);
  white-space: normal;
}

html[data-nn-push="blocked"] .nn-push-cta-blocked { display: inline-block; }

/* Neighborhood badge filter (colors are inline per label, set server-side) */
.hood-badge { cursor: pointer; user-select: none; -webkit-user-select: none; }
.hood-badge.hood-active { box-shadow: 0 0 0 1.5px currentColor; }
.venue-card.hood-hidden { display: none !important; }
