:root {
  /* Clear Sky palette — modern, clean, calm. Body is near-white so the
     eye has a neutral place to rest on phone. Sky-blue lives in the
     header band + accents only; yellow is the sun + CTA highlight. */
  --bg:        #F6F8FB;            /* off-white — barely warm, calm base */
  --bg-2:      #EEF2F7;

  --panel:        #FFFFFF;          /* solid white cards */
  --panel-2:      #F6F9FC;
  --panel-3:      #EDF2F8;
  --border:        #E1E6EF;          /* neutral grey — for subtle separators */
  --border-strong: #B5C0CE;          /* stronger — for card outlines on near-white */

  --text:      #1A2233;            /* near-black slate — full contrast */
  --muted:     #4D5A6E;            /* slate body */
  --muted-dim: #7A8898;

  --accent:        #F4B82A;        /* warm sun yellow — primary CTA */
  --accent-soft:   #FFE8A3;
  --accent-deep:   #D89A0F;        /* yellow hover/active */
  --accent-2:      #2E84BD;        /* sky-blue deep — links / dates */
  --accent-2-soft: #BFDBF0;
  --accent-3:      #1F8F5E;        /* leaf-green — family / saved */
  --accent-3-soft: #C9E8D8;
  --accent-4:      #C73B7A;        /* magenta — kids accent */
  --danger:        #C63A3A;
  --pill:          #F2F7FC;
  --pill-strong:   #E2ECF6;

  --sun:     #FFCE3D;
  --sun-hot: #F4B82A;
  --sky:     #4FA4D2;

  /* Per-category colour system. Each event card receives --cat-color
     based on its data-cat attribute; the pill outline + left-stripe pick
     it up. Tuned for AA contrast against white pill backgrounds. */
  --cat-kids:       #C73B7A;
  --cat-music:      #2E84BD;
  --cat-theatre:    #7846C2;
  --cat-comedy:     #C97A0E;
  --cat-exhibition: #9446BD;
  --cat-workshop:   #1F8F5E;
  --cat-talk:       #5C6E88;
  --cat-market:     #C86519;
  --cat-food:       #C24524;
  --cat-outdoor:    #157F73;
  --cat-sport:      #2670B8;
  --cat-festival:   #C97A0E;
  --cat-community:  #3F62B8;
  --cat-tour:       #1A809A;
  --cat-cinema:     #6840BD;
  --cat-other:      #5C6E88;
  --shadow-soft: 0 1px 2px rgba(20, 35, 60, 0.06), 0 4px 12px rgba(20, 35, 60, 0.08);
  --shadow-card: 0 1px 2px rgba(20, 35, 60, 0.07), 0 6px 20px rgba(20, 35, 60, 0.10);
  --gradient-header: linear-gradient(180deg, #4FA4D2 0%, #6CB4E2 100%);
  --gradient-card: #FFFFFF;
  --gradient-accent: linear-gradient(135deg, #FFD64A 0%, #F4B82A 100%);
  --gradient-warm:   linear-gradient(135deg, #FFD64A 0%, #F4B82A 100%);
  --gradient-sky:    linear-gradient(135deg, #6CB4E2 0%, #4FA4D2 100%);
  --ring: 0 0 0 3px rgba(244, 184, 42, 0.40);
  --radius-sm: 8px;
  --radius: 12px;
  --radius-lg: 16px;
}

/* ===== Dark mode — "midnight sky" navy. Opt-in via data-theme="dark" on the
   <html> element (persisted in localStorage; first visit honours the OS
   setting). ONLY the neutrals flip — the sun-yellow + sky-blue accents stay so
   the brand stays unmistakable. Surface whites in the CSS below were routed to
   var(--panel), so redefining the vars here is all it takes. ===== */
[data-theme="dark"] {
  --bg:        #0F1E2A;            /* midnight sky-navy */
  --bg-2:      #0B1721;

  --panel:        #182C3B;         /* lifted card surface */
  --panel-2:      #142534;
  --panel-3:      #1E3646;
  --border:        #294256;
  --border-strong: #3B5A73;

  --text:      #E6EDF3;            /* soft off-white — never pure white */
  --muted:     #AEBECE;
  --muted-dim: #8194A6;

  --accent-soft:   #3A2F14;        /* dark amber tint for yellow highlights */
  --accent-2:      #6BB6E8;        /* brighter sky — links / dates on dark */
  --accent-2-soft: #17384F;        /* dark blue chip (e.g. count pills) */
  --accent-3:      #3DBE87;        /* brighter leaf-green */
  --accent-3-soft: #14342A;
  --accent-4:      #E86AA3;        /* brighter magenta */
  --pill:          #142534;
  --pill-strong:   #1E3646;

  /* Category colours re-tuned to read on dark card pills. */
  --cat-kids:       #E86AA3;
  --cat-music:      #6BB6E8;
  --cat-theatre:    #A98AE6;
  --cat-comedy:     #E8B25A;
  --cat-exhibition: #C88AE6;
  --cat-workshop:   #4CC891;
  --cat-talk:       #9DB0C8;
  --cat-market:     #E89A5A;
  --cat-food:       #E8825A;
  --cat-outdoor:    #46C2B0;
  --cat-sport:      #6BB0E8;
  --cat-festival:   #E8B25A;
  --cat-community:  #7E9CE8;
  --cat-tour:       #4CC0D8;
  --cat-cinema:     #A986E6;
  --cat-other:      #9DB0C8;

  --gradient-card: #182C3B;
  --shadow-soft: 0 1px 2px rgba(0,0,0,0.35), 0 4px 14px rgba(0,0,0,0.40);
  --shadow-card: 0 1px 2px rgba(0,0,0,0.40), 0 8px 24px rgba(0,0,0,0.50);
  --ring: 0 0 0 3px rgba(107, 182, 232, 0.40);
  color-scheme: dark;
}
/* Dark-mode touch-ups for the few spots that hardcode a colour we can't route
   through a variable (literal-coloured text that would go low-contrast). */
/* Header band drops the sky-blue in dark mode and matches the body, so the top
   of the app doesn't read as a bright blue slab at night. The border-bottom
   (var(--border)) keeps a subtle line between header and content. */
[data-theme="dark"] header { background: var(--bg); }
[data-theme="dark"] .event .pill.estate { color: #A986E6; }
[data-theme="dark"] .route-clear,
[data-theme="dark"] .route-setoff button,
[data-theme="dark"] .route-title { color: var(--accent-2); }
/* The two filled buttons keep their white text — the rule above would grey them out. */
[data-theme="dark"] .route-setoff .rs-start:not(.set) { color: #fff; }
[data-theme="dark"] .route-setoff .rs-tidy { color: #F08CBB; }
/* Weather bar stays deliberately WARM — but a dark warm amber, not glaring
   cream. Keeps the "never grey, never apologetic" intent in dark mode. */
[data-theme="dark"] .weather-bar {
  background: linear-gradient(180deg, #241C0B, #1C1607);
  border-color: color-mix(in srgb, var(--sun-hot) 40%, transparent);
  box-shadow: 0 3px 12px rgba(0,0,0,0.40);
}
[data-theme="dark"] .weather-bar .wx { background: rgba(255,255,255,0.06); color: #F0C978; }
[data-theme="dark"] .weather-bar .wx:hover { background: rgba(255,255,255,0.12); }
[data-theme="dark"] .weather-bar .wx[data-weather="all"][aria-pressed="true"] { color: #FFD98A; }
[data-theme="dark"] .weather-bar .wx[data-weather="sunny"][aria-pressed="true"] {
  color: #FFD98A; background: linear-gradient(180deg, #33280D, #29200A);
}
[data-theme="dark"] .weather-bar .wx[data-weather="rainy"][aria-pressed="true"] {
  color: #9AD0F0; background: linear-gradient(180deg, #102A3B, #0C2231);
}
/* Status chips: light tints → dark tints so they don't glare. */
[data-theme="dark"] .digest-dialog .status.error { background: #3A1712; color: #F0A88E; }
[data-theme="dark"] .digest-dialog .status.success { background: #12331F; color: #8FD9AE; }
/* Modebar (Events/Classes/Places) stays exactly as it looks in LIGHT mode — the
   top banner is kept consistent across themes on purpose. Re-scoping the vars it
   uses back to their light values makes the whole bar (and its active pills)
   render identically without touching each rule. */
[data-theme="dark"] .modebar {
  --bg-2: #EEF2F7;
  --border-strong: #B5C0CE;
  --muted: #4D5A6E;
  --text: #1A2233;
}
/* Bottom promo cards — keep the coloured border identity but darken the fill so
   they stop glaring, and keep text on the yellow buttons dark for contrast. */
[data-theme="dark"] .guides-card {
  background:
    radial-gradient(circle at 0% 0%, rgba(79,164,210,0.22), transparent 55%),
    radial-gradient(circle at 100% 100%, rgba(244,184,42,0.12), transparent 50%),
    #142838;
  border-color: #2E84BD;
}
[data-theme="dark"] .digest-card {
  background:
    radial-gradient(circle at 100% 0%, rgba(244,184,42,0.20), transparent 55%),
    radial-gradient(circle at 0% 100%, rgba(74,158,212,0.12), transparent 50%),
    #241C0B;
  border-color: var(--accent);
}
[data-theme="dark"] .digest-card-cta,
[data-theme="dark"] .digest-card-kicker { color: #1A2233; }

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; overflow-x: hidden; }
body {
  font: 15.5px/1.55 -apple-system, BlinkMacSystemFont, "Inter", "SF Pro Text", "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  background: var(--bg);
  color: var(--text);
  min-height: 100vh;
  font-variant-numeric: tabular-nums;
  /* Page chrome scrolls, it never zooms. `manipulation` kills the double-tap
     zoom (and its 300ms tap delay) everywhere in the shell; the map keeps its
     own pinch-zoom because MapLibre drives that from touch events on its
     canvas, not from browser gestures. See lockPageZoom() in app.js. */
  touch-action: manipulation;
}
::selection { background: rgba(244, 184, 42, 0.32); color: var(--text); }
a { color: var(--accent); }
.wrap { max-width: 1120px; margin: 0 auto; padding: 0 22px; }

header {
  /* Deeper sky-blue band — gives the top some colour weight against the
     near-white body. Single solid tone (no peach/pink), strong enough to
     read as "the brand band" but calm enough not to distract. */
  background: linear-gradient(180deg, #2F7FB6 0%, #2E84BD 100%);
  padding: 16px 0 12px;
  border-bottom: 1px solid var(--border);
  position: relative;
}
header .headerrow {
  position: relative;
  display: block;
  text-align: center;
}
header h1 {
  margin: 0; font-size: 22px; font-weight: 800;
  letter-spacing: -0.015em; line-height: 1.1;
  color: #FFFFFF;
  text-align: center;
}
header .region {
  color: var(--sun);
  font-weight: 700;
}
header .tagline { display: none; }
header .cta {
  background: var(--accent); color: var(--text);
  border: 0; padding: 0; border-radius: 50%;
  width: 40px; height: 40px;
  font-size: 22px; font-weight: 600; cursor: pointer;
  font-family: inherit;
  box-shadow: 0 2px 6px rgba(212, 154, 15, 0.30);
  display: inline-flex; align-items: center; justify-content: center;
}
header .cta:hover { background: #FFCB4F; }
header .cta.secondary { background: rgba(255,255,255,0.95); color: var(--accent-2); border: 1px solid rgba(255,255,255,0.7); }
header .cta.secondary:hover { border-color: #fff; }
header .cta.icon-only {
  width: 40px; height: 40px; padding: 0;
  font-size: 24px; line-height: 1; font-weight: 400;
  border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
}
/* QR / share button — sits in the top-right of the blue header band,
   opposite the centred title. Sun-yellow round icon so it reads as the
   one tappable thing up there without crowding the wordmark. */
.share-app-btn {
  position: absolute; right: 22px; top: 50%;
  transform: translateY(-50%);
}
.share-app-btn:active { transform: translateY(-50%) scale(0.94); }
.share-app-btn svg { display: block; }
/* Dark-mode toggle — sits just left of the share button in the header band.
   Translucent white circle so it reads as a utility control, distinct from
   the sun-yellow share button. Emoji icon swaps 🌙/☀️ in JS. */
/* The toggle stays a sun-yellow circle in BOTH themes (mirrors the share button
   on the right); only the icon swaps — moon in light, sun in dark. The icon is
   pinned dark so it always reads crisp on the yellow, in either theme. */
header .cta.theme-toggle-btn {
  position: absolute; left: 22px; top: 50%;
  transform: translateY(-50%);
  font-size: 20px;
  color: #1A2233;
}
header .cta.theme-toggle-btn svg { display: block; }
header .cta.theme-toggle-btn:active { transform: translateY(-50%) scale(0.94); }

.poster-dialog {
  max-width: 520px; width: 92%;
  background: var(--gradient-card); color: var(--text);
  border: 1px solid var(--border-strong); border-radius: var(--radius-lg);
  padding: 26px; box-shadow: 0 40px 100px rgba(0,0,0,0.75);
}
.poster-dialog::backdrop { background: rgba(40, 30, 80, 0.42); backdrop-filter: blur(6px); }
.poster-dialog h2 { margin: 0 0 6px; font-size: 18px; }
.poster-dialog .dialog-sub { color: var(--muted); font-size: 13px; margin: 0 0 16px; }
.dropzone {
  display: flex; align-items: center; justify-content: center;
  min-height: 200px; padding: 20px;
  background: var(--panel-2); border: 2px dashed var(--border); border-radius: 10px;
  cursor: pointer; text-align: center; color: var(--muted);
  transition: border-color .15s, background .15s;
}
.dropzone:hover, .dropzone.drag { border-color: var(--accent); background: rgba(255, 220, 170, 0.45); }
.dropzone .dropicon { font-size: 36px; margin-bottom: 8px; }
.dropzone img { max-width: 100%; max-height: 280px; border-radius: 6px; }
.status { margin: 14px 0 0; padding: 10px 12px; border-radius: 8px; font-size: 13px; }
.status.info { background: rgba(74, 158, 212, 0.14); color: #1F5E8A; border: 1px solid rgba(74, 158, 212, 0.32); }
.status.error { background: rgba(212, 58, 58, 0.10); color: #8A1F1F; border: 1px solid rgba(212, 58, 58, 0.30); }
.status.success { background: rgba(46, 157, 107, 0.14); color: #1F6E4A; border: 1px solid rgba(46, 157, 107, 0.30); }
.result { margin: 14px 0 0; padding: 12px; background: var(--panel-2); border: 1px solid var(--border); border-radius: 8px; font-size: 13px; }
.result h3 { margin: 0 0 6px; font-size: 15px; color: var(--text); }
.result .row { display: flex; gap: 6px; margin-top: 4px; color: var(--muted); }
.result .row strong { color: var(--text); min-width: 70px; }
.dialog-buttons { display: flex; gap: 8px; justify-content: flex-end; margin-top: 18px; }
.dialog-buttons button {
  background: var(--panel-2); color: var(--text); border: 1px solid var(--border);
  padding: 9px 18px; border-radius: var(--radius-sm); cursor: pointer; font-family: inherit; font-size: 14px;
  font-weight: 500; transition: all .15s;
}
.dialog-buttons button.primary { background: var(--gradient-accent); color: #051d2b; border-color: transparent; font-weight: 600; }
.dialog-buttons button.primary:hover:not(:disabled) { filter: brightness(1.05); transform: translateY(-1px); }
.dialog-buttons button.primary:disabled { opacity: 0.4; cursor: not-allowed; }
.dialog-buttons button:not(.primary):hover { border-color: var(--accent); color: var(--accent); }

/* Hero stats strip — Today + Tomorrow get big feature tiles */
.herostrip {
  padding: 22px 0 14px;
  background: linear-gradient(180deg, var(--bg) 0%, var(--bg-2) 100%);
  border-bottom: 1px solid var(--border);
}
.tiles {
  display: grid;
  grid-template-columns: 1fr 1fr 0.75fr;
  gap: 12px;
  align-items: stretch;
}

.feature-tile {
  background: var(--gradient-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 18px 20px 16px;
  text-align: left;
  cursor: pointer;
  font-family: inherit;
  color: var(--text);
  position: relative;
  overflow: hidden;
  transition: transform .18s, border-color .18s, box-shadow .18s;
  display: flex; flex-direction: column; gap: 10px;
  min-height: 180px;
}
.feature-tile::before {
  content: ''; position: absolute; inset: 0;
  background: radial-gradient(360px 220px at 95% -10%, var(--feature-glow, transparent), transparent 65%);
  pointer-events: none;
}
.feature-tile:hover { transform: translateY(-2px); border-color: var(--feature-border, var(--border-strong)); box-shadow: var(--shadow-card); }

.feature-today    { --feature-glow: rgba(245,196,107,0.28); --feature-border: color-mix(in srgb, var(--accent-2) 55%, var(--border)); }
.feature-tomorrow { --feature-glow: rgba(95,209,255,0.24);  --feature-border: color-mix(in srgb, var(--accent) 50%, var(--border)); }

.feature-head {
  display: flex; align-items: baseline; gap: 10px;
  position: relative;
}
.feature-label {
  font-size: 12px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.12em;
  color: var(--muted);
}
.feature-today .feature-label { color: var(--accent-2); }
.feature-tomorrow .feature-label { color: var(--accent); }
.feature-count {
  font-size: 42px; font-weight: 800;
  line-height: 1; letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  margin-left: auto;
}
.feature-today .feature-count { background: var(--gradient-warm); -webkit-background-clip: text; background-clip: text; color: transparent; }
.feature-tomorrow .feature-count { background: var(--gradient-accent); -webkit-background-clip: text; background-clip: text; color: transparent; }
.feature-date {
  font-size: 13px; color: var(--muted); font-weight: 500;
  margin-top: -4px;
}
.feature-body {
  display: flex; flex-direction: column; gap: 6px;
  margin-top: 2px;
  flex: 1;
}
.feature-empty { color: var(--muted-dim); font-size: 13px; font-style: italic; padding: 4px 0; }
.tile-ev {
  display: flex; align-items: center; gap: 8px;
  font-size: 13px; color: var(--text);
  padding: 4px 0;
  border-bottom: 1px dashed var(--border);
  text-align: left;
}
.tile-ev:last-of-type { border-bottom: 0; }
.tile-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; box-shadow: 0 0 0 2px rgba(255,255,255,0.06); }
.tile-title { flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-weight: 500; }
.tile-free { font-size: 10px; font-weight: 700; color: #1F6E4A; background: rgba(46, 157, 107, 0.16); padding: 2px 7px; border-radius: 10px; letter-spacing: 0.04em; text-transform: uppercase; border: 1px solid rgba(46, 157, 107, 0.35); }
.tile-ongoing { color: var(--muted-dim); font-size: 16px; line-height: 1; margin-right: -2px; }
.feature-cta {
  color: var(--accent);
  font-size: 12.5px;
  font-weight: 600;
  margin-top: auto;
  opacity: 0.9;
}
.feature-tile:hover .feature-cta { opacity: 1; }

/* Compact mini-tiles column for the weekend/kids/saved trio */
.mini-tiles { display: grid; grid-template-rows: repeat(3, 1fr); gap: 10px; }
.mini-tile {
  background: var(--gradient-card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 10px 14px 9px;
  text-align: left;
  cursor: pointer; font-family: inherit; color: var(--text);
  display: flex; flex-direction: column; gap: 2px;
  position: relative; overflow: hidden;
  transition: transform .18s, border-color .18s;
}
.mini-tile::after {
  content: ''; position: absolute; inset: 0;
  background: radial-gradient(160px 120px at 110% -20%, var(--tile-accent, transparent), transparent 60%);
  opacity: 0.6; pointer-events: none;
}
.mini-tile:hover { transform: translateY(-1px); border-color: var(--border-strong); }
.mini-tile .tile-count {
  font-size: 22px; font-weight: 700; line-height: 1;
  background: var(--tile-fg, var(--gradient-accent));
  -webkit-background-clip: text; background-clip: text; color: transparent;
  font-variant-numeric: tabular-nums;
}
.mini-tile .tile-label { font-size: 12px; font-weight: 600; color: var(--text); margin-top: 2px; }
.mini-tile .tile-hint { font-size: 10px; color: var(--muted-dim); text-transform: uppercase; letter-spacing: 0.06em; }
.tile-cyan { --tile-accent: rgba(95,209,255,0.18);  --tile-fg: var(--gradient-accent); }
.tile-mint { --tile-accent: rgba(123,240,177,0.18); --tile-fg: linear-gradient(135deg, #7bf0b1, #4ccf91); }
.tile-gold { --tile-accent: rgba(245,196,107,0.18); --tile-fg: linear-gradient(135deg, #f5c46b, #d79a3a); }
.tile-warm { --tile-accent: rgba(245,196,107,0.18); --tile-fg: var(--gradient-warm); }

/* Filter expand toggle — only appears on mobile (overridden in mobile block) */
/* Legacy — the old mobile collapse toggle used to inject a .filter-toggle
   button. It no longer exists but this belt-and-braces hides any stale
   reference. */
.filter-toggle { display: none !important; }
/* The mini .mobile-only tiles duplicate the big feature tiles — hidden on
   desktop, visible on phones when the feature tiles are themselves hidden. */
.mini-tile.mobile-only { display: none; }
@media (max-width: 640px) {
  .mini-tile.mobile-only { display: flex; }
}

@media (max-width: 820px) {
  .tiles { grid-template-columns: 1fr 1fr; }
  .mini-tiles { grid-column: 1 / -1; grid-template-columns: repeat(3, 1fr); grid-template-rows: 1fr; }
}
@media (max-width: 520px) {
  .tiles { grid-template-columns: 1fr; }
  .mini-tiles { grid-column: auto; }
  .feature-tile { min-height: auto; }
}

/* ── Compact mobile layout ──
   On phones the hero tiles + filter bar combined were pushing events almost
   entirely below the fold. Here the big Today/Tomorrow preview cards get
   replaced by a single compact row of count-pills, the filter bar shrinks
   to a single tight row by default with the chips behind a toggle button.
   Events are the primary content from the first pixel. */
@media (max-width: 640px) {
  header { padding: 14px 0 12px; }
  header h1 { font-size: 18px; }
  header .tagline { display: none; }
  /* Keep the icon-only "+" button as a 36px circle on phones — symmetric
     and unobtrusive. Override the legacy size pattern. */
  header .cta { width: 36px; height: 36px; font-size: 20px; padding: 0; }
  header .header-actions { right: 16px; }

  .herostrip { padding: 10px 0 6px; }
  .herostrip::before { display: none; }

  /* Hide the big feature tiles, show compact count-pills instead */
  .feature-tile { display: none; }
  .tiles {
    display: flex;
    flex-wrap: nowrap;
    gap: 6px;
    overflow-x: auto;
    scrollbar-width: none;
    padding-bottom: 2px;
  }
  .tiles::-webkit-scrollbar { display: none; }
  .mini-tiles {
    display: contents; /* hoist children into .tiles flex */
  }
  .mini-tile {
    flex: 0 0 auto;
    padding: 8px 12px;
    min-width: auto;
  }
  .mini-tile .tile-count { font-size: 16px; }
  .mini-tile .tile-label { font-size: 10.5px; margin-top: 1px; }
  .mini-tile .tile-hint { display: none; }

  /* Pseudo "Today" + "Tomorrow" quick-filter pills injected by JS in the
     same tile row (they share .mini-tile styling). */

  /* Filter bar — now that facet counts hide empty categories, the chip row
     stays short and we can keep everything always visible on mobile. No
     more "⚙ Filters" toggle: just let the page scroll past it. */
  nav.filters { padding: 8px 0 6px; }
  .filters .row { gap: 6px; }
  .filters .row > label { min-width: 0; }
  .filters .row.sub { margin-top: 6px; gap: 6px; flex-wrap: wrap; }
  .filters .count-group { gap: 6px; }
  .filters .linkbtn { padding: 4px 8px; font-size: 11px; }

  /* The View toggle buttons can be tighter on phones. */
  .viewtoggle button { padding: 5px 10px; font-size: 11.5px; }
}

nav.filters {
  background: var(--panel);
  border-bottom: 1px solid var(--border);
  padding: 14px 0 12px;
  /* Scroll with the page at every screen size — the filter bar is tall enough
     that keeping it pinned eats too much of the viewport on mobile and tablet.
     Users scroll back up to change filters, same pattern as most event apps. */
}
/* Filter row is a 2-column grid so When/Within/Town/Search pair up
   naturally (When+Within row 1, Town+Search row 2). On Places mode the
   When filter is hidden, leaving 3 fields — Search spans both columns on
   its own row so the lone field doesn't look orphaned. */
.filters .row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  align-items: flex-end;
}
.filters .row > label { min-width: 0; }
body.mode-places .filters .row > .grow { grid-column: 1 / -1; }
.filters .row.sub {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 12px;
  align-items: center;
  gap: 10px;
}
.filters label { display: flex; flex-direction: column; font-size: 11px; color: var(--muted-dim); text-transform: uppercase; letter-spacing: 0.07em; font-weight: 600; }
.filters label.grow { flex: 1; min-width: 200px; }
.filters label.check { flex-direction: row; align-items: center; gap: 6px; color: var(--text); font-size: 13.5px; padding-bottom: 6px; text-transform: none; letter-spacing: 0; font-weight: 500; }
.filters label.check input[type="checkbox"] { accent-color: var(--accent); }
.filters select, .filters input[type="search"] {
  background: var(--panel-2); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 8px 12px; font-size: 14px; min-width: 140px;
  font-family: inherit;
  margin-top: 4px;
  transition: border-color .15s, box-shadow .15s, background .15s;
}
.filters select:hover, .filters input[type="search"]:hover { border-color: var(--border-strong); }
.filters select:focus, .filters input[type="search"]:focus { outline: 0; border-color: var(--accent); box-shadow: var(--ring); background: var(--panel-3); }
.filters input[type="search"] { width: 100%; }
.filters .count-group { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.filters .count { color: var(--muted); font-size: 12.5px; font-weight: 500; }
.filters .linkbtn {
  background: var(--panel-2); color: var(--accent);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 6px 12px; font-size: 12.5px; font-weight: 500;
  cursor: pointer; font-family: inherit;
  transition: all .15s;
}
.filters .linkbtn:hover:not(:disabled) { border-color: var(--accent); background: var(--panel-3); }
.filters .linkbtn:disabled { opacity: 0.4; cursor: not-allowed; }
.filters .linkbtn.subtle { color: var(--muted); }
.filters .linkbtn.subtle:hover { color: var(--danger); border-color: var(--danger); }

/* Toggle chips (Free only / Saved only) — appear inline on sub row */
.toggle-chip {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--panel); border: 1px solid var(--border-strong);
  border-radius: 999px; padding: 4px 12px 4px 6px;
  cursor: pointer; font-size: 12.5px; font-weight: 500;
  color: var(--text); text-transform: none; letter-spacing: 0;
  transition: all .15s;
  padding-bottom: 4px;
}
.toggle-chip input[type="checkbox"] { appearance: none; -webkit-appearance: none; width: 14px; height: 14px; border-radius: 4px; border: 1.5px solid var(--border-strong); background: var(--panel); cursor: pointer; position: relative; margin: 0; transition: all .15s; }
.toggle-chip input[type="checkbox"]:checked { background: var(--accent); border-color: var(--accent); }
.toggle-chip input[type="checkbox"]:checked::after { content: ''; position: absolute; top: 1px; left: 4px; width: 4px; height: 7px; border: solid #1A2233; border-width: 0 2px 2px 0; transform: rotate(45deg); }
.toggle-chip:hover { border-color: var(--accent-2); }
.toggle-chip:has(input:checked) { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-deep); }

/* Category-chip row: always wrap to multiple lines so the user can scan
   every category at once. flex-wrap is explicit + flex-wrap: wrap kept the
   default but historically this row had overflow-x: auto which made some
   browsers prefer a single scrollable row — lock down both behaviours. */
.chiprow {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 10px 0 2px;
  scrollbar-width: none;
  justify-content: center;
  overflow-x: visible;
}
.chiprow.ages { padding-top: 6px; border-top: 1px dashed var(--border); margin-top: 4px; justify-content: center; }
.chiprow::-webkit-scrollbar { display: none; }
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--pill); color: var(--text);
  border: 1px solid var(--border);
  border-radius: 20px; padding: 5px 12px;
  font-size: 12.5px; font-weight: 500;
  cursor: pointer; white-space: nowrap;
  font-family: inherit;
  transition: all .15s;
}
.chip:hover { border-color: var(--border-strong); background: var(--pill-strong); }
/* Opt-in layer chips (Picnic & pit stops) — dashed edge says "this one is a
   switch, not a filter": its places are off the map until you tap it. */
.chip-optin { border-style: dashed; }
.chip-optin.active { border-style: solid; }
.chip[data-cat] { --chip-color: var(--cat-other); }
.chip[data-cat="Kids"]          { --chip-color: var(--cat-kids); }
.chip[data-cat="Music"]         { --chip-color: var(--cat-music); }
.chip[data-cat="Theatre"]       { --chip-color: var(--cat-theatre); }
.chip[data-cat="Comedy"]        { --chip-color: var(--cat-comedy); }
.chip[data-cat="Exhibition"]    { --chip-color: var(--cat-exhibition); }
.chip[data-cat="Workshop"]      { --chip-color: var(--cat-workshop); }
.chip[data-cat="Talk"]          { --chip-color: var(--cat-talk); }
.chip[data-cat="Market"]        { --chip-color: var(--cat-market); }
.chip[data-cat="Food"]          { --chip-color: var(--cat-food); }
.chip[data-cat="Outdoor"]       { --chip-color: var(--cat-outdoor); }
.chip[data-cat="Sport"]         { --chip-color: var(--cat-sport); }
.chip[data-cat="Festival"]      { --chip-color: var(--cat-festival); }
.chip[data-cat="Community"]     { --chip-color: var(--cat-community); }
.chip[data-cat="Tour"]          { --chip-color: var(--cat-tour); }
.chip[data-cat="Cinema / Film"] { --chip-color: var(--cat-cinema); }
.chip[data-cat="All"]           { --chip-color: var(--accent); }

/* Non-active chip: text + background tinted with the category colour so it
   visually matches the pill + stripe on the cards below. */
.chip[data-cat]:not(.active) {
  background: color-mix(in srgb, var(--chip-color) 12%, var(--pill));
  border-color: color-mix(in srgb, var(--chip-color) 32%, transparent);
  color: color-mix(in srgb, var(--chip-color) 90%, white);
}
.chip[data-cat]:not(.active):hover {
  background: color-mix(in srgb, var(--chip-color) 20%, var(--pill));
  border-color: color-mix(in srgb, var(--chip-color) 55%, transparent);
}
/* Zero-count chips: hidden entirely. Faceted filtering means a category
   with 0 events under the current filters doesn't earn chip real estate. */
/* Zero-count chips: dim but keep visible so the user can still see every
   category and switch to one directly without first tapping "All". The
   chip remains clickable — clicking it just narrows to that category which
   may show zero results (and prompts the user to broaden filters). */
.chip.chip-empty { opacity: 0.35; }
.chip.chip-empty:hover { opacity: 0.6; }
.chip[data-cat]:not(.active) .chip-count {
  background: color-mix(in srgb, var(--chip-color) 18%, transparent);
  color: inherit;
}
/* "All" is the neutral baseline — don't tint it heavily */
.chip[data-cat="All"]:not(.active) {
  background: var(--pill);
  color: var(--text);
  border-color: var(--border);
}
.chip[data-cat="All"]:not(.active) .chip-count { background: var(--pill-strong); color: var(--muted); }

.chip.active {
  background: color-mix(in srgb, var(--chip-color) 88%, white 0%);
  color: #051d2b;
  border-color: transparent; font-weight: 700;
  box-shadow: 0 4px 14px color-mix(in srgb, var(--chip-color) 45%, transparent);
}
.chip.active .chip-count { background: rgba(0,0,0,0.22); color: inherit; }
/* Major / Big tier pills — gold accent so they read as scope filters, not categories */
.tier-chip { --chip-color: #FFCE3D; border-color: color-mix(in srgb, #FFCE3D 60%, transparent); font-weight: 700; }
.chip .chip-count {
  background: var(--pill-strong);
  color: inherit;
  padding: 1px 7px; border-radius: 10px;
  font-size: 11px; font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.chip.active .chip-count { background: rgba(0,0,0,0.18); }
.chip .chip-icon { font-size: 13px; line-height: 1; margin-right: 2px; }

.viewtoggle { display: inline-flex; background: var(--panel-2); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 3px; }
.viewtoggle button {
  background: transparent; color: var(--muted); border: 0;
  padding: 6px 14px; font-size: 12.5px; font-weight: 500; border-radius: 6px;
  cursor: pointer; font-family: inherit;
  transition: all .15s;
}
.viewtoggle button:hover { color: var(--text); }
.viewtoggle button.active { background: var(--gradient-accent); color: #051d2b; font-weight: 600; }

main { padding: 28px 0 80px; }

@keyframes fadeUp {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
.daygroup { animation: fadeUp .35s ease both; }
.daygroup:nth-child(2) { animation-delay: .04s; }
.daygroup:nth-child(3) { animation-delay: .08s; }
.daygroup:nth-child(4) { animation-delay: .12s; }
.daygroup:nth-child(n+5) { animation-delay: .16s; }

/* Place-return banner — shown after the user taps "X events here" on a
   place card. Sticks below the header so they can always get back to the
   Places list they came from without losing their filters or scroll. */
.place-return-banner {
  position: sticky;
  top: 0;
  z-index: 30;
  background: var(--accent-2);
  color: #ffffff;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 14px;
  font-size: 13.5px;
  font-weight: 600;
  box-shadow: 0 2px 8px rgba(20, 35, 60, 0.18);
}
.place-return-banner[hidden] { display: none !important; }
.place-return-btn {
  background: rgba(255,255,255,0.18);
  color: #ffffff;
  border: 1px solid rgba(255,255,255,0.35);
  border-radius: 999px;
  padding: 6px 14px;
  font-size: 13px;
  font-weight: 700;
  font-family: inherit;
  cursor: pointer;
  transition: background .15s;
}
.place-return-btn:hover { background: rgba(255,255,255,0.32); }
.place-return-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  opacity: 0.9;
  font-weight: 500;
}

/* Toast */
.toast {
  position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%) translateY(12px);
  background: var(--panel-3); color: var(--text);
  border: 1px solid var(--border-strong); border-radius: 999px;
  padding: 9px 18px; font-size: 13px; font-weight: 500;
  box-shadow: var(--shadow-card);
  opacity: 0; pointer-events: none;
  transition: opacity .2s, transform .2s;
  z-index: 50;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.toast .tag { color: var(--accent-3); font-weight: 600; margin-right: 4px; }

/* Day group headings (list view) */
.daygroup { margin-bottom: 32px; }
.daygroup h2 {
  margin: 0 0 14px;
  font-size: 12px;
  color: var(--text);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  border-bottom: 1px solid var(--border-strong);
  padding-bottom: 8px;
  display: flex; align-items: baseline; gap: 10px;
  font-weight: 700;
}
.daygroup h2 .relative {
  color: var(--accent-2);
  font-weight: 600;
  text-transform: none;
  letter-spacing: 0;
  font-size: 12px;
}
.daygroup ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }

/* Classes tab — collapsible activity-type groups. Turns the recurring-session
   sea into a short tappable menu (Storytime, Rhyme Time, Lego Club…). */
.classes-intro { color: var(--muted); font-size: 13.5px; line-height: 1.5; margin: 2px 2px 16px; }
.classgroup {
  background: var(--panel); border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-soft);
  margin-bottom: 12px; overflow: hidden; animation: fadeUp .35s ease both;
}
.classgroup > summary {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px;
  padding: 14px 16px; cursor: pointer; list-style: none;
  user-select: none; -webkit-tap-highlight-color: transparent;
}
.classgroup > summary::-webkit-details-marker { display: none; }
.classgroup > summary::after {
  content: '›'; margin-left: auto; font-size: 22px; line-height: 1;
  color: var(--muted-dim); transform: rotate(90deg);
  transition: transform .25s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.classgroup[open] > summary::after { transform: rotate(-90deg); }
.classgroup[open] > summary { border-bottom: 1px solid var(--border); }
.cg-icon { font-size: 20px; line-height: 1; }
.cg-title { font-weight: 700; color: var(--text); font-size: 15.5px; }
.cg-count {
  background: var(--accent-2-soft); color: var(--accent-2); font-weight: 700;
  font-size: 12.5px; padding: 2px 9px; border-radius: 999px;
}
.cg-preview { flex-basis: 100%; color: var(--muted-dim); font-size: 12.5px; padding-left: 30px; margin-top: -2px; }
.classgroup > ul { list-style: none; margin: 0; padding: 12px; display: grid; gap: 10px; background: var(--panel-2); }

.event {
  background: var(--gradient-card);
  border: 2px solid var(--border-strong);
  border-radius: var(--radius);
  padding: 14px 14px 14px 20px;
  display: grid;
  grid-template-columns: 88px 1fr auto;
  grid-template-areas:
    "when  content actions"
    "thumb content actions";
  gap: 8px 14px;
  align-items: start;
  transition: border-color .18s, transform .18s, box-shadow .18s;
  position: relative;
  overflow: hidden;
  box-shadow: var(--shadow-soft);
}
.event .when     { grid-area: when; }
.event .thumbwrap { grid-area: thumb; }
.event .content  { grid-area: content; }
.event .event-actions { grid-area: actions; }
/* Thumbnail fills its column under the date block — same width as the
   date column, square aspect for visual rhythm. */
.event .thumbwrap, .event .thumb, .event .thumb-fallback {
  width: 88px; height: 88px;
}
.event {
  /* default category colour — overridden per-card below */
  --cat-color: var(--cat-other);
}
.event::before {
  /* Brand stripe — sky-blue at the top fading to sun-yellow at the bottom.
     Replaces the old per-category stripe; the category colour still shows
     on the pills so users can still scan by type. */
  content: ''; position: absolute; left: 0; top: 0; bottom: 0;
  width: 5px;
  background: linear-gradient(180deg, var(--accent-2) 0%, var(--sun) 100%);
  opacity: 1;
  transition: width .2s;
}
.event:hover {
  border-color: var(--accent-2);
  transform: translateY(-1px); box-shadow: var(--shadow-card);
}
.event:hover::before { width: 6px; }
.event.is-saved::before {
  background: linear-gradient(180deg, var(--accent-3) 0%, var(--sun) 100%);
  width: 6px;
}

/* --- Marquee events ----------------------------------------------------
   The big-money, lots-going-on events that earn a full-bleed poster and a
   stronger frame so they pop out of the scannable list. Layout flips to a
   banner: poster spans the full width on top, the date/content/actions row
   sits beneath it. */
.event.is-marquee {
  grid-template-columns: 88px 1fr auto;
  grid-template-areas:
    "thumb thumb thumb"
    "when  content actions";
  /* Chunky, unmistakable frame — 4px accent border + outer glow ring. */
  border: 4px solid var(--accent);
  border-radius: calc(var(--radius) + 4px);
  box-shadow: 0 10px 30px rgba(0,0,0,0.16), 0 0 0 4px var(--accent-soft);
  /* Warm tint at the top so even an image-less marquee card reads as special. */
  background: linear-gradient(180deg, var(--accent-soft) 0%, var(--gradient-card) 30%);
  padding: 0 16px 18px;
  margin: 14px 0;                                  /* extra breathing room from neighbours */
  overflow: hidden;
}
.event.is-marquee::before { display: none; }       /* the whole card IS the highlight now */
.event.is-marquee:hover { transform: translateY(-3px); box-shadow: 0 16px 40px rgba(0,0,0,0.2), 0 0 0 4px var(--accent-soft); }
/* Full-width poster banner ~1.5× a normal card's footprint. Beats the generic
   88px square rule on specificity (three classes vs two). */
.event.is-marquee .thumbwrap,
.event.is-marquee .thumb,
.event.is-marquee .thumb-fallback {
  width: 100%; height: 230px;
}
.event.is-marquee .thumbwrap { margin: 0 -16px 14px; width: auto; }
.event.is-marquee .thumb {
  border-radius: 0;
  border: 0;
  border-bottom: 4px solid var(--accent);
}
.event.is-marquee .thumb-fallback {
  font-size: 92px;
  border-radius: 0;
  border: 0;
  border-bottom: 4px solid var(--accent);
}
.event.is-marquee h3 { font-size: 22px; font-weight: 800; line-height: 1.2; }
.event.is-marquee .when .date { color: var(--accent-deep); }
/* Banner ribbon — bigger and louder so it reads at a glance. */
.event.is-marquee .marquee-flag {
  position: absolute;
  top: 14px; left: 0;
  z-index: 2;
  background: var(--accent);
  color: var(--text);
  font-size: 12.5px; font-weight: 800;
  letter-spacing: 0.05em; text-transform: uppercase;
  padding: 7px 16px 7px 22px;
  border-radius: 0 22px 22px 0;
  box-shadow: 0 3px 10px rgba(0,0,0,0.22);
}
/* Cross-list "+ Market" pill — quieter than the primary category pill */
.event .pill.cat-also { opacity: 0.78; font-weight: 600; }

/* --- "Don't miss" highlights strip -------------------------------------
   A swipeable row of the few biggest events across the selected period,
   pinned above the day-by-day list so the great stuff is the first thing
   you see. */
.highlights { margin: 4px 0 20px; }
.highlights-head {
  font-size: 16px; font-weight: 800; color: var(--text);
  margin: 0 0 11px; display: flex; align-items: baseline; gap: 8px;
}
.highlights-sub { font-size: 12.5px; font-weight: 600; color: var(--muted); }
.highlights-row {
  display: flex; gap: 12px; overflow-x: auto;
  padding: 2px 2px 12px;
  scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch;
}
.hl-card {
  scroll-snap-align: start;
  flex: 0 0 165px; width: 165px;
  text-align: left; padding: 0; cursor: pointer;
  background: var(--gradient-card);
  border: 2px solid var(--accent);
  border-radius: 14px; overflow: hidden;
  box-shadow: 0 4px 14px rgba(0,0,0,0.09);
  transition: transform .15s, box-shadow .15s;
}
.hl-card:hover { transform: translateY(-2px); box-shadow: 0 9px 22px rgba(0,0,0,0.15); }
.hl-thumb {
  height: 100px;
  background: linear-gradient(135deg, var(--accent-2-soft, #BFDBF0), var(--accent-soft));
  display: flex; align-items: center; justify-content: center;
}
.hl-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hl-thumb .hl-emoji { font-size: 44px; filter: grayscale(0.15) brightness(1.1); }
.hl-info { padding: 9px 11px 11px; }
.hl-title {
  font-size: 13px; font-weight: 700; line-height: 1.25; color: var(--text);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.hl-metaline { font-size: 11px; color: var(--muted); margin-top: 4px; }
.hl-why {
  font-size: 10.5px; font-weight: 800; color: var(--accent-deep);
  margin-top: 7px; text-transform: uppercase; letter-spacing: 0.03em;
}

/* Category colour assignments */
.event[data-cat="Kids"]               { --cat-color: var(--cat-kids); }
.event[data-cat="Music"]              { --cat-color: var(--cat-music); }
.event[data-cat="Theatre"]            { --cat-color: var(--cat-theatre); }
.event[data-cat="Comedy"]             { --cat-color: var(--cat-comedy); }
.event[data-cat="Exhibition"]         { --cat-color: var(--cat-exhibition); }
.event[data-cat="Workshop"]           { --cat-color: var(--cat-workshop); }
.event[data-cat="Talk"]               { --cat-color: var(--cat-talk); }
.event[data-cat="Market"]             { --cat-color: var(--cat-market); }
.event[data-cat="Food"]               { --cat-color: var(--cat-food); }
.event[data-cat="Outdoor"]            { --cat-color: var(--cat-outdoor); }
.event[data-cat="Sport"]              { --cat-color: var(--cat-sport); }
.event[data-cat="Festival"]           { --cat-color: var(--cat-festival); }
.event[data-cat="Community"]          { --cat-color: var(--cat-community); }
.event[data-cat="Tour"]               { --cat-color: var(--cat-tour); }
.event[data-cat="Cinema / Film"]      { --cat-color: var(--cat-cinema); }
.event[data-cat="Other"]              { --cat-color: var(--cat-other); }

.event .when {
  text-align: center;
  background: var(--panel-2);
  border-radius: var(--radius-sm);
  padding: 10px 6px 8px;
  align-self: start;
  border: 1px solid var(--border);
  min-width: 72px;
}
.event .when .day { font-size: 10.5px; color: var(--muted-dim); text-transform: uppercase; letter-spacing: 0.1em; font-weight: 600; }
.event .when .date {
  font-size: 26px; font-weight: 800; line-height: 1; margin-top: 3px;
  color: var(--accent-2);
  letter-spacing: -0.02em;
}
.event .when .month { font-size: 10.5px; color: var(--muted); text-transform: uppercase; margin-top: 3px; font-weight: 600; letter-spacing: 0.08em; }
.event .when .range { font-size: 10px; color: var(--muted-dim); margin-top: 5px; }
.event .when .wx {
  font-size: 14px; margin-top: 6px; line-height: 1;
  padding: 2px 0; border-top: 1px dashed var(--border);
  padding-top: 6px;
}

/* Thumbnail column */
.event .thumbwrap { align-self: start; }
.event .thumb {
  width: 88px; height: 88px;
  border-radius: var(--radius-sm);
  object-fit: cover;
  display: block;
  background: var(--panel-2);
  border: 1px solid var(--border);
}
.event .thumb-fallback {
  display: flex; align-items: center; justify-content: center;
  background:
    linear-gradient(135deg, rgba(95,209,255,0.08), rgba(123,240,177,0.06));
  color: var(--muted);
  font-size: 32px;
  border: 1px solid var(--border);
}
.event .thumb-fallback span { filter: grayscale(0.25) brightness(1.15); }
.event .content { min-width: 0; } /* prevent long titles from pushing actions off-screen */

.event h3 { margin: 0 0 5px; font-size: 16px; line-height: 1.3; letter-spacing: -0.005em; font-weight: 600; }
.event h3 a { color: var(--text); text-decoration: none; }
.event h3 a:hover { color: var(--accent); }
.event .meta { font-size: 12.5px; color: var(--muted); margin-bottom: 6px; display: flex; flex-wrap: wrap; align-items: center; }
.event .meta .dot { margin: 0 6px; opacity: 0.35; }
.event .meta .miles { color: var(--accent-3); font-weight: 600; }
.event .desc { font-size: 13.5px; color: var(--muted); margin: 8px 0 10px; line-height: 1.5; }
.event .desc.expanded { color: var(--text); }
.event .desc .more-btn {
  background: transparent;
  border: 0;
  padding: 0;
  margin-left: 2px;
  color: var(--accent);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.event .desc .more-btn:hover { color: var(--accent-deep); }
.event .pills { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 4px; }
.event .pill {
  background: var(--panel);
  color: var(--muted);
  font-size: 10.5px;
  padding: 3px 9px;
  border-radius: 20px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 600;
  border: 1px solid var(--border);
}
.event .pill.source { color: var(--accent-2); background: var(--panel); border-color: var(--accent-2-soft); }
.event .pill.cat {
  color: var(--cat-color);
  background: var(--panel);
  border-color: color-mix(in srgb, var(--cat-color) 38%, transparent);
  font-weight: 700;
}
.event .pill.ongoing { color: var(--muted); background: var(--panel); border-color: var(--border-strong); }
.event .pill.age { color: var(--accent-4); background: var(--panel); border-color: color-mix(in srgb, var(--accent-4) 32%, transparent); }
.event .pill.family { color: var(--accent-3); background: var(--panel); border-color: color-mix(in srgb, var(--accent-3) 38%, transparent); }
.event .pill.big { color: var(--accent-deep); background: var(--panel); border-color: color-mix(in srgb, var(--accent) 50%, transparent); font-weight: 700; }
.event .pill.estate { color: #6840BD; background: var(--panel); border-color: color-mix(in srgb, #6840BD 35%, transparent); font-weight: 700; }
/* Series pill — marks an outreach-programme event that's been deduped:
   "+N other towns" appears on the entry nearest your home, while the
   duplicates in other towns are hidden. Soft slate so it doesn't compete
   with the louder category pills. */
.event .pill.series { color: var(--muted); background: var(--pill); border-color: var(--border-strong); font-style: italic; }
.event .pill.free { color: var(--accent-3); background: var(--panel); border-color: color-mix(in srgb, var(--accent-3) 45%, transparent); font-weight: 700; }
.event .pill.price { color: var(--muted); background: var(--panel); border-color: var(--border-strong); }

.new-badge {
  display: inline-block;
  background: var(--gradient-accent);
  color: #051d2b; font-size: 10px; font-weight: 700;
  padding: 2px 7px; border-radius: 4px; margin-right: 6px;
  vertical-align: 1px; letter-spacing: 0.08em;
  box-shadow: 0 2px 10px rgba(95,209,255,0.35);
  animation: pulse 2s ease-in-out infinite;
}
@keyframes pulse {
  0%, 100% { box-shadow: 0 2px 10px rgba(95,209,255,0.35); }
  50%      { box-shadow: 0 2px 16px rgba(95,209,255,0.6); }
}
.event.is-new { border-color: rgba(95,209,255,0.3); }

.event-actions {
  display: flex; flex-direction: column; gap: 4px;
  align-self: start;
  margin-left: 2px;
}
.iconbtn {
  background: transparent;
  color: var(--muted-dim);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  width: 32px; height: 32px;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; font-size: 15px; font-family: inherit;
  transition: all .15s;
}
.iconbtn:hover { color: var(--accent); border-color: var(--border); background: var(--panel-2); }
.iconbtn.star { font-size: 17px; }
.iconbtn.star.active { color: var(--accent-2); border-color: rgba(245,196,107,0.3); background: rgba(245,196,107,0.08); }
.iconbtn.star.active:hover { color: var(--accent-2); }

/* =======================================================================
   Hero-image event card (events list only — `:not(.place)` keeps the
   Places list card on its own older layout). Big photo / category-tinted
   emoji panel on the left, content on the right, and a footer bar with the
   navy date badge · category pills · save/calendar/share actions.
   ======================================================================= */
.event:not(.place) {
  grid-template-columns: clamp(140px, 40%, 240px) 1fr;
  grid-template-rows: 1fr auto;
  grid-template-areas:
    "hero content"
    "hero footer";              /* image spans the full card height */
  gap: 8px 16px;
  padding: 14px;
  align-items: stretch;
  border-width: 1px;
  border-color: var(--border);
  border-radius: 18px;
}
.event:not(.place)::before { display: none; }   /* drop the prototype-y left stripe */
.event:not(.place) .ev-hero   { grid-area: hero; }
.event:not(.place) .content   { grid-area: content; align-self: start; }
.event:not(.place) .ev-footer { grid-area: footer; }

.event:not(.place) .ev-hero {
  position: relative;
  width: 100%;
  min-height: 140px;             /* a generous image even when the text is short */
  border-radius: 14px;
  overflow: hidden;
  border: 1px solid var(--border);
  background: linear-gradient(140deg,
    color-mix(in srgb, var(--cat-color) 26%, var(--panel)),
    color-mix(in srgb, var(--cat-color) 8%, var(--panel)));
  display: flex; align-items: center; justify-content: center;
}
.event:not(.place) .ev-emoji {
  font-size: clamp(52px, 16vw, 86px); line-height: 1;
  filter: drop-shadow(0 2px 5px rgba(0,0,0,0.14));
}
.event:not(.place) .ev-img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: block;
}
.event:not(.place) .ev-hero-badge {
  position: absolute; top: 8px; left: 8px; z-index: 2;
  background: var(--accent); color: var(--text);
  font-size: 10px; font-weight: 800; letter-spacing: 0.04em;
  text-transform: uppercase; padding: 4px 9px; border-radius: 999px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.22);
}
.event:not(.place) .ev-new {
  position: absolute; top: 8px; right: 8px; z-index: 2;
  background: var(--gradient-accent); color: #051d2b;
  font-size: 9.5px; font-weight: 800; letter-spacing: 0.08em;
  padding: 3px 7px; border-radius: 6px;
  box-shadow: 0 2px 10px rgba(95,209,255,0.4);
}

/* Bigger, bolder title + icon-led meta on the right */
.event:not(.place) h3 {
  font-size: 18px; font-weight: 700; line-height: 1.25; margin: 0 0 6px;
  /* Clamp the title to 2 lines so every regular card is the same height. */
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
}
.event:not(.place) .meta { font-size: 13px; gap: 0 2px; }
.event:not(.place) .meta-pin { margin-right: 4px; }
.event:not(.place) .meta .miles { color: var(--accent-3); font-weight: 700; }
.event:not(.place) .why-line { margin: 2px 0 6px; }
/* Clamp the blurb to 2 lines + reserve those 2 lines, so all regular events
   share one tidy height and the bigger ⭐ Big / Major cards stand out. The
   full description is always available by tapping the card. */
.event:not(.place):not(.is-marquee) .desc {
  margin: 6px 0 0; line-height: 1.45; min-height: 2.5em;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
}
.event:not(.place):not(.is-marquee) .desc .more-btn { display: none; }

/* Bottom strip under the content: category pills + save/cal/share actions */
.event:not(.place) .ev-footer {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  border-top: 1px solid var(--border);
  padding-top: 10px;
}
.event:not(.place) .ev-footer .pills { flex: 1 1 auto; margin: 0; align-items: center; }
.event:not(.place) .ev-footer .event-actions {
  flex-direction: row; align-self: center; gap: 4px; margin: 0 0 0 auto;
}

/* Navy date badge — overlaid on the bottom-left of the image */
.event:not(.place) .when {
  position: absolute; left: 8px; bottom: 8px; z-index: 2;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  min-width: 50px; padding: 6px 9px;
  background: linear-gradient(160deg, var(--accent-2) 0%, #1F5E8A 100%);
  border-radius: 12px;
  box-shadow: 0 4px 12px rgba(10,30,50,0.42);
}
.event:not(.place) .when .day   { color: rgba(255,255,255,0.82); font-size: 9.5px; letter-spacing: 0.1em; }
.event:not(.place) .when .date  { color: #fff; font-size: 22px; font-weight: 800; line-height: 1; margin: 1px 0; }
.event:not(.place) .when .month { color: rgba(255,255,255,0.82); font-size: 9.5px; letter-spacing: 0.08em; }
.event:not(.place) .when .range { color: rgba(255,255,255,0.7); font-size: 9px; margin-top: 2px; }
.event:not(.place) .when .wx { display: none; }

/* Marquee = the loudest events: full-width hero banner across the top */
.event.is-marquee:not(.place) {
  grid-template-columns: 1fr;
  grid-template-rows: auto auto auto;
  grid-template-areas: "hero" "content" "footer";
}
.event.is-marquee:not(.place) .ev-hero { min-height: 0; height: 210px; }
.event.is-marquee:not(.place) .ev-emoji { font-size: 84px; }
.event.is-marquee:not(.place) h3 { font-size: 22px; font-weight: 800; }

/* Major-event photo gallery — a strip of tappable thumbnails that swap the big
   hero photo in place. On the card the strip sits bottom-right of the hero
   (the date badge owns bottom-left); the full set appears in the popup. */
.ev-gallery-strip {
  position: absolute; right: 8px; bottom: 8px; z-index: 3;
  display: flex; gap: 6px;
}
.ev-thumb {
  width: 46px; height: 46px; flex: 0 0 auto; padding: 0;
  border: 2px solid #fff; border-radius: 10px; overflow: hidden;
  position: relative; cursor: pointer; background: var(--panel);
  box-shadow: 0 2px 8px rgba(0,0,0,0.35);
  transition: transform 0.18s cubic-bezier(0.34, 1.56, 0.64, 1), border-color 0.15s, box-shadow 0.15s;
}
.ev-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ev-thumb:hover { transform: translateY(-2px); }
.ev-thumb.active {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent), 0 2px 10px rgba(0,0,0,0.4);
}
.ev-thumb-more {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  background: rgba(8,16,24,0.6); color: #fff; font-weight: 800; font-size: 13px;
}

/* Popup gallery — bigger hero, then a scrollable thumbnail row underneath. */
.event-dialog-gallery { position: relative; }
.event-dialog-strip {
  display: flex; gap: 8px; padding: 10px 0 2px;
  overflow-x: auto; -webkit-overflow-scrolling: touch;
}
.event-dialog-strip .ev-thumb { width: 62px; height: 62px; }

.empty {
  color: var(--muted); text-align: center; padding: 80px 0 60px; font-size: 14px;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
}
/* Honour the `hidden` attribute even when `.empty` has display:flex set.
   Without this the empty-state block kept showing at the bottom of every
   page even when there were hundreds of results above it. */
.empty[hidden] { display: none !important; }

/* Hide the explanatory clutter under the preset bar — the user has the four
   preset buttons clearly named, the When dropdown for date, and the search
   box; the scope label / "Live as of" stamp / quick When-chip buttons just
   add noise above the filter row. Easy to re-enable per element if any one
   of them ends up missed. */
#scopeLabel,
#liveAsOf,
#rainySuggest,
#appliedFilters,
.when-chips { display: none !important; }
.empty .empty-icon { font-size: 44px; opacity: 0.8; }
.empty h3 { margin: 6px 0 0; color: var(--text); font-size: 18px; font-weight: 600; }
.empty p { margin: 0 0 12px; max-width: 360px; }
.empty .cta { margin-top: 8px; }
.empty-actions { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin-top: 4px; }
.empty-actions .cta-soft {
  background: var(--panel-2);
  color: var(--accent-deep);
  border: 1px solid var(--border-strong);
  padding: 9px 14px;
  border-radius: var(--radius-sm);
  font-weight: 600;
  font-size: 13.5px;
  cursor: pointer;
  font-family: inherit;
  transition: all .15s;
}
.empty-actions .cta-soft:hover { background: var(--accent-soft); border-color: var(--accent); }

.live-as-of {
  margin-top: 6px;
  font-size: 11.5px;
  color: var(--muted);
  letter-spacing: 0.01em;
  text-align: center;
  opacity: 0.85;
}

.applied-filters {
  margin-top: 10px;
  display: flex; flex-wrap: wrap; gap: 6px; justify-content: center;
}
.applied-pill {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--accent-soft);
  border: 1px solid var(--accent);
  color: var(--accent-deep);
  border-radius: 999px;
  padding: 4px 10px 4px 12px;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
  transition: filter .12s;
}
.applied-pill:hover { filter: brightness(0.96); }
.applied-pill .x {
  display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px;
  border-radius: 999px;
  background: rgba(255,255,255,0.6);
  font-size: 13px;
  line-height: 1;
}

.when-chips {
  display: flex; gap: 8px; flex-wrap: wrap;
  margin: 0 0 10px;
  padding: 0;
}
.when-chips .when-chip {
  background: var(--panel-2);
  border: 1px solid var(--border-strong);
  color: var(--text);
  padding: 7px 14px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
  transition: all .12s;
}
.when-chips .when-chip:hover { border-color: var(--accent); }
.when-chips .when-chip.active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--text);
}
.when-chips[hidden] { display: none; }
.applied-filters[hidden] { display: none; }
.live-as-of[hidden] { display: none; }

.iconbtn.share { font-size: 14px; }
.iconbtn.share:hover { color: var(--accent-3, var(--accent)); }

.why-line {
  margin: 4px 0 6px;
  font-size: 12px;
  color: var(--accent-deep, var(--text));
  font-weight: 600;
  letter-spacing: 0.005em;
  opacity: 0.88;
  line-height: 1.5;
}

.rainy-suggest {
  margin-top: 8px;
  padding: 8px 10px;
  background: linear-gradient(135deg, rgba(108,178,232,0.14), rgba(95,209,255,0.10));
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  font-size: 13px;
  color: var(--accent-deep, var(--text));
}
.rainy-suggest[hidden] { display: none; }
.rainy-suggest-text { flex: 1; min-width: 180px; font-weight: 600; }
.rainy-suggest-yes {
  background: var(--accent);
  color: var(--text);
  border: none;
  padding: 6px 12px;
  border-radius: 999px;
  font-size: 12.5px;
  font-weight: 700;
  cursor: pointer;
  font-family: inherit;
}
.rainy-suggest-yes:hover { filter: brightness(1.05); }
.rainy-suggest-x {
  background: transparent;
  border: 1px solid transparent;
  color: var(--muted);
  width: 24px; height: 24px;
  border-radius: 999px;
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
  font-family: inherit;
}
.rainy-suggest-x:hover { color: var(--text); background: rgba(0,0,0,0.04); }

.saved-export-bar {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  margin: 6px 0 0;
  padding: 6px 10px;
  background: var(--accent-soft);
  border: 1px dashed var(--accent);
  border-radius: var(--radius-sm);
  font-size: 12.5px;
  flex-basis: 100%;
}
.saved-export-bar[hidden] { display: none; }
.saved-export-label {
  color: var(--accent-deep);
  font-weight: 700;
  margin-right: 4px;
}

/* --- Guides & top lists card (sibling of the digest card — blue where it is gold) --- */
.guides-strip {
  margin: 56px 0 0;
  padding: 0 12px;
}
.guides-card {
  display: block;
  max-width: 620px;
  margin: 0 auto;
  padding: 26px 26px 24px;
  background:
    radial-gradient(circle at 0% 0%, rgba(79,164,210,0.16), transparent 55%),
    radial-gradient(circle at 100% 100%, rgba(244,184,42,0.10), transparent 50%),
    #F4FAFF;
  border: 3px solid #4FA4D2;
  border-radius: 18px;
  box-shadow:
    0 2px 4px rgba(20,35,60,0.06),
    0 24px 44px -18px rgba(79,164,210,0.45),
    0 14px 36px -18px rgba(20,35,60,0.22);
  text-align: center;
  position: relative;
  color: inherit;
  text-decoration: none;
}
.guides-card::before {
  content: '';
  position: absolute;
  inset: -3px;
  border-radius: 18px;
  background: linear-gradient(135deg, rgba(79,164,210,0.35), transparent 45%, rgba(244,184,42,0.25));
  z-index: -1;
  filter: blur(14px);
  opacity: 0.6;
}
.guides-card-kicker {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 6px;
  width: max-content;
  margin: 0 auto 14px;
  padding: 7px 14px;
  background: #4FA4D2;
  color: #fff;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  box-shadow: 0 2px 8px rgba(79,164,210,0.45);
}
.guides-card-kicker-icon { font-size: 14px; }
.guides-card-hook {
  margin: 0 0 10px;
  font-size: 24px;
  line-height: 1.18;
  font-weight: 800;
  letter-spacing: -0.018em;
  color: var(--text);
  text-align: center;
}
.guides-card-sub {
  margin: 0 0 16px;
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--muted);
  text-align: center;
}
.guides-card-cta {
  display: block;
  width: 100%;
  background: #4FA4D2;
  color: #fff;
  padding: 16px 22px;
  border-radius: 12px;
  font-weight: 800;
  font-size: 16px;
  letter-spacing: -0.005em;
  transition: filter .14s, transform .14s, box-shadow .14s;
  box-shadow:
    0 1px 0 rgba(20,35,60,0.05),
    0 8px 18px -8px rgba(79,164,210,0.6);
}
.guides-card:hover .guides-card-cta {
  filter: brightness(1.06);
  transform: translateY(-1px);
  box-shadow:
    0 1px 0 rgba(20,35,60,0.05),
    0 12px 22px -8px rgba(79,164,210,0.7);
}

.digest-strip {
  margin: 56px 0 32px;
  padding: 0 12px;
}
.digest-card {
  max-width: 620px;
  margin: 0 auto;
  padding: 28px 26px 24px;
  background:
    radial-gradient(circle at 100% 0%, rgba(244,184,42,0.18), transparent 55%),
    radial-gradient(circle at 0% 100%, rgba(74,158,212,0.10), transparent 50%),
    #FFFCF0;
  border: 3px solid var(--accent);
  border-radius: 18px;
  box-shadow:
    0 2px 4px rgba(20,35,60,0.06),
    0 24px 44px -18px rgba(244,184,42,0.45),
    0 14px 36px -18px rgba(20,35,60,0.22);
  text-align: left;
  position: relative;
}
.digest-card::before {
  content: '';
  position: absolute;
  inset: -3px;
  border-radius: 18px;
  background: linear-gradient(135deg, rgba(244,184,42,0.35), transparent 45%, rgba(74,158,212,0.25));
  z-index: -1;
  filter: blur(14px);
  opacity: 0.6;
}
.digest-card-kicker {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 6px;
  width: max-content;
  margin: 0 auto 14px;
  padding: 7px 14px;
  background: var(--accent);
  color: var(--text);
  border-radius: 999px;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  box-shadow: 0 2px 8px rgba(244,184,42,0.45);
}
.digest-card-kicker-icon { font-size: 14px; }
.digest-card-hook {
  margin: 0 0 12px;
  font-size: 24px;
  line-height: 1.18;
  font-weight: 800;
  letter-spacing: -0.018em;
  color: var(--text);
  text-align: center;
}
.digest-card-headline {
  margin: 0 0 14px;
  font-size: 26px;
  line-height: 1.18;
  font-weight: 800;
  letter-spacing: -0.018em;
  color: var(--text);
}
.digest-card-sub {
  margin: 0 0 22px;
  font-size: 15.5px;
  line-height: 1.6;
  color: var(--muted);
}
.digest-card-cta {
  display: block;
  width: 100%;
  background: var(--accent);
  color: var(--text);
  border: none;
  padding: 16px 22px;
  border-radius: 12px;
  font-weight: 800;
  font-size: 16px;
  letter-spacing: -0.005em;
  cursor: pointer;
  font-family: inherit;
  transition: filter .14s, transform .14s, box-shadow .14s;
  box-shadow:
    0 1px 0 rgba(20,35,60,0.05),
    0 8px 18px -8px rgba(244,184,42,0.6);
}
.digest-card-cta:hover {
  filter: brightness(1.05);
  transform: translateY(-1px);
  box-shadow:
    0 1px 0 rgba(20,35,60,0.05),
    0 12px 22px -8px rgba(244,184,42,0.7);
}
.digest-card-cta:active { transform: translateY(0); }
.digest-card-trust {
  margin: 14px 0 0;
  font-size: 12px;
  color: var(--muted-dim);
  font-weight: 600;
  text-align: center;
  letter-spacing: 0.01em;
}
@media (min-width: 600px) {
  .digest-card { padding: 34px 36px 28px; }
  .digest-card-hook { font-size: 28px; }
  .digest-card-headline { font-size: 30px; }
  .digest-card-cta { width: auto; padding: 16px 32px; }
}

.digest-dialog .optional {
  font-weight: 400;
  font-size: 12px;
  color: var(--muted);
  margin-left: 4px;
}
.digest-dialog .status {
  margin: 10px 0 0;
  padding: 8px 10px;
  border-radius: 6px;
  font-size: 13px;
}
.digest-dialog .status.info { background: var(--accent-soft); color: var(--accent-deep); }
.digest-dialog .status.error { background: #FCE9E5; color: #9B3A1A; }
.digest-dialog .status.success { background: #E8F6EE; color: #1F6A41; }

.daygroup-wx {
  margin-left: auto;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text);
  text-transform: none;
  letter-spacing: 0;
  background: var(--panel);
  padding: 4px 10px;
  border-radius: 999px;
  border: 1px solid var(--border-strong);
}
.daygroup-mood {
  margin: -6px 0 14px;
  font-size: 13px;
  color: var(--accent-deep);
  font-weight: 600;
  font-style: italic;
  letter-spacing: 0;
  text-transform: none;
}

/* Skeleton */
.event.skeleton {
  background: var(--panel);
  border-color: var(--border);
  cursor: default;
  pointer-events: none;
}
.skeleton-box, .skeleton-line {
  background: linear-gradient(90deg, var(--panel-2) 0%, var(--panel-3) 40%, var(--panel-2) 80%);
  background-size: 300% 100%;
  animation: shimmer 1.6s ease-in-out infinite;
  border-radius: 6px;
}
.event.skeleton .when.skeleton-box { height: 72px; width: 72px; border: 0; }
.event.skeleton .thumbwrap.skeleton-box { height: 88px; width: 88px; border: 0; }
.event.skeleton .content { display: flex; flex-direction: column; gap: 8px; padding-top: 6px; }
.skeleton-line { height: 12px; }
.daygroup h2.skeleton-line { height: 14px; border-radius: 4px; display: inline-block; }

/* Build-stamp pill — bottom-right, low opacity. Tells the user which build
   they're on. Click to force a reload. */
.version-pill {
  position: fixed; right: 8px; bottom: 8px; z-index: 200;
  background: rgba(26, 34, 51, 0.65); color: #FFFFFF;
  font-size: 10px; font-weight: 600;
  padding: 3px 8px; border-radius: 999px;
  font-family: -apple-system, BlinkMacSystemFont, "SF Mono", Menlo, monospace;
  font-variant-numeric: tabular-nums; letter-spacing: 0.04em;
  cursor: pointer; opacity: 0.5;
  transition: opacity 0.2s;
}
.version-pill:hover { opacity: 1; }

/* Auto-refresh banner — appears when the server has a newer build than
   the client first saw. Fixed-bottom, full-width, can't be missed. */
.update-banner {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 300;
  background: var(--accent); color: var(--text);
  font-weight: 700; text-align: center;
  padding: 12px 16px; cursor: pointer;
  box-shadow: 0 -4px 16px rgba(20, 35, 60, 0.18);
  font-size: 14px;
}
.update-banner:hover { background: #FFCB4F; }

@keyframes shimmer {
  0% { background-position: 100% 0; }
  100% { background-position: -100% 0; }
}

/* Calendar grid */
.calgrid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
.calhead {
  text-align: center; font-size: 10.5px; color: var(--muted-dim);
  text-transform: uppercase; letter-spacing: 0.1em; padding-bottom: 8px;
  font-weight: 600;
}
.calcell {
  background: var(--gradient-card); border: 1px solid var(--border);
  border-radius: var(--radius-sm); min-height: 110px; padding: 7px 9px;
  display: flex; flex-direction: column; gap: 3px;
  transition: border-color .15s, transform .15s;
}
.calcell:hover { border-color: var(--border-strong); }
.calcell.empty-cell { background: transparent; border: 1px dashed var(--border); opacity: 0.4; }
.calcell.today { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent), 0 6px 24px rgba(95,209,255,0.15); }
.calcell .num { font-size: 13px; color: var(--muted); font-weight: 700; display: flex; align-items: center; justify-content: space-between; }
.calcell .cal-wx { font-size: 12px; opacity: 0.9; margin-left: auto; }
.calcell.today .num {
  color: var(--accent);
  background: var(--gradient-accent);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.calcell .ev {
  font-size: 11px; line-height: 1.35;
  background: var(--panel-2); padding: 3px 7px; border-radius: 5px;
  color: var(--text); text-decoration: none; display: block;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  border-left: 2px solid var(--accent-2);
  transition: background .15s;
}
.calcell .ev:hover { background: var(--panel-3); }
.calcell .ev.family { border-left-color: var(--accent-3); }
.calcell .ev.free { box-shadow: inset 0 0 0 1px rgba(123,240,177,0.25); }
.calcell .more { font-size: 10px; color: var(--muted-dim); margin-top: 2px; font-weight: 600; }
.calmonth { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; }
.calmonth h2 {
  margin: 0; font-size: 20px; font-weight: 700; letter-spacing: -0.01em;
  background: linear-gradient(180deg, var(--panel) 0%, #aac0d6 100%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.calmonth button {
  background: var(--panel-2); color: var(--text); border: 1px solid var(--border);
  padding: 7px 14px; border-radius: var(--radius-sm); cursor: pointer; font-family: inherit; font-size: 13.5px;
  font-weight: 500; transition: all .15s;
}
.calmonth button:hover { border-color: var(--accent); color: var(--accent); background: var(--panel-3); }

footer {
  border-top: 1px solid var(--border);
  padding: 18px 0 28px;
  color: var(--muted-dim);
  font-size: 12px;
  margin-top: 40px;
  background: var(--bg);
}
footer #meta { display: block; margin-bottom: 6px; }
footer .foot-legal { display: block; }
footer .foot-account { display: block; margin-bottom: 6px; min-height: 1.2em; }
footer .foot-link { color: var(--muted-dim); text-decoration: underline; }
footer .foot-link:hover { color: var(--accent-2); }
footer .foot-sep { margin: 0 6px; opacity: 0.6; }
footer .acc-link {
  background: none; border: 0; padding: 0;
  color: var(--accent-2); text-decoration: underline;
  font: inherit; cursor: pointer;
}
footer .acc-link:hover { color: var(--accent-2-deep, var(--accent-2)); }
footer .acc-email { color: var(--text); font-weight: 600; }
footer .acc-hint { color: var(--muted-dim); margin-left: 6px; }

/* Sign-in dialog — same minimal style as the existing poster dialog */
dialog.sign-in-dialog {
  border: 0;
  border-radius: 14px;
  padding: 22px 22px 18px;
  max-width: 380px;
  width: calc(100vw - 32px);
  background: var(--panel);
  color: var(--text);
  box-shadow: 0 18px 60px rgba(20,30,50,0.18);
}
dialog.sign-in-dialog::backdrop {
  background: rgba(20,30,50,0.42);
}
dialog.sign-in-dialog h2 {
  margin: 0 0 8px;
  font-size: 20px;
}
dialog.sign-in-dialog .sign-in-sub {
  margin: 0 0 14px;
  color: var(--muted);
  font-size: 14px;
  line-height: 1.5;
}
dialog.sign-in-dialog input[type="email"] {
  width: 100%;
  box-sizing: border-box;
  padding: 12px 14px;
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  font-size: 16px;
  background: var(--panel-2);
  color: var(--text);
}
dialog.sign-in-dialog input[type="email"]:focus {
  outline: none;
  border-color: var(--accent-2);
  background: var(--panel);
}
dialog.sign-in-dialog .sign-in-actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  margin-top: 14px;
}
dialog.sign-in-dialog .sign-in-actions button {
  padding: 10px 16px;
  border-radius: 10px;
  border: 1px solid var(--border-strong);
  background: var(--panel-2);
  color: var(--text);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
dialog.sign-in-dialog .sign-in-actions button:hover { background: var(--panel-3); }
dialog.sign-in-dialog .sign-in-actions button.primary {
  background: var(--accent);
  border-color: var(--accent-deep);
  color: #2a1d00;
}
dialog.sign-in-dialog .sign-in-actions button.primary:hover { background: var(--accent-deep); }
dialog.sign-in-dialog .sign-in-actions button[disabled] {
  opacity: 0.55;
  cursor: default;
}
dialog.sign-in-dialog .sign-in-status {
  margin: 10px 0 0;
  font-size: 13px;
  line-height: 1.4;
}
dialog.sign-in-dialog .sign-in-fine {
  margin: 14px 0 0;
  font-size: 12px;
  color: var(--muted-dim);
  line-height: 1.45;
}

/* Map view */
#mapView { padding: 0; }
#mapCanvas {
  height: calc(100vh - 260px);
  min-height: 520px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  overflow: hidden;
  background: var(--panel);
}
/* MapLibre + Protomaps vector basemap — popup, control, attribution and
   geolocate overrides so the map matches the dark/cool app chrome. The map
   canvas itself is a single <canvas>, not tile <img>s, so the old per-tile
   label brightening trick (.leaflet-label-tile) is gone: label colour and
   halo are part of the vector style and don't need CSS help. */

/* Popup chrome */
.maplibregl-popup-content {
  background: var(--panel-3) !important;
  color: var(--text) !important;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  box-shadow: 0 12px 40px rgba(0,0,0,0.6);
  padding: 14px 16px;
  font-size: 13px;
  line-height: 1.45;
}
.maplibregl-popup-content hr { border: 0; border-top: 1px solid var(--border); margin: 8px 0; }
.maplibregl-popup-anchor-top .maplibregl-popup-tip { border-bottom-color: var(--panel-3); }
.maplibregl-popup-anchor-bottom .maplibregl-popup-tip { border-top-color: var(--panel-3); }
.maplibregl-popup-anchor-left .maplibregl-popup-tip { border-right-color: var(--panel-3); }
.maplibregl-popup-anchor-right .maplibregl-popup-tip { border-left-color: var(--panel-3); }
.maplibregl-popup-close-button {
  color: var(--muted) !important;
  font-size: 22px !important;
  padding: 2px 8px !important;
  background: transparent !important;
}
.maplibregl-popup-close-button:hover { color: var(--text) !important; background: rgba(255,255,255,0.04) !important; }

.map-popup-event strong { color: var(--text); font-size: 13.5px; }
.map-popup-event .popup-meta { color: var(--muted); font-size: 12px; }
.map-popup-event a { color: var(--accent); text-decoration: none; font-size: 12.5px; font-weight: 600; }
.map-popup-event a:hover { text-decoration: underline; }
.map-popup .popup-more { color: var(--muted-dim); font-size: 11.5px; margin-top: 6px; font-style: italic; }
.popup-flagship-star { color: #fcbe5d; }

/* Controls (zoom, geolocate, scale) */
.maplibregl-ctrl-group {
  background: var(--panel-3) !important;
  border: 1px solid var(--border) !important;
  box-shadow: 0 6px 16px rgba(0,0,0,0.4) !important;
}
.maplibregl-ctrl-group button {
  background-color: transparent !important;
}
.maplibregl-ctrl-group button:hover { background-color: var(--panel-2) !important; }
.maplibregl-ctrl-group button + button { border-top: 1px solid var(--border) !important; }
.maplibregl-ctrl-icon {
  filter: invert(0.85) brightness(1.1) hue-rotate(180deg);
}
.maplibregl-ctrl-attrib {
  background: rgba(7,16,26,0.8) !important;
  color: var(--muted-dim) !important;
  font-size: 10px !important;
}
.maplibregl-ctrl-attrib a { color: var(--accent-soft) !important; }
.maplibregl-ctrl-scale {
  background: rgba(7,16,26,0.65) !important;
  color: var(--muted) !important;
  border-color: var(--border-strong) !important;
  font-size: 10px !important;
}

/* Canvas reset — MapLibre adds its own outline on focus that flickers
   when popups open. Hide it; the canvas is decorative, not focusable text. */
.maplibregl-canvas:focus { outline: none; }

@media (max-width: 700px) {
  header h1 { font-size: 24px; }
  header { padding: 28px 0 24px; }
  .event h3 { font-size: 15px; }
  /* Mobile card layout — two columns + bottom action row.
       row 1: [date]  [content]
       row 2: [thumb] [content]   ← thumb fills the column (big square image)
       row 3: [    actions span full width, right-aligned    ]
     The actions used to sit in a third column on the right, which ate
     horizontal room and left a dead patch under the pills. Moving them
     to a full-width bottom row lets the content text and the thumbnail
     both use the entire card width.
     Weather emoji is hidden on mobile so the date block stays compact
     and the image directly under it can be bigger. */
  .event {
    grid-template-columns: 108px 1fr;
    grid-template-areas:
      "when    content"
      "thumb   content"
      "actions actions";
    gap: 8px 12px;
    padding: 12px;
  }
  .event .thumbwrap, .event .thumb, .event .thumb-fallback { width: 108px; height: 108px; }
  .event .when { min-width: 108px; padding: 8px 4px 6px; }
  .event .when .date { font-size: 24px; }
  .event .when .wx { display: none; }
  /* Mobile: place cards without a thumbnail collapse to a single content
     row — no phantom thumb slot pushing the layout taller. */
  .event.place:not(.has-thumb) {
    grid-template-areas:
      "when    content"
      "actions actions";
  }
  .event-actions {
    flex-direction: row;
    gap: 4px;
    align-self: stretch;
    justify-content: flex-end;
    margin-top: 2px;
    margin-left: 0;
    border-top: 1px solid var(--border);
    padding-top: 8px;
  }
  .iconbtn { width: 30px; height: 30px; }
  .calgrid { gap: 3px; }
  .calcell { min-height: 82px; padding: 4px 5px; }
  .calcell .ev { font-size: 10px; padding: 2px 4px; }
  .calhead { font-size: 10px; }
  .chip { font-size: 12px; padding: 4px 10px; }

  .filters .row { gap: 8px; }
  .filters .row.sub { flex-wrap: wrap; }
  .chiprow { padding: 8px 0 2px; }
}

/* --- Mode toggle (What's on / Things to do) ----------------------------
   Full-width segmented control under the header — perfectly symmetric
   two-column grid so neither mode pulls the eye more than the other. */
.modebar {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 3px;
  padding: 4px;
  margin: 12px 0 0;
  background: var(--bg-2);
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  position: relative;
}
.modebar button {
  background: transparent;
  color: var(--muted);
  border: 0;
  padding: 9px 6px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  transition: color .15s, background .15s;
  letter-spacing: 0.01em;
  text-align: center;
  white-space: nowrap;
  min-width: 0;
}
.modebar button:hover { color: var(--text); }
.modebar button.active {
  background: var(--accent);
  color: var(--text);
  box-shadow: 0 2px 6px rgba(212, 154, 15, 0.30);
}

/* --- Preset bar (Home pill + Big/All pair) ---------------------------
   Top row: one centred "home" pill — three button slices in one pill
   (cog · Near me label · plus). The cog and plus sit on the pill edges,
   the label fills the middle.
   Bottom row: Big events + All NI as a symmetric two-column row. */
.presetbar {
  background: var(--panel);
  border-bottom: 1px solid var(--border);
  padding: 14px 0 14px;
}

/* "For you" preset — the default landing feed (local radius + big events
   from anywhere in NI). Same not-active / active visual pattern as the
   other preset buttons so it's never ambiguous whether it's selected:
   not active = white outlined, active = yellow filled. The slightly
   larger size signals it's the recommended start without bleeding into
   the "is this selected?" question. */
.foryou-row {
  display: flex;
  justify-content: center;
  margin-bottom: 10px;
}
.foryou-btn {
  max-width: 380px;
  width: 100%;
  min-height: 40px;
  padding: 0 22px;
  font-size: 13.5px;
  font-weight: 700;
  border-radius: 999px;
  justify-content: center;
  align-items: center;
}

.home-pill {
  display: flex;
  align-items: stretch;
  justify-content: stretch;
  max-width: 380px;
  min-height: 40px;
  margin: 0 auto 0;
  background: var(--panel);
  border: 1.5px solid var(--border-strong);
  border-radius: 999px;
  overflow: hidden;
  box-shadow: var(--shadow-soft);
}
.home-pill .home-cog {
  background: transparent;
  color: var(--accent-2);
  border: 0;
  border-right: 1px solid var(--border);
  width: 44px;
  height: auto;
  border-radius: 0;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 17px;
  font-family: inherit;
  flex-shrink: 0;
  transition: background .15s, color .15s;
}
.home-pill .home-cog:hover { background: var(--bg-2); color: var(--text); }

.home-pill .home-label {
  flex: 1;
  background: transparent;
  color: var(--text);
  border: 0;
  border-radius: 0;
  padding: 10px 14px;
  font-size: 14px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  text-align: center;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  transition: background .15s;
  min-width: 0;
}
.home-pill .home-label:hover { background: var(--bg-2); }
.home-pill .home-label[aria-pressed="true"] {
  background: var(--accent-soft);
  color: var(--accent-deep);
}
.home-pill .home-label em {
  font-style: normal;
  font-weight: 500;
  font-size: 12.5px;
  opacity: 0.75;
}
/* Separator dot is no longer needed — the "Near me" span is hidden in
   every mode and the em alone reads "Coleraine 20mi". The pin emoji
   provides the "near me" semantic. */

.home-pill .home-plus {
  background: var(--accent);
  color: var(--text);
  border: 0;
  border-left: 1px solid var(--border);
  width: 44px;
  border-radius: 0;
  cursor: pointer;
  font-size: 24px;
  font-weight: 400;
  font-family: inherit;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: background .15s;
}
.home-pill .home-plus:hover { background: #FFCB4F; }

.preset-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}
.preset-pair > .preset-btn {
  width: 100%;
  min-width: 0;
  min-height: 40px;
  padding: 0 14px;
  font-size: 13.5px;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Symmetric pair grid for the preset row. All four buttons (For You,
   Big events, Near me, All of NI) are now direct children of .preset-row
   so grid-area placement actually works in Safari (display: contents had
   propagation issues). The home pill stays a compound element with cog +
   label + plus inside.
     Events  → 2x2 grid (For You + Big events | Near me + All of NI)
     Classes → For You + All of NI on top, Near me full width below
     Places  → Near me + All of NI single row */
.preset-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  max-width: 460px;
  margin: 0 auto;
}
.preset-row .home-pill { max-width: none; margin: 0; width: 100%; }
.preset-row .foryou-btn { max-width: none; }

body.mode-events .preset-row {
  grid-template-areas:
    "foryou big"
    "near   all";
}
body.mode-events #presetForYou { grid-area: foryou; }
body.mode-events #presetMajor    { grid-area: big; }
body.mode-events .home-pill    { grid-area: near; }
body.mode-events #presetAllNI  { grid-area: all; }

body.mode-classes .preset-row {
  grid-template-areas:
    "foryou all"
    "near   near";
}
body.mode-classes #presetForYou { grid-area: foryou; }
body.mode-classes .home-pill    { grid-area: near; }
body.mode-classes #presetAllNI  { grid-area: all; }

body.mode-places .preset-row {
  grid-template-areas: "near all";
}
body.mode-places .home-pill   { grid-area: near; }
body.mode-places #presetAllNI { grid-area: all; }

/* Always-compact home pill — drop the "Near me" wording and show just
   "📍 Coleraine 20mi" so the pill is consistently the same shape as the
   other preset buttons and fits side-by-side at ~180px wide on phones. */
.home-pill .home-cog,
.home-pill .home-plus { width: 32px; font-size: 13px; }
.home-pill .home-label { padding: 0 6px; font-size: 12.5px; gap: 3px; min-width: 0; }
.home-pill .home-label > span { display: none; }
.home-pill .home-label em {
  font-style: normal;
  font-weight: 600;
  font-size: 12.5px;
  opacity: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

/* Indoor + Outdoor toggle chips paired explicitly so they sit side-by-side
   underneath whichever filter row they end up wrapping below. */
.indoor-outdoor-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  flex-basis: 100%;
}
.indoor-outdoor-pair .toggle-chip { justify-content: center; }
.preset-pair .preset-btn {
  justify-content: center;
  text-align: center;
  padding: 12px 14px;
  font-size: 13.5px;
}

.scope-label {
  margin-top: 10px;
  font-size: 12.5px;
  color: var(--muted);
  letter-spacing: 0.01em;
  text-align: center;
}
.chip-count {
  font-style: normal;
  display: inline-block;
  margin-left: 4px;
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--pill-strong);
  color: var(--accent-2);
  font-size: 11px;
  font-weight: 700;
  min-width: 18px;
  text-align: center;
}
.preset-btn {
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--border-strong);
  min-height: 40px;
  padding: 0 14px;
  border-radius: 999px;
  font-size: 13.5px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  transition: color .15s, background .15s, border-color .15s;
}
.preset-btn em {
  font-style: normal;
  font-weight: 400;
  font-size: 12px;
  opacity: 0.8;
}
.preset-btn:hover { color: var(--text); border-color: var(--border-strong); }
.preset-btn.active {
  background: var(--gradient-accent);
  color: #051d2b;
  border-color: transparent;
  box-shadow: 0 4px 14px rgba(95,209,255,0.25);
}
.preset-btn.active em { color: #051d2b; opacity: 0.7; }

/* Home dialog — matches the established .poster-dialog / .event-dialog look */
.home-dialog {
  max-width: 380px; width: 92%;
  background: var(--gradient-card); color: var(--text);
  border: 1px solid var(--border-strong); border-radius: var(--radius-lg);
  padding: 24px 26px; box-shadow: 0 40px 100px rgba(0,0,0,0.75);
}
.home-dialog::backdrop { background: rgba(3, 10, 18, 0.72); backdrop-filter: blur(6px); }
.home-dialog h2 { margin: 0 0 6px; font-size: 19px; }
.home-dialog .dialog-sub { margin: 0 0 16px; color: var(--muted); font-size: 13px; }
.home-field { display: flex; flex-direction: column; gap: 5px; margin: 12px 0; font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; font-weight: 600; }
.home-field select {
  background: var(--panel-2); color: var(--text);
  border: 1px solid var(--border-strong);
  padding: 10px 12px; border-radius: 8px;
  font-size: 14px; font-family: inherit; font-weight: 500;
  text-transform: none; letter-spacing: normal;
}
.home-dialog .dialog-buttons { display: flex; gap: 10px; justify-content: flex-end; margin-top: 18px; }
.home-dialog .dialog-buttons button { padding: 9px 18px; border-radius: 8px; font-size: 13.5px; font-weight: 600; font-family: inherit; cursor: pointer; border: 1px solid var(--border-strong); background: var(--panel-2); color: var(--text); }
.home-dialog .dialog-buttons button.primary { background: var(--gradient-accent); color: #051d2b; border-color: transparent; }

/* --- Share / QR dialog -------------------------------------------------- */
.share-dialog { max-width: 340px; text-align: center; }
.share-dialog .dialog-sub { text-align: center; }
.qr-box {
  width: 220px; height: 220px; margin: 4px auto 14px;
  background: var(--panel); border-radius: 14px; padding: 12px;
  box-shadow: 0 6px 18px rgba(0,0,0,0.18);
  display: flex; align-items: center; justify-content: center;
  color: var(--muted); font-size: 13px;
}
.qr-box svg { width: 100%; height: 100%; display: block; }
.share-url {
  font-weight: 700; font-size: 15px; color: var(--accent-2);
  letter-spacing: 0.01em; margin-bottom: 4px;
}
.share-dialog .share-buttons { justify-content: center; flex-wrap: wrap; }

/* "Get the app" install section inside the share dialog. Exactly one
   variant is visible at a time: Android one-tap button, iOS pictured
   steps, or the installed tick. */
.install-section { margin-top: 14px; }
.install-divider {
  display: flex; align-items: center; gap: 10px;
  color: var(--muted); font-size: 12px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.06em;
  margin-bottom: 12px;
}
.install-divider::before, .install-divider::after {
  content: ""; flex: 1; height: 1px; background: var(--border-strong);
}
.install-btn {
  width: 100%; padding: 12px 18px; border-radius: 10px;
  border: 1px solid transparent; cursor: pointer;
  background: var(--gradient-accent); color: #051d2b;
  font-family: inherit; font-size: 15px; font-weight: 700;
}
.install-steps {
  list-style: none; counter-reset: install-step;
  margin: 0; padding: 0; text-align: left;
  display: flex; flex-direction: column; gap: 10px;
}
.install-steps li {
  counter-increment: install-step;
  display: flex; align-items: center; gap: 10px;
  font-size: 13.5px; line-height: 1.35; color: var(--text);
}
.install-steps li::before {
  content: counter(install-step);
  flex: 0 0 auto; width: 20px; height: 20px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--gradient-accent); color: #051d2b;
  font-size: 11.5px; font-weight: 800;
}
.install-ico {
  flex: 0 0 auto; width: 30px; height: 30px; border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  background: var(--panel-2); border: 1px solid var(--border-strong);
  color: var(--accent-2);
}
.install-ico svg { width: 17px; height: 17px; }
.install-ico-done { font-size: 15px; font-weight: 800; color: var(--accent-2); }
.install-done {
  margin: 0; font-size: 14px; font-weight: 700; color: var(--accent-2);
}
.install-note {
  display: block; font-style: normal; font-size: 12px;
  color: var(--muted); margin-top: 2px;
}
.install-section { margin: 0 0 4px; }
.install-headline {
  margin: 0 0 6px; font-size: 22px; font-weight: 900; line-height: 1.15;
  color: var(--text); letter-spacing: -0.01em;
}
.install-sub {
  margin: 0 0 14px; font-size: 14px; line-height: 1.45; color: var(--muted);
}
.share-block { margin-top: 6px; }
.install-open-safari {
  text-align: left; padding: 12px 14px; border-radius: 12px;
  background: var(--panel-2); border: 1px solid var(--border-strong);
}
.install-hint-title {
  margin: 0 0 6px; font-size: 14.5px; font-weight: 800; color: var(--accent-2);
}
.install-hint-body {
  margin: 0; font-size: 13.5px; line-height: 1.45; color: var(--text);
}

/* --- Mode-specific control visibility ----------------------------------
   Events mode hides Calendar + Map view toggles (calendar miscounted with
   the When filter; map for events stacked badly on the same venue — both
   removed in favour of the list, which is the only view that genuinely
   helps for events). Places mode keeps List + Map (calendar isn't
   meaningful for stationary places).
   The hero "223 Today / 24 Tomorrow / 86 Weekend" strip is also gone for
   events mode — counts ignored the When filter and confused users into
   thinking the bottom list count was wrong. The When picker already
   exposes these shortcuts, so the strip was duplication. */
body.mode-events .viewtoggle [data-view="calendar"],
body.mode-events .viewtoggle [data-view="map"] { display: none; }
body.mode-events .viewtoggle { display: none; } /* only one view → no toggle */
body.mode-events .herostrip { display: none; }

/* Classes mode = recurring participatory activities (ClassForKids, Libraries
   storytimes, parent-and-toddler, dance/karate/etc). List-only, no map.
   Hides the events-specific noise (Big-events preset, library/toddler/estate
   toggles which are now redundant since classes are the dedicated home for
   that content) and the place-only ones. */
body.mode-classes .viewtoggle { display: none; }
body.mode-classes .herostrip { display: none; }
body.mode-classes #presetMajor,
body.mode-classes .toggle-chip:has(#showLibraryRoutine),
body.mode-classes .toggle-chip:has(#showToddlerRoutine),
body.mode-classes .toggle-chip:has(#estatesOnly),
body.mode-classes .toggle-chip:has(#rainyDay),
body.mode-classes .toggle-chip:has(#indoorOnly),
body.mode-classes .toggle-chip:has(#outdoorOnly) { display: none; }
body.mode-classes .modebar button.active {
  background: var(--accent);
  color: var(--text);
  box-shadow: 0 2px 6px rgba(212, 154, 15, 0.30);
}

/* Classes mode preset bar = three vertically-stacked pills, all the same
   max-width (380px) and centred. Without this, the lone "All of NI" pill in
   the preset-pair grid renders left-aligned at a different width to the
   For You / home pill above, breaking the vertical symmetry the user
   expects. Mirrors the Places-mode treatment. */
/* Classes/Places preset-pair custom column rules removed — preset-row now
   uses display: contents on .preset-pair so the buttons are direct grid
   children of .preset-row, positioned via grid-area per mode. */

/* Things to do mode hides every UI element that's events-only — no more
   carry-over chips/toggles that look clickable but do nothing in this mode.
   The + button stays visible in both modes for layout symmetry (the home
   pill looks lopsided without it). It still drives the poster-extract
   dialog, which works whether you're suggesting an event or a place. */
body.mode-places .when-filter,
body.mode-places .viewtoggle [data-view="calendar"],
body.mode-places .herostrip,
body.mode-places .toggle-chip:has(#showLibraryRoutine),
body.mode-places .toggle-chip:has(#showToddlerRoutine),
body.mode-places .toggle-chip:has(#estatesOnly),
body.mode-places .toggle-chip:has(#familyOnly),
body.mode-places .toggle-chip:has(#freeOnly),
body.mode-places .toggle-chip:has(#rainyDay),
body.mode-events .toggle-chip:has(#indoorOnly),
body.mode-events .toggle-chip:has(#outdoorOnly),
body.mode-places #presetMajor,
body.mode-places #presetForYou,
body.mode-places .ages { display: none; }

/* Places-mode toolbar: a clean trio of equal-width buttons — List · Map ·
   ★ Saved — and nothing else. The place COUNT and the standalone "★ Saved"
   checkbox are hidden (Saved now lives in the trio), so the row reads as one
   tidy segmented control instead of the old toggle-soup. */
.viewtoggle [data-view="saved"] { display: none; }            /* events/classes: no Saved view */
body.mode-places .viewtoggle [data-view="saved"] { display: inline-flex; }
body.mode-places .viewtoggle {
  display: flex; width: 100%; max-width: 460px;
}
body.mode-places .viewtoggle button { flex: 1 1 0; justify-content: center; white-space: nowrap; }
body.mode-places .filters .count-group,
body.mode-places .toggle-chip:has(#savedOnly) { display: none; }
/* The relocated full category-pill group sits below the map; give it air so
   it doesn't crowd the map's bottom edge once you scroll to it. */
#placesBelowMap:not(:empty) { margin-top: 14px; }
#placesBelowMap .chiprow { margin-top: 0; }

/* Places-mode preset-pair custom column rule removed — see grid-area
   assignments above. */

/* Title stays the brand colour (white on sky-blue band) in both modes —
   mode is communicated by the segmented control below, not the title. */
body.mode-places .modebar button.active {
  background: var(--accent);
  color: var(--text);
  box-shadow: 0 2px 6px rgba(212, 154, 15, 0.30);
}

/* Place cards: when there's no real photo, the left column is just the
   emoji-on-soft-green panel (.when) and there's no thumbnail row beneath
   it. When we DO have a photo, the .when block stays as a compact label
   above and the thumb fills the column below — same rhythm as event cards. */
/* =======================================================================
   Place card — wide banner image on top (places mostly get wide photos),
   then a two-column body (title/meta/desc + category pills), then big
   Search-web / Directions action buttons. Full vertical card, distinct
   from the events list card.
   ======================================================================= */
.event.place {
  display: flex;
  flex-direction: column;
  gap: 0;
  padding: 0;                    /* hero is full-bleed to the card edges */
  overflow: hidden;
  border-width: 1px;
  border-color: var(--border);
  border-radius: 18px;
}
.event.place::before { display: none; }

.event.place .pc-hero {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;          /* wide banner — suits the wide photos */
  display: flex; align-items: center; justify-content: center;
  overflow: hidden;
  background: linear-gradient(140deg,
    color-mix(in srgb, var(--cat-color) 28%, var(--panel)),
    color-mix(in srgb, var(--cat-color) 9%, var(--panel)));
}
.event.place .pc-emoji {
  font-size: clamp(56px, 18vw, 100px); line-height: 1;
  filter: drop-shadow(0 2px 6px rgba(0,0,0,0.16));
}
.event.place .pc-img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: block;
}
.event.place .pc-hero-chips {
  position: absolute; left: 10px; bottom: 10px; z-index: 2;
  display: flex; gap: 6px; flex-wrap: wrap;
}
.event.place .pc-chip {
  display: inline-flex; align-items: center; gap: 4px;
  background: color-mix(in srgb, var(--panel) 92%, transparent); color: var(--text);
  font-size: 11px; font-weight: 700;
  padding: 4px 10px; border-radius: 999px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.18);
}
.event.place .pc-chip.dist { color: var(--accent-3); }
.event.place .pc-free {
  position: absolute; top: 10px; right: 10px; z-index: 2;
  background: var(--panel); color: var(--accent-3);
  font-size: 11px; font-weight: 800; letter-spacing: 0.04em;
  padding: 5px 13px; border-radius: 999px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.18);
}
/* Photo credit. Creative Commons photos (Geograph/Wikimedia) are someone else's
   picture: the licence requires the photographer be named wherever the photo is
   shown, and those files never carry our watermark. Small and low-contrast so it
   reads as a caption, not a label — but always present, never hover-only. */
.event.place .pc-credit {
  position: absolute; left: 10px; bottom: 8px; z-index: 2;
  max-width: calc(100% - 20px);
  font-size: 10px; line-height: 1.3; font-weight: 600;
  color: #fff; text-shadow: 0 1px 3px rgba(0,0,0,0.85);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  pointer-events: none;
}
.map-popup-place .popup-credit {
  font-size: 10px; line-height: 1.3; color: var(--muted);
  margin: 4px 0 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.event.place .pc-flag {
  position: absolute; top: 10px; left: 10px; z-index: 2;
  width: 28px; height: 28px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--accent); color: var(--text); font-size: 15px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.24);
}
/* Star + Guide badge can now both show on a flagship place that also has a guide.
   Lay them out in a row at the top-left so they don't stack on the same spot. */
.event.place .pc-badges {
  position: absolute; top: 10px; left: 10px; z-index: 2;
  display: flex; align-items: center; gap: 6px;
}
.event.place .pc-badges .pc-flag,
.event.place .pc-badges .pc-guide-badge { position: static; top: auto; left: auto; }

.event.place .pc-body {
  display: grid;
  grid-template-columns: 1fr clamp(118px, 40%, 190px);
  gap: 2px 12px;
  align-items: start;
  padding: 14px 16px 10px;
}
.event.place .pc-main { grid-column: 1; min-width: 0; }
.event.place .pc-pills {
  grid-column: 2;
  display: flex; flex-wrap: wrap; gap: 6px;
  justify-content: flex-end; align-content: flex-start;
}
.event.place .pc-pills .chip-icon { margin-right: 3px; }
.event.place h3 {
  color: var(--text); font-size: 19px; font-weight: 800;
  line-height: 1.2; margin: 0 0 6px;
}
.event.place .meta { font-size: 13px; color: var(--muted); display: flex; flex-wrap: wrap; align-items: center; gap: 0 3px; }
.event.place .meta-pin { margin-right: 4px; }
.event.place .meta .miles { color: var(--accent-3); font-weight: 700; }
.event.place .desc { font-size: 13.5px; color: var(--muted); margin: 6px 0 0; line-height: 1.45; }

/* "You'll see …" — the wildlife species you can spot at a reserve. Tinted to the
   category colour so it reads as a highlight, not body copy. */
.event.place .pc-wildlife { display: flex; flex-wrap: wrap; align-items: center; gap: 5px; margin: 8px 0 0; }
.event.place .pc-wildlife-label { font-size: 11px; font-weight: 700; letter-spacing: .02em; color: var(--cat-color, var(--accent-2)); text-transform: uppercase; }
.event.place .pc-wildlife-tag {
  font-size: 11.5px; font-weight: 600; color: var(--text);
  background: color-mix(in srgb, var(--cat-color, #6ed9e4) 20%, var(--panel));
  border: 1px solid color-mix(in srgb, var(--cat-color, #6ed9e4) 45%, var(--border));
  padding: 2px 8px; border-radius: 999px;
}

.event.place .pc-actions {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  border-top: 1px solid var(--border);
  padding: 10px 16px 12px;
}
.event.place .pc-btn {
  flex: 1 1 auto;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 11px 14px; border-radius: 12px;
  font-size: 13.5px; font-weight: 700; font-family: inherit;
  text-decoration: none; cursor: pointer;
  border: 1px solid var(--border-strong); background: var(--panel-2); color: var(--text);
  transition: border-color .15s, background .15s, transform .12s;
}
.event.place .pc-btn:hover { transform: translateY(-1px); }
.event.place .pc-btn.search { background: color-mix(in srgb, var(--accent-2) 8%, var(--panel)); color: var(--accent-2); border-color: color-mix(in srgb, var(--accent-2) 32%, transparent); }
.event.place .pc-btn.directions { background: color-mix(in srgb, var(--accent-3) 8%, var(--panel)); color: var(--accent-3); border-color: color-mix(in srgb, var(--accent-3) 32%, transparent); }
.event.place .pc-btn.events { background: var(--accent-soft); color: var(--accent-deep); border-color: color-mix(in srgb, var(--accent) 45%, transparent); }
.event.place .pc-btn.website { color: var(--accent-deep); border-color: color-mix(in srgb, var(--accent) 35%, transparent); }
.event.place .pc-star {
  flex: 0 0 auto; width: 42px; height: 42px; font-size: 19px;
  border: 1px solid var(--border); border-radius: 12px;
}
/* The guide is the page we WANT people to read — pull it out of the utility
   row into its own full-width gold bar, plus a badge on the photo, so it can't
   be missed (and hide "Search web" when a guide exists — our page is better). */
.event.place .pc-guide { padding: 12px 16px 0; }
.event.place .pc-guide-cta {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; padding: 13px 16px; border-radius: 13px;
  background: var(--gradient-accent); color: #3a2b00;
  font-size: 15px; font-weight: 800; text-decoration: none;
  box-shadow: 0 5px 16px rgba(244,184,42,0.38);
  transition: transform .15s, filter .15s;
}
.event.place .pc-guide-cta:hover { transform: translateY(-1px); filter: brightness(1.04); }
.event.place .pc-guide-cta .arr { transition: transform .2s; }
.event.place .pc-guide-cta:hover .arr { transform: translateX(4px); }
.event.place .pc-guide-badge {
  position: absolute; top: 10px; left: 10px; z-index: 2;
  display: inline-flex; align-items: center; gap: 5px;
  background: var(--gradient-accent); color: #3a2b00;
  font-size: 11.5px; font-weight: 800; letter-spacing: 0.01em;
  padding: 5px 11px; border-radius: 999px;
  box-shadow: 0 2px 10px rgba(0,0,0,0.22);
}
.map-popup-place .popup-actions a.guide-cta {
  flex-basis: 100%; justify-content: center;
  background: var(--gradient-accent); color: #3a2b00; border: 0;
  font-weight: 800; box-shadow: 0 4px 12px rgba(244,184,42,0.35);
}

/* Active search banner — shown at the top of the results list when the user
   has clicked a venue/place link (or typed in the search box). Gives an
   unmistakable "back to all results" path so users don't get stranded at
   a venue-filtered view with no obvious way out. */
.search-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  background: var(--accent-soft);
  border: 1.5px solid var(--accent);
  border-radius: var(--radius);
  padding: 10px 14px;
  margin: 0 0 14px;
  font-size: 14px;
  color: var(--text);
  box-shadow: var(--shadow-soft);
}
.search-banner-text strong { color: var(--accent-deep); }
.search-banner-clear {
  background: var(--accent);
  color: var(--text);
  border: 0;
  padding: 6px 14px;
  border-radius: 999px;
  font-weight: 700;
  font-size: 13px;
  cursor: pointer;
  font-family: inherit;
  flex-shrink: 0;
  transition: background .15s;
}
.search-banner-clear:hover { background: #FFCB4F; }

/* Venue / place-name link — clicking jumps to events filtered by that venue.
   Sits inline in the meta row on event cards, or on the h3 of place cards.
   Styled as a subtle interactive element so it reads as clickable without
   shouting. */
.venue-link {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px dotted var(--accent-2-soft);
  cursor: pointer;
  transition: color .15s, border-color .15s;
}
.venue-link:hover {
  color: var(--accent-2);
  border-bottom-color: var(--accent-2);
}
/* On place cards the venue-link wraps the whole title — make it look like a
   regular heading by default and only show the affordance on hover. */
.event.place h3 .venue-link {
  color: var(--text);
  border-bottom-color: transparent;
}
.event.place h3 .venue-link:hover {
  color: var(--accent-2);
  border-bottom-color: var(--accent-2);
}

/* Action buttons on place cards — every card gets a "Search web" button so
   even entries without a curated website URL still have a path to "find out
   more". Plus Directions to Google Maps and (where available) a website link. */
.place-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 10px;
}
.place-action {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 6px 12px;
  border-radius: 999px;
  background: var(--panel);
  border: 1.5px solid var(--border-strong);
  color: var(--text);
  font-size: 12.5px;
  font-weight: 600;
  text-decoration: none;
  transition: border-color .15s, background .15s, color .15s;
}
.place-action:hover {
  border-color: var(--accent-2);
  color: var(--accent-2);
  background: var(--pill);
}
.place-action.search { color: var(--accent-2); border-color: var(--accent-2-soft); }
.place-action.directions { color: var(--accent-3); border-color: var(--accent-3-soft); }
.place-action.website { color: var(--accent-deep); border-color: var(--accent-soft); }
/* Events-here pill: only rendered when count > 0, so always actionable. */
.place-action.events-here {
  color: var(--text);
  background: var(--accent);
  border-color: var(--accent-deep);
}
.place-action.events-here:hover {
  background: #FFCB4F;
  color: var(--text);
}

/* Map popup version of the events-here link */
.popup-events-link {
  display: inline-block;
  margin-top: 10px;
  padding: 6px 12px;
  background: var(--accent);
  color: var(--text) !important;
  border-radius: 999px;
  font-weight: 700;
  font-size: 13px;
  text-decoration: none;
}
.popup-events-link:hover { background: #FFCB4F; }

/* Place pins on the map — diamond/rounded square to visually distinguish
   from circular event pins. */
.pin.place .pin-inner {
  border-radius: 6px;
  width: 24px; height: 24px;
  transform: rotate(45deg);
}
.pin.place .pin-inner > span { transform: rotate(-45deg); display: inline-block; }

/* Flagship pin overlay — small gold star on the corner of "main town park"
   type entries (vs the swing-and-slide playgrounds). Lets the map
   communicate tier at a glance. */
.pin.flagship .pin-inner {
  box-shadow: 0 0 0 3px var(--accent), 0 4px 12px rgba(20,35,60,0.25);
}
.pin .pin-star {
  position: absolute;
  top: -8px; right: -8px;
  width: 18px; height: 18px;
  background: var(--accent);
  color: var(--text);
  border-radius: 50%;
  font-size: 12px;
  font-weight: 700;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 1px 4px rgba(20,35,60,0.25);
  transform: rotate(-45deg);
}

/* Category filter strip pinned above the map. The main category chips are
   up in the filters bar, but when the user is looking at the map those are
   scrolled off-screen — so we duplicate a compact version of them here so
   filtering is always one tap away. */
.map-chip-bar {
  display: flex;
  gap: 6px;
  padding: 10px 2px;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  margin: 0 0 10px;
  scroll-padding: 8px;
}
.map-chip-bar::-webkit-scrollbar { display: none; }
.map-chip-bar .chip {
  flex-shrink: 0;
  white-space: nowrap;
}
/* Instructions helper card — now sits BELOW the map, above the category
   pills. Styled to read as friendly-but-important guidance, not throwaway
   small print. */
.map-hint {
  margin: 14px 0 4px;
  padding: 12px 13px;
  display: flex; flex-direction: column; gap: 7px;
  background: linear-gradient(180deg, color-mix(in srgb, var(--accent-2) 11%, var(--panel)), color-mix(in srgb, var(--accent-2) 4%, var(--panel)));
  border: 1.5px solid color-mix(in srgb, var(--accent-2) 32%, transparent);
  border-radius: 14px;
  color: var(--muted);
  font-size: 13.5px; font-weight: 600;
  box-shadow: 0 3px 10px rgba(46,132,189,0.12);
}
.map-hint .mh-row { display: flex; align-items: center; gap: 10px; text-align: left; line-height: 1.35; }
.map-hint .mh-ico { flex: none; width: 22px; text-align: center; font-size: 15px; }
/* The new gesture gets its own highlighted pill so it reads as "try this",
   not a footnote crammed onto the end of a sentence. */
.map-hint .mh-hero {
  padding: 9px 11px; border-radius: 11px;
  background: var(--panel);
  border: 1.5px solid color-mix(in srgb, #2F7FB6 30%, transparent);
  color: var(--muted);
}
.map-hint .mh-hero b { color: #2F7FB6; }

/* --- Weather bar (All / Sunny day / Rainy day) ----------------------------
   Sits below the map hint, above the category pills. Filters places by their
   indoor/outdoor flags: sunny = outdoor or both, rainy = indoor or both.

   Mood rule (deliberate): this bar is warm in EVERY state. In a rainy country
   a grey, cold "rainy" button quietly tells people their day is ruined, so the
   rainy option gets an umbrella, a soft sky-blue tint and the SAME warm sunlit
   card as the rest. Nothing here is grey, dark or apologetic. */
.weather-bar {
  display: flex;
  gap: 8px;
  margin: 10px 0 2px;
  padding: 7px;
  border-radius: 16px;
  background: linear-gradient(180deg, #FFF9EA, #FFF4DC);
  border: 1.5px solid color-mix(in srgb, var(--sun-hot) 34%, transparent);
  box-shadow: 0 3px 12px rgba(244,184,42,0.16);
}
.weather-bar .wx {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 10px 6px;
  border-radius: 12px;
  border: 1.5px solid transparent;
  background: rgba(255,255,255,0.55);
  color: #8A6A1E;
  font-family: inherit;
  font-size: 13.5px;
  font-weight: 800;
  line-height: 1;
  cursor: pointer;
  transition: transform .18s cubic-bezier(0.34, 1.56, 0.64, 1), background .18s ease, border-color .18s ease, box-shadow .18s ease;
}
.weather-bar .wx:hover { background: rgba(255,255,255,0.85); }
.weather-bar .wx:active { transform: scale(0.96); }
.weather-bar .wx-ico { font-size: 15px; flex: none; }
.weather-bar .wx-lbl { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Count sits quietly beside the label so the choice is informed, not a leap. */
.weather-bar .wx-n {
  flex: none;
  font-size: 11px;
  font-weight: 700;
  opacity: 0.62;
  font-variant-numeric: tabular-nums;
}
/* Selected states — sunny gets full sunlight, rainy gets a fresh sky-blue
   (still bright, still inviting), all gets the neutral warm white. */
.weather-bar .wx[aria-pressed="true"] {
  background: var(--panel);
  box-shadow: 0 3px 9px rgba(0,0,0,0.09);
}
.weather-bar .wx[data-weather="all"][aria-pressed="true"] {
  border-color: color-mix(in srgb, var(--sun-hot) 55%, transparent);
  color: #7A5B12;
}
.weather-bar .wx[data-weather="sunny"][aria-pressed="true"] {
  border-color: var(--sun-hot);
  color: #A8720A;
  background: linear-gradient(180deg, #FFFDF5, #FFF3CE);
  box-shadow: 0 3px 12px rgba(244,184,42,0.34);
}
.weather-bar .wx[data-weather="rainy"][aria-pressed="true"] {
  border-color: var(--sky);
  color: #23678F;
  background: linear-gradient(180deg, #FBFDFF, #E4F2FB);
  box-shadow: 0 3px 12px rgba(79,164,210,0.30);
}
@media (max-width: 380px) {
  .weather-bar .wx { font-size: 12.5px; padding: 9px 4px; gap: 4px; }
  .weather-bar .wx-n { display: none; }
}

/* --- Day planner / route strip -------------------------------------------
   The numbered list of stops under the map. Based on the site's own brand blue
   (#2F7FB6 / #4FA4D2) so it COMPLEMENTS the page rather than fighting it; the
   only magenta is the tiny blue→magenta gradient on the "Directions" CTA, to
   match the popup "Add to my day" button. Gradient-outline per design defaults. */
.route-strip {
  margin: 14px 0 4px;
  padding: 14px 14px 16px;
  border-radius: 16px;
  background: linear-gradient(180deg, color-mix(in srgb, #2F7FB6 9%, var(--panel)), color-mix(in srgb, #2F7FB6 4%, var(--panel)));
  border: 1.5px solid color-mix(in srgb, #2F7FB6 30%, transparent);
  box-shadow: 0 4px 14px rgba(47,127,182,0.12);
}
.route-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin-bottom: 10px;
}
.route-title { font-weight: 800; font-size: 15px; color: #2F7FB6; }
.route-count { display: block; font-weight: 600; font-size: 12.5px; color: var(--muted); margin-top: 2px; }
.route-clear {
  border: 1.5px solid color-mix(in srgb, #2F7FB6 35%, transparent);
  background: var(--panel); color: #2F7FB6;
  font-weight: 700; font-size: 13px; font-family: inherit;
  padding: 6px 14px; border-radius: 999px; cursor: pointer;
  transition: transform .18s cubic-bezier(0.34, 1.56, 0.64, 1), background .18s ease;
}
.route-clear:hover { background: color-mix(in srgb, #2F7FB6 8%, var(--panel)); transform: translateY(-1px); }
.route-head-actions { display: flex; align-items: center; gap: 8px; flex: none; }
/* Share reads as the primary action (filled), Clear stays the quiet outline. */
.route-share {
  border: 0; color: #fff; cursor: pointer;
  font-weight: 800; font-size: 13px; font-family: inherit;
  padding: 7px 15px; border-radius: 999px;
  background: linear-gradient(135deg, #2F7FB6, #4FA4D2);
  box-shadow: 0 3px 10px rgba(47,127,182,0.28);
  transition: transform .18s cubic-bezier(0.34, 1.56, 0.64, 1), filter .18s ease;
}
.route-share:hover { transform: translateY(-1px); filter: brightness(1.05); }
.route-share:active { transform: scale(0.97); }
/* Save is the quiet sibling of Share — outline, not filled. */
.route-save {
  border: 1.5px solid color-mix(in srgb, #2F7FB6 35%, transparent);
  background: var(--panel); color: #2F7FB6;
  font-weight: 700; font-size: 13px; font-family: inherit;
  padding: 6px 13px; border-radius: 999px; cursor: pointer;
  transition: transform .18s cubic-bezier(0.34, 1.56, 0.64, 1), background .18s ease;
}
.route-save:hover { background: color-mix(in srgb, #2F7FB6 8%, var(--panel)); transform: translateY(-1px); }
.route-save:active { transform: scale(0.97); }

/* Numbered stop preview inside the share dialog so the sender sees exactly
   what they're about to hand over. */
.route-share-summary {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px 6px;
  margin: 2px 0 12px; font-size: 12.5px; line-height: 1.4;
}
.route-share-summary .rss-stop {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px; border-radius: 999px;
  background: color-mix(in srgb, #2F7FB6 10%, var(--panel));
  border: 1px solid color-mix(in srgb, #2F7FB6 25%, transparent);
  color: var(--text); font-weight: 600;
}
.route-share-summary .rss-stop b {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 17px; height: 17px; padding: 0 4px; border-radius: 999px;
  background: linear-gradient(135deg, #2F7FB6, #4FA4D2); color: #fff;
  font-size: 11px; font-weight: 800;
}
.route-share-summary .rss-arrow { color: var(--muted); font-weight: 700; }
.route-share-summary .rss-label { flex-basis: 100%; font-weight: 800; color: #2F7FB6; margin-bottom: 2px; }

/* --- Days out — collections (saved + featured routes) -------------------- */
.collections { margin: 10px 0 4px; }
.col-head {
  width: 100%; display: flex; align-items: center; gap: 10px;
  padding: 11px 14px; border-radius: 12px; cursor: pointer;
  font-family: inherit; text-align: left;
  background: linear-gradient(180deg, color-mix(in srgb, #2F7FB6 8%, var(--panel)), var(--panel));
  border: 1.5px solid color-mix(in srgb, #2F7FB6 28%, transparent);
  transition: background .18s ease, transform .18s ease;
}
.col-head:hover { background: color-mix(in srgb, #2F7FB6 10%, var(--panel)); }
.col-title { font-weight: 800; font-size: 14.5px; color: #2F7FB6; }
.col-count {
  min-width: 20px; height: 20px; padding: 0 7px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 999px; background: linear-gradient(135deg, #2F7FB6, #4FA4D2);
  color: #fff; font-size: 12px; font-weight: 800;
}
.col-chev {
  margin-left: auto; width: 8px; height: 8px;
  border-right: 2px solid #2F7FB6; border-bottom: 2px solid #2F7FB6;
  transform: rotate(45deg) translateY(-2px);
  transition: transform .25s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.col-chev.open { transform: rotate(-135deg) translateY(-1px); }
.col-body { padding: 10px 2px 2px; }
.col-group-label { font-size: 12px; font-weight: 800; color: var(--muted); text-transform: uppercase; letter-spacing: .03em; margin: 8px 4px 6px; }
.col-list { list-style: none; margin: 0 0 6px; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.col-card {
  display: flex; align-items: stretch; gap: 8px;
  border-radius: 12px; background: var(--panel);
  border: 1.5px solid color-mix(in srgb, #2F7FB6 20%, transparent);
  overflow: hidden;
}
.col-main {
  flex: 1; min-width: 0; text-align: left; cursor: pointer;
  padding: 11px 12px; border: 0; background: transparent; font-family: inherit;
  transition: background .15s ease;
}
.col-main:hover { background: color-mix(in srgb, #2F7FB6 6%, var(--panel)); }
.col-name { font-weight: 700; font-size: 14px; color: var(--text); display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.col-area {
  font-size: 10.5px; font-weight: 700; color: #2F7FB6;
  padding: 2px 7px; border-radius: 999px;
  background: color-mix(in srgb, #2F7FB6 12%, var(--panel));
}
.col-meta { font-size: 12.5px; font-weight: 600; color: var(--muted); margin-top: 3px; }
.col-blurb { font-size: 12.5px; color: var(--text); opacity: .82; margin-top: 4px; line-height: 1.35; }
.col-note { display: block; font-size: 11.5px; color: var(--accent-deep); font-weight: 600; margin-top: 5px; }
.col-actions { display: flex; flex-direction: column; }
.col-share, .col-del {
  flex: 1; width: 44px; border: 0; cursor: pointer;
  font-size: 16px; font-weight: 800; font-family: inherit;
  display: flex; align-items: center; justify-content: center;
  transition: background .15s ease;
}
.col-share { background: color-mix(in srgb, #2F7FB6 12%, var(--panel)); color: #2F7FB6; }
.col-share:hover { background: color-mix(in srgb, #2F7FB6 22%, var(--panel)); }
.col-del { background: color-mix(in srgb, #C73B7A 10%, var(--panel)); color: #C73B7A; font-size: 14px; }
.col-del:hover { background: color-mix(in srgb, #C73B7A 20%, var(--panel)); }
.col-empty { font-size: 13px; color: var(--muted); margin: 4px 6px 8px; line-height: 1.4; }
/* Storage warning inside the collections panel — amber, calm, never alarming.
   Shown only while the app genuinely can't keep saves (see isThrowawayBrowser
   and storageWriteFailed in app.js). */
.col-warn {
  font-size: 13px; line-height: 1.45; margin: 4px 6px 10px; padding: 10px 12px;
  border-radius: 12px; color: var(--text);
  background: rgba(244, 184, 42, 0.14); border: 1px solid rgba(244, 184, 42, 0.42);
}
.col-warn b { font-weight: 800; }

/* "Paste a shared day" — the receiving end of a link someone sent you. Full
   width so it reads as an action of the collections panel, not a stray chip. */
.col-paste {
  display: block; width: calc(100% - 12px); margin: 10px 6px 4px;
  padding: 11px 14px; border-radius: 12px; cursor: pointer;
  font: inherit; font-size: 14px; font-weight: 700;
  color: var(--accent-2); background: var(--panel);
  border: 1px dashed var(--border);
}
.col-paste:hover { background: var(--panel-2); border-style: solid; }

.share-dialog .share-note { font-size: 12.5px; color: var(--muted-dim); margin-top: -4px; }

/* The hand-across note under the map when a shared day lands in a browser tab
   while the person may have the app installed. Amber like the storage warning,
   because it's the same family of problem: saved in the wrong place. */
.route-handoff {
  margin: 10px 0 2px; padding: 12px 14px; border-radius: 14px;
  background: rgba(244, 184, 42, 0.14); border: 1px solid rgba(244, 184, 42, 0.42);
}
.route-handoff .rh-text { font-size: 13px; line-height: 1.45; color: var(--text); }
.route-handoff .rh-actions { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.route-handoff button {
  font: inherit; font-size: 13px; font-weight: 700; cursor: pointer;
  padding: 8px 14px; border-radius: 10px; border: 1px solid var(--border);
  background: var(--panel); color: var(--accent-2);
}
.route-handoff .rh-copy { background: var(--accent-2); color: #fff; border-color: transparent; }
.route-handoff .rh-dismiss { background: transparent; color: var(--muted); border-color: transparent; }
.route-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.route-card {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 12px; border-radius: 12px;
  background: var(--panel);
  border: 1.5px solid color-mix(in srgb, #2F7FB6 20%, transparent);
  cursor: pointer;
  transition: transform .18s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow .18s ease;
}
.route-card:hover { transform: translateY(-1px); box-shadow: 0 4px 12px rgba(47,127,182,0.14); }
.route-num {
  flex: none;
  width: 26px; height: 26px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, #2F7FB6, #4FA4D2); color: #fff;
  font-weight: 800; font-size: 14px;
}
.route-name { flex: 1; font-weight: 600; font-size: 14px; color: var(--text); line-height: 1.3; }
.route-remove {
  flex: none;
  width: 28px; height: 28px; border-radius: 50%;
  border: none; background: color-mix(in srgb, #2F7FB6 12%, var(--panel));
  color: #2F7FB6; font-size: 18px; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: background .15s ease, transform .15s ease;
}
.route-remove:hover { background: color-mix(in srgb, #2F7FB6 22%, var(--panel)); transform: scale(1.08); }
.route-go {
  display: block; margin-top: 12px; padding: 13px 16px;
  border-radius: 12px; text-align: center;
  background: linear-gradient(135deg, #2F7FB6, #C73B7A); color: #fff !important;
  font-weight: 800; font-size: 15px; text-decoration: none;
  box-shadow: 0 4px 12px rgba(47,127,182,0.26);
  transition: transform .18s cubic-bezier(0.34, 1.56, 0.64, 1), filter .18s ease;
}
.route-go:hover { transform: translateY(-1px); filter: brightness(1.05); }
.route-more-hint { margin: 12px 2px 0; font-size: 12.5px; color: var(--muted); text-align: center; }

/* --- Featured place of the day -------------------------------------------
   A SLIM band directly under the header, above everything else, because half
   its job is to be found in two seconds by someone at a venue's front desk
   checking we're who we say we are. Deliberately kept shallow — it must read as
   a ribbon across the top, not a second hero pushing the real content down.
   Sun-yellow rather than the site blue so it reads as a celebration of the
   place rather than another navigation bar. Photo sits RIGHT, text LEFT. */
.featured-today {
  background: linear-gradient(180deg, color-mix(in srgb, #FFCE3D 26%, var(--panel)), color-mix(in srgb, #FFCE3D 10%, var(--panel)));
  border-bottom: 1.5px solid color-mix(in srgb, #FFCE3D 55%, transparent);
  padding: 9px 0;
  display: none;              /* Places mode only — see below */
}
/* The band belongs to PLACES, not to events. It's a place we're featuring, it
   sits above the map and the place list where it's genuinely useful, and the
   events feed stays clean. Shown at the very top of Places so it's the first
   thing anyone lands on there — including a venue checking us out. */
body.mode-places .featured-today { display: block; }
.featured-today[hidden] { display: none !important; }
.ft-card {
  display: flex; align-items: stretch; gap: 14px;
  min-height: 104px;
  padding: 10px 12px; border-radius: 14px;
  background: var(--panel);
  border: 1.5px solid color-mix(in srgb, #FFCE3D 60%, transparent);
  box-shadow: 0 3px 12px rgba(31,94,138,0.10);
  text-decoration: none; color: inherit;
  transition: transform .18s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow .18s ease;
}
a.ft-card:hover { transform: translateY(-2px); box-shadow: 0 7px 20px rgba(31,94,138,0.16); }
/* The photo STRETCHES to the full height of the card rather than sitting as a
   small landscape crop with dead space above and below it. The text decides how
   tall the band is; the photo simply fills whatever that comes to, so the venue
   gets a proper vertical showing and no space is wasted. */
.ft-photo {
  flex: none; order: 2; align-self: stretch;
  width: 132px; min-height: 100%;
  border-radius: 11px; overflow: hidden;
  background: color-mix(in srgb, #FFCE3D 20%, var(--panel));
}
.ft-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ft-text { flex: 1 1 auto; display: flex; flex-direction: column; justify-content: center; gap: 1px; min-width: 0; }
.ft-kicker {
  font-weight: 800; font-size: 10.5px; letter-spacing: 0.02em; line-height: 1.25;
  text-transform: uppercase; color: #B8860B;
}
.ft-name {
  font-family: Poppins, system-ui, sans-serif;
  font-weight: 800; font-size: clamp(18px, 4.2vw, 24px); line-height: 1.12;
  color: var(--text);
}
.ft-town { font-weight: 600; font-size: 13px; color: var(--muted); }
/* Two lines at most — a long note must never be what makes the band deep. */
.ft-note {
  margin-top: 3px; font-size: 13px; line-height: 1.4; color: var(--text);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.ft-go {
  margin-top: 6px; align-self: flex-start;
  padding: 5px 13px; border-radius: 999px;
  font-weight: 800; font-size: 12.5px; color: #fff;
  background: linear-gradient(135deg, #2F7FB6, #4FA4D2);
  box-shadow: 0 2px 8px rgba(47,127,182,0.26);
}
/* Stays a ROW on phones — stacking is what made it tower over the page. The
   photo just gets smaller. */
@media (max-width: 560px) {
  .ft-card { gap: 11px; padding: 9px 10px; }
  .ft-photo { width: 118px; border-radius: 10px; }
  .ft-note { -webkit-line-clamp: 2; font-size: 12.5px; }
}
@media (max-width: 380px) {
  .ft-photo { width: 96px; }
}
[data-theme="dark"] .featured-today {
  background: linear-gradient(180deg, #2A2208, #1E1906);
  border-bottom-color: color-mix(in srgb, #FFCE3D 35%, transparent);
}
[data-theme="dark"] .ft-kicker { color: #F0C978; }

/* The set-off row: leaving point + the two ordering buttons, sitting between
   the day's title and its stops — read before the list, which is the order you
   actually plan in ("I'm leaving Coleraine" → "so what's first?"). Gradient
   outline per the workspace default. */
.route-setoff {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  margin: 0 0 10px;
}
.route-setoff button {
  font-family: inherit; font-weight: 700; font-size: 13px;
  padding: 7px 14px; border-radius: 999px; cursor: pointer;
  border: 1.5px solid color-mix(in srgb, #2F7FB6 35%, transparent);
  background: var(--panel); color: #2F7FB6;
  transition: transform .18s cubic-bezier(0.34, 1.56, 0.64, 1), background .18s ease, filter .18s ease;
}
.route-setoff button:hover { background: color-mix(in srgb, #2F7FB6 8%, var(--panel)); transform: translateY(-1px); }
.route-setoff button:active { transform: scale(0.97); }
.rs-start { flex: 1 1 auto; text-align: left; }
.rs-start b { font-weight: 800; }
/* Unset reads as the thing to do next — filled, not outline. */
.rs-start:not(.set) {
  border-color: transparent; color: #fff;
  background: linear-gradient(135deg, #2F7FB6, #4FA4D2);
  box-shadow: 0 3px 10px rgba(47,127,182,0.26);
}
.rs-start:not(.set):hover { background: linear-gradient(135deg, #2F7FB6, #4FA4D2); filter: brightness(1.05); }
.rs-tidy { border-color: color-mix(in srgb, #C73B7A 40%, transparent); color: #C73B7A; }
.rs-tidy:hover { background: color-mix(in srgb, #C73B7A 8%, var(--panel)); }

/* A day too long for one Google Maps link, split into chained parts. */
.route-legs { margin-top: 12px; }
.route-legs-note {
  margin: 0 2px 10px; font-size: 12.5px; line-height: 1.45; color: var(--muted);
}
.route-go-part { margin-top: 8px; }
.route-go-part .rg-sub {
  display: block; margin-top: 2px;
  font-size: 12px; font-weight: 600; opacity: 0.92;
}

/* Leaving-point dialog. */
.rs-gps {
  display: block; width: 100%; margin: 4px 0 14px;
  padding: 12px 16px; border-radius: 12px; cursor: pointer;
  border: 0; color: #fff; font-family: inherit; font-weight: 800; font-size: 15px;
  background: linear-gradient(135deg, #2F7FB6, #4FA4D2);
  box-shadow: 0 4px 12px rgba(47,127,182,0.26);
  transition: transform .18s cubic-bezier(0.34, 1.56, 0.64, 1), filter .18s ease;
}
.rs-gps:hover { transform: translateY(-1px); filter: brightness(1.05); }
.rs-gps:disabled { opacity: 0.6; cursor: default; transform: none; }
.rs-loop {
  display: flex; align-items: center; gap: 9px;
  margin: 12px 0 4px; font-size: 14px; font-weight: 600; color: var(--text);
  cursor: pointer;
}
.rs-loop input { width: 18px; height: 18px; accent-color: #2F7FB6; }
.rs-clear { color: #C73B7A; }

/* "Add to my day" button inside the map popup card. Gradient-outline pill (the
   workspace design default) over a soft blue→magenta wash — it ties to both the
   brand blue and the day-planner magenta, and stands out via a coloured edge +
   lift rather than a flat fill that fought the card's greens/blues/golds. */
.route-strip .route-grip,
.popup-route { -webkit-tap-highlight-color: transparent; }
.popup-route {
  position: relative; isolation: isolate;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; margin: 4px 0 10px;
  padding: 11px 16px; border-radius: 12px; border: 0;
  background: linear-gradient(135deg, color-mix(in srgb, var(--accent-2) 11%, var(--panel)), color-mix(in srgb, var(--accent-4) 11%, var(--panel)));
  color: var(--text); font-weight: 800; font-size: 14px; font-family: inherit; letter-spacing: 0.01em;
  cursor: pointer;
  box-shadow: 0 3px 10px rgba(46,132,189,0.12);
  transition: transform .16s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow .16s ease, filter .16s ease;
}
/* Masked gradient border — blue at one corner, magenta at the other. */
.popup-route::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  border-radius: inherit; padding: 1.6px;
  background: linear-gradient(135deg, #2F7FB6, #C73B7A);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  pointer-events: none;
}
.popup-route .pr-plus {
  display: inline-flex; align-items: center; justify-content: center;
  width: 19px; height: 19px; border-radius: 50%;
  background: linear-gradient(135deg, #2F7FB6, #C73B7A); color: #fff;
  font-weight: 800; font-size: 15px; line-height: 1;
}
.popup-route:hover { transform: translateY(-1px); box-shadow: 0 6px 16px rgba(199,59,122,0.20); filter: brightness(1.01); }

/* Confirmed "in your day" state — the outline pill fills solid (blue→magenta),
   the + becomes a ✓, so tapping produces an obvious, on-brand change without
   closing the card. Tap again to remove. */
.popup-route.added {
  background: linear-gradient(135deg, #2F7FB6, #C73B7A);
  color: #fff; box-shadow: 0 5px 14px rgba(199,59,122,0.30);
}
.popup-route.added::before { opacity: 0; }
.popup-route.added .pr-plus { background: var(--panel); color: var(--accent-4); }
/* Pop on every tap so repeat toggles still register visually. */
.popup-route.pr-pop { animation: prPop .34s cubic-bezier(0.34, 1.56, 0.64, 1); }
@keyframes prPop {
  0%   { transform: scale(1); }
  40%  { transform: scale(1.06); }
  100% { transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) { .popup-route.pr-pop { animation: none; } }

/* Drag-to-reorder grip on each stop card. touch-action:none so dragging the
   handle reorders instead of scrolling the page on touch. */
.route-grip {
  flex: none; cursor: grab; touch-action: none; user-select: none;
  color: var(--muted-dim); font-size: 15px; line-height: 1;
  padding: 4px 3px; letter-spacing: -1px;
}
.route-grip:active { cursor: grabbing; }
.route-card.dragging {
  opacity: 0.92; transform: scale(1.015);
  box-shadow: 0 10px 22px rgba(47,127,182,0.22);
  border-color: color-mix(in srgb, #2F7FB6 45%, transparent);
}

/* Active-filter bar — chunky, warm, attention-catching (not an error). One
   tidy row: icon · "Showing" + tag(s) on the left, a single Clear button on
   the right, vertically centred and always aligned. */
/* Slim results toolbar — one tidy row above the list: the count + .ics on a
   quiet neutral strip, which LIGHTS UP warm (tint + pulsing dot + "Filtered"
   tag + a Show-all button) whenever a filter/preset is narrowing results.
   Proportional to the other controls; left = info, right = actions. */
.results-bar {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin: 0 0 14px; padding: 8px 10px 8px 14px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 12px;
  transition: background .2s, border-color .2s, box-shadow .2s;
}
.results-bar[hidden] { display: none !important; }
.results-bar.is-filtered {
  background: linear-gradient(180deg, var(--accent-soft), color-mix(in srgb, var(--accent) 12%, var(--panel)));
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
  box-shadow: 0 3px 12px rgba(212,154,15,0.18);
}
.results-bar .rb-left { display: flex; align-items: center; gap: 9px; min-width: 0; }
.results-bar .rb-count { font-weight: 800; font-size: 14px; color: var(--muted); white-space: nowrap; }
.results-bar.is-filtered .rb-count { color: var(--accent-deep); }
.results-bar .rb-tag {
  font-size: 10.5px; font-weight: 800; letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--accent-deep); background: var(--panel);
  border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent);
  padding: 3px 9px; border-radius: 999px; white-space: nowrap;
}
.results-bar .rb-dot {
  flex: 0 0 auto; width: 9px; height: 9px; border-radius: 50%;
  background: var(--accent-deep);
  animation: rbDotPulse 1.6s ease-in-out infinite;
}
@keyframes rbDotPulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(212,154,15,0.55); }
  50%      { box-shadow: 0 0 0 6px rgba(212,154,15,0); }
}
.results-bar .rb-right { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }
.results-bar .rb-clear {
  background: linear-gradient(135deg, #2F7FB6 0%, #2E84BD 100%); color: #fff; border: 0;
  font-family: inherit; font-weight: 700; font-size: 13px; cursor: pointer;
  padding: 8px 16px; border-radius: 999px; white-space: nowrap;
  box-shadow: 0 2px 8px rgba(46,132,189,0.30);
  transition: filter .15s, transform .12s;
}
.results-bar .rb-clear:hover { filter: brightness(1.07); transform: translateY(-1px); }
.results-bar .rb-ics {
  background: var(--panel); color: var(--accent-2); border: 1px solid var(--border-strong);
  font-family: inherit; font-weight: 700; font-size: 13px; cursor: pointer;
  padding: 8px 13px; border-radius: 999px; white-space: nowrap;
  transition: border-color .15s, color .15s;
}
.results-bar .rb-ics:hover { border-color: var(--accent-2); }
@media (prefers-reduced-motion: reduce) { .results-bar .rb-dot { animation: none; } }

/* The old inline count + .ics row in the filter panel is retired — the results
   bar above the list now carries the count, the .ics export and the filter
   notice in one place. */
.filters .count-group { display: none !important; }

/* The old inline "× Clear" link in the count row is retired — the filter bar
   above is now the single, obvious way to clear. Keeps the count row tidy. */
#clearFilters { display: none !important; }

/* On mobile, give the map a bit more headroom since the filter strip eats
   some vertical space. */
@media (max-width: 700px) {
  body.mode-places #mapCanvas { height: calc(100vh - 340px); min-height: 420px; }
}

/* …but never let it fill the screen. MapLibre takes one-finger drags to pan the
   map, which is what you want INSIDE the map — the catch is that a map taller
   than the viewport leaves nothing to scroll the PAGE with. Scroll until the map
   is all you can see and every drag pans it instead, so it reads as "the map has
   taken over and won't let go", and a reload lands you in exactly the same spot.
   Capping it keeps a strip of page in reach at all times. svh is the SMALL
   viewport (phone toolbars showing), so the cap holds in the worst case; the vh
   line above it is the fallback for browsers without svh. */
@media (pointer: coarse) {
  #mapCanvas,
  body.mode-places #mapCanvas {
    /* 75% of the screen: big enough to actually read the map, with a quarter of
       the page always left over to scroll by. Set as a HEIGHT as well as a cap,
       so the map is a consistent three-quarters on every phone rather than
       whatever the older pixel minimums happened to produce. */
    height: 75vh;
    height: 75svh;
    min-height: 280px;
    max-height: 75vh;
    max-height: 75svh;
  }
}

/* Place popups — more generous than the event popup since the description
   is the whole point (families need to know "what is this place?").
   Title is bumped to 17px/700 — the previous 14px was noticeably faded on
   mobile. */
.map-popup-place { max-width: 280px; position: relative; }
.popup-save {
  position: absolute;
  top: 0;
  right: 0;
  background: var(--panel-2);
  border: 1px solid var(--border);
  color: var(--muted);
  border-radius: 999px;
  padding: 4px 10px;
  font-size: 11.5px;
  font-weight: 700;
  cursor: pointer;
  font-family: inherit;
  letter-spacing: 0.01em;
  transition: filter .12s, background .12s, color .12s;
}
.popup-save:hover { filter: brightness(0.97); }
.popup-save.active {
  background: var(--accent-soft);
  color: var(--accent-deep);
  border-color: rgba(245,196,107,0.5);
}
.map-popup-place .popup-hero {
  display: block;
  width: calc(100% + 32px);
  height: 158px;
  object-fit: cover;
  margin: -14px -16px 12px;
  border-radius: var(--radius) var(--radius) 0 0;
  background: var(--panel-2);
}
.map-popup-place.has-hero .popup-save {
  top: 8px;
  right: 8px;
  background: rgba(0,0,0,0.55);
  color: #fff;
  border-color: rgba(255,255,255,0.25);
  backdrop-filter: blur(3px);
}
.map-popup-place strong {
  color: var(--text);
  font-size: 17px;
  font-weight: 700;
  line-height: 1.2;
  display: block;
  letter-spacing: -0.005em;
}
.map-popup-place .popup-cat {
  color: var(--accent-3);
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-top: 6px;
}
.map-popup-place p { margin: 10px 0 0; color: var(--text); font-size: 13px; line-height: 1.5; opacity: 0.9; }
.map-popup-place .popup-actions {
  display: flex; gap: 6px; margin-top: 10px; flex-wrap: wrap;
}
.map-popup-place .popup-actions a {
  display: inline-block;
  background: var(--panel-2);
  color: var(--accent);
  text-decoration: none;
  padding: 6px 10px;
  border-radius: 8px;
  font-size: 11.5px;
  font-weight: 600;
  border: 1px solid var(--border);
}
.map-popup-place .popup-actions a.primary {
  background: var(--accent-3);
  color: #052518;
  border-color: transparent;
}
.map-popup-place .popup-actions a:hover { filter: brightness(1.08); }

/* --- Centered map card -------------------------------------------------- */
/* Replaces the pin-anchored MapLibre popup for marker taps. Always opens dead
   centre so it can't generate half-clipped behind a map edge on small or
   embedded maps. Dismiss via ✕ (top-left), backdrop tap, or Escape. */
.map-card-overlay {
  position: fixed;
  inset: 0;
  z-index: 1200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(8, 14, 20, 0.55);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  animation: mapCardFade .14s ease;
}
.map-card-overlay[hidden] { display: none; }
@keyframes mapCardFade { from { opacity: 0; } to { opacity: 1; } }
.map-card-shell {
  position: relative;
  width: 320px;
  max-width: calc(100vw - 40px);
  max-height: calc(100vh - 40px);
  overflow: auto;
  animation: mapCardPop .18s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes mapCardPop { from { transform: scale(0.94); } to { transform: scale(1); } }
.map-card-body {
  background: var(--panel-3);
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  box-shadow: 0 18px 52px rgba(0, 0, 0, 0.6);
  padding: 14px 16px;
  font-size: 13px;
  line-height: 1.45;
}
/* In the centered card the width is the shell's, not the popup's 280px cap. */
.map-card-body .map-popup-place,
.map-card-body .map-popup { max-width: none; }
.map-card-close {
  position: absolute;
  top: 8px;
  left: 8px;
  z-index: 5;
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.25);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  font-family: inherit;
  transition: filter .12s;
}
.map-card-close:hover { filter: brightness(1.15); }

/* --- Admin mode --------------------------------------------------------- */
body:not(.admin-mode) .admin-only { display: none; }
body.admin-mode header::after {
  content: 'ADMIN';
  position: absolute;
  top: 8px; right: 12px;
  background: #ff7a7a;
  color: #1a0505;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  padding: 3px 8px;
  border-radius: 999px;
  z-index: 50;
}
.iconbtn.ban {
  color: #ff8585;
  border-color: rgba(255,133,133,0.35);
}
.iconbtn.ban:hover {
  background: rgba(255,133,133,0.12);
  border-color: #ff8585;
}
/* Toast action button — used for the Undo on ban. Inline with the toast
   text, tappable on mobile, doesn't look like a warning. */
.toast-action {
  background: rgba(95,209,255,0.2);
  color: var(--accent);
  border: 1px solid rgba(95,209,255,0.45);
  padding: 4px 12px;
  border-radius: 6px;
  font-size: 13px;
  font-weight: 700;
  font-family: inherit;
  cursor: pointer;
  margin-left: 4px;
}
.toast-action:hover { background: rgba(95,209,255,0.3); }

/* Removed-events dialog list — compact rows, one Restore button each. */
.bans-list {
  list-style: none; padding: 0; margin: 10px 0 0;
  display: flex; flex-direction: column; gap: 6px;
}
.bans-list li {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 10px;
}
.bans-title {
  color: var(--text); font-weight: 600; font-size: 14px; line-height: 1.3;
  grid-column: 1;
  /* Long titles should wrap, not clip, so admin can recognise the event. */
  word-wrap: break-word;
}
.bans-meta {
  grid-column: 1;
  color: var(--muted-dim); font-size: 11.5px;
}
.bans-unban {
  grid-column: 2; grid-row: 1 / span 2;
  background: var(--accent-3); color: #052518;
  border: 0; padding: 8px 14px;
  border-radius: 8px; font-size: 13px; font-weight: 700;
  font-family: inherit; cursor: pointer;
}
.bans-unban:hover { filter: brightness(1.06); }

.bans-dialog { max-width: 540px; }

/* --- Event details modal (tap-to-learn-more) --------------------------- */
/* Native <dialog> defaults to position:absolute, which means on a long
   scrolled page the dialog renders relative to the document — users then
   see a dark backdrop but have to scroll to find the actual box. Force
   viewport-fixed centering + bound height + internal scroll so only the
   dialog content ever scrolls, never the page behind it. */
.event-dialog {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  margin: 0;
  max-width: 560px;
  width: 92%;
  max-height: min(85vh, 85dvh);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  background: var(--gradient-card); color: var(--text);
  border: 1px solid var(--border-strong); border-radius: var(--radius-lg);
  padding: 28px 26px 22px; box-shadow: 0 40px 100px rgba(0,0,0,0.75);
}
.event-dialog::backdrop { background: rgba(3, 10, 18, 0.74); backdrop-filter: blur(6px); }
/* Stop the page underneath from scrolling while the dialog is open.
   Belt-and-braces: <dialog>.showModal() is supposed to do this, but iOS
   Safari sometimes lets the body scroll anyway. */
body:has(.event-dialog[open]) { overflow: hidden; }

/* On narrow phones, tighten inner padding and allow a wider relative
   width, but keep the dialog centered in the viewport rather than
   anchored to the bottom — middle of the screen reads as "this is the
   important thing right now" more clearly than a bottom sheet does. */
@media (max-width: 600px) {
  .event-dialog {
    width: 94%;
    padding: 22px 20px 18px;
  }
  .event-dialog h2 { font-size: 19px; }
}
.event-dialog .dialog-close {
  position: absolute; top: 10px; right: 12px; z-index: 3;
  background: color-mix(in srgb, var(--panel) 86%, transparent); border: 0; color: var(--text);
  font-size: 18px; cursor: pointer; width: 34px; height: 34px; padding: 0;
  border-radius: 50%; display: flex; align-items: center; justify-content: center;
  box-shadow: 0 2px 8px rgba(0,0,0,0.18);
}
.event-dialog .dialog-close:hover { color: var(--text); background: var(--panel); }
/* Full-bleed hero photo at the top of the detail dialog — same image the
   feed card shows. Bleeds to the dialog edges and rounds the top corners. */
.event-dialog-hero {
  display: block;
  width: calc(100% + 52px);
  margin: -28px -26px 18px;
  height: 220px; object-fit: cover;
  background: var(--panel-2);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}
@media (max-width: 600px) {
  .event-dialog-hero { width: calc(100% + 40px); margin: -22px -20px 16px; height: 180px; }
}
.event-dialog-head { padding-right: 30px; }
.event-dialog-date {
  color: var(--accent-2);
  font-size: 12.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.06em;
  margin-bottom: 6px;
}
.event-dialog h2 {
  margin: 0 0 8px;
  font-size: 22px; font-weight: 700; line-height: 1.2;
  letter-spacing: -0.01em; color: var(--text);
}
.event-dialog-loc {
  color: var(--muted); font-size: 13.5px; line-height: 1.4;
  margin-bottom: 12px;
}
.event-dialog .pills { margin: 0 0 14px; display: flex; flex-wrap: wrap; gap: 4px; }
.event-dialog-desc {
  margin: 0 0 16px; color: var(--text); font-size: 15px;
}
.event-dialog-desc.muted { color: var(--muted); font-style: italic; }

/* Prose — the shared body-copy rhythm used wherever we render paragraphs of
   description text. Comfortable line-height, a capped measure so lines don't
   run too wide to track, and clear breathing room between paragraphs. Reuse
   this class anywhere long copy is shown so spacing stays consistent. */
.prose { line-height: 1.68; max-width: 68ch; }
.prose p { margin: 0 0 0.95em; }
.prose p:last-child { margin-bottom: 0; }
.prose p:first-child { margin-top: 0; }
.event-dialog-actions {
  display: flex; flex-wrap: wrap; gap: 8px;
  padding-top: 12px; border-top: 1px solid var(--border);
}
.event-dialog-actions a {
  display: inline-flex; align-items: center; gap: 4px;
  background: var(--panel-2); color: var(--accent);
  text-decoration: none; padding: 9px 14px;
  border-radius: 10px; font-size: 13px; font-weight: 600;
  border: 1px solid var(--border);
}
.event-dialog-actions a.primary {
  background: var(--accent); color: #051d2b; border-color: transparent;
}
.event-dialog-actions a:hover { filter: brightness(1.08); transform: translateY(-1px); }
.event-dialog-hint {
  margin: 12px 0 0; font-size: 12px; color: var(--muted-dim);
  padding: 10px 12px; background: rgba(123,240,177,0.06);
  border: 1px solid rgba(123,240,177,0.18); border-radius: 8px;
}

/* Cue that the whole card is tappable on mobile. */
.event { cursor: pointer; }
.event .event-actions button, .event a { cursor: pointer; }

/* ===== Days Out NI brand — Poppins + Inter ===== */
body{font-family:'Inter',system-ui,-apple-system,BlinkMacSystemFont,'Helvetica Neue',Arial,sans-serif}
h1,h2,h3,h4{font-family:'Poppins',system-ui,sans-serif;font-weight:800}

#addPosterBtn{display:none!important}  /* submit-event hidden for launch */

/* ===================================================================
   COLLAPSIBLE FILTER PANEL
   The when/where/search fields, the toggle chips and the category pills
   all sit behind one "Filters" button now, and the panel opens CLOSED.
   Rationale: filtering is a NARROWING action and you can't narrow what
   you haven't seen yet — a first-timer needs Top picks above the fold,
   not sixteen category pills. Regulars pay one tap, and the open/closed
   choice is remembered per device.
   =================================================================== */
/* nowrap so the hint sits in the dead space to the RIGHT of the button and
   shrinks (ellipsis) rather than dropping to its own line. Only the button +
   hint share this row in Events/Classes; Places shows just the centred view
   toggle — nowrap is safe for both. */
.filterbar { display: flex; align-items: center; gap: 10px; flex-wrap: nowrap; }
body.mode-places .filterbar { justify-content: center; }

.filters-toggle {
  position: relative;
  flex: 0 0 auto;   /* keep full size; the hint beside it does the shrinking */
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 16px;
  border: 0;
  border-radius: 999px;
  background: var(--panel-2);
  color: var(--text);
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background .18s ease, transform .18s cubic-bezier(0.34, 1.56, 0.64, 1);
}
/* Masked gradient outline — the house treatment for tappable surfaces. */
.filters-toggle::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1.5px;
  background: var(--gradient-accent);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  pointer-events: none;
}
.filters-toggle:hover { background: var(--panel-3); }
.filters-toggle:active { transform: scale(0.97); }
.filters-toggle:focus-visible { outline: 0; box-shadow: var(--ring); }

/* Self-explaining hint that fills the empty bar space beside the button.
   Reads as a quiet caption, but the whole strip is tappable and opens the
   panel — so a newcomer who reads "narrow by date, town…" and taps lands
   exactly where they need to be. */
.filters-hint {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 0 6px 0 2px;
  border: 0;
  background: transparent;
  color: var(--muted);
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 500;
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.filters-hint .fh-text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.filters-hint .fh-cue {
  margin-left: auto;
  flex: none;
  color: var(--accent-deep);
  font-weight: 600;
  white-space: nowrap;
}
.filters-hint .fh-cue::after {
  content: ' ‹';
  font-weight: 700;
}
.filters-hint:hover { color: var(--text); }
body.mode-places .filters-hint { display: none; }
body.filters-open .filters-hint { display: none; }
/* On the tightest phones, drop the descriptive text and keep just the cue so
   the row never wraps or crowds the button. */
@media (max-width: 400px) {
  .filters-hint .fh-text { display: none; }
  .filters-hint .fh-cue { margin-left: 10px; }
}

/* First-visit nudge: a soft gold breath that draws the eye to the one control
   that unlocks the whole site. Removed for good the moment the user opens the
   panel once (see app.js), and silenced for reduced-motion. */
@keyframes ft-attention {
  0%, 100% { box-shadow: 0 0 0 0 rgba(244, 184, 42, 0); }
  50%      { box-shadow: 0 0 0 7px rgba(244, 184, 42, 0.22); }
}
.filters-toggle.needs-attention { animation: ft-attention 1.9s ease-in-out infinite; }
.filters-hint.needs-attention .fh-cue { animation: fh-cue-breathe 1.9s ease-in-out infinite; }
@keyframes fh-cue-breathe {
  0%, 100% { opacity: 0.55; }
  50%      { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .filters-toggle.needs-attention,
  .filters-hint.needs-attention .fh-cue { animation: none; }
}
.ft-ico { font-size: 15px; line-height: 1; }
.ft-chev {
  width: 7px; height: 7px;
  border-right: 2px solid var(--muted);
  border-bottom: 2px solid var(--muted);
  transform: rotate(45deg) translateY(-2px);
  transition: transform .28s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.filters-toggle[aria-expanded="true"] .ft-chev { transform: rotate(-135deg) translateY(-2px); }

/* Live count of what's narrowing the list right now, so a closed panel can
   never quietly explain away a short result list. */
.ft-count {
  min-width: 20px; height: 20px; padding: 0 6px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 999px;
  background: var(--gradient-accent);
  color: #4A3400;
  font-size: 11.5px; font-weight: 700; font-style: normal;
}

/* 0fr → 1fr lets the browser measure the height for us — no JS height maths,
   and it keeps working when the category pills re-render at any moment. */
.filter-panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows .3s ease;
}
.filter-panel.open { grid-template-rows: 1fr; }
.filter-panel > .fp-inner { overflow: hidden; min-height: 0; }

@media (prefers-reduced-motion: reduce) {
  .filter-panel, .ft-chev { transition: none; }
}

/* Places mode hides the When field, the toggle chips and the count group, so
   the panel collapses down to roughly the height of the button that hides it —
   the toggle buys no space and just adds a tap. Filters stay open here. */
body.mode-places .filters-toggle { display: none; }
body.mode-places .filter-panel { grid-template-rows: 1fr; }

/* --- Search clear (X) ---------------------------------------------------
   type="search" gets a native clear button on desktop WebKit but nothing on
   iOS, and it never matches the app's look. Suppress the native one and draw
   our own so the behaviour is identical everywhere. */
.search-wrap { position: relative; display: block; }
.search-wrap > input[type="search"] { width: 100%; padding-right: 38px; }
.search-wrap > input[type="search"]::-webkit-search-cancel-button,
.search-wrap > input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; appearance: none; }
.q-clear {
  position: absolute; top: 50%; right: 6px; transform: translateY(-50%);
  width: 28px; height: 28px; display: grid; place-items: center;
  padding: 0; border: 0; border-radius: 50%;
  background: var(--panel-3, #EDF2F8); color: var(--ink-2, #56657a);
  cursor: pointer; line-height: 0;
  transition: background .15s ease, color .15s ease, transform .15s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.q-clear svg { width: 14px; height: 14px; }
.q-clear:hover, .q-clear:focus-visible { background: var(--accent, #5FB1DD); color: #fff; transform: translateY(-50%) scale(1.08); }
.q-clear[hidden] { display: none; }

/* Title only appears when the dialog is sharing a list, not the whole app. */
.share-dialog-title { margin: 0 0 12px; font-size: 19px; font-weight: 800; }
.share-dialog-title[hidden] { display: none; }

/* Title only appears when the dialog is sharing a list, not the whole app. */
.share-dialog-title { margin: 0 0 12px; font-size: 19px; font-weight: 800; }
.share-dialog-title[hidden] { display: none; }

/* --- "Share this list" ---------------------------------------------------
   Its own button on its own line, between the results box and the first
   result. Deliberately NOT inside the results box — bolting it on stretched
   that box and read as a footnote to the count rather than an action. */
.share-list-bar { margin: -4px 0 14px; }
.share-list-bar[hidden] { display: none !important; }
.share-list-btn {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 9px 17px; border-radius: 999px;
  font: inherit; font-size: 13.5px; font-weight: 800;
  color: var(--accent-deep); background: var(--panel);
  border: 1px solid color-mix(in srgb, var(--accent) 50%, transparent);
  box-shadow: 0 2px 9px rgba(212,154,15,0.15);
  cursor: pointer; white-space: nowrap;
  transition: transform .15s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow .15s ease, background .15s ease;
}
.share-list-btn svg { width: 15px; height: 15px; }
.share-list-btn:hover, .share-list-btn:focus-visible {
  transform: translateY(-1px) scale(1.02);
  box-shadow: 0 6px 16px rgba(212,154,15,0.25);
  background: var(--accent-soft, var(--panel-2));
}

/* --- "Share this list" ---------------------------------------------------
   Rides the right-hand end of the first section heading ("⭐ Best play parks
   35") instead of taking a row of its own — a row pushed the first photo
   further down the screen for a button most people tap once.
   .daygroup h2 is already display:flex, so margin-left:auto parks it right. */
.daygroup h2 .share-list-btn {
  margin-left: auto;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 12px; border-radius: 999px;
  font: inherit; font-size: 11px; font-weight: 800;
  letter-spacing: 0.04em; text-transform: none;
  color: var(--accent-deep); background: var(--panel);
  border: 1px solid color-mix(in srgb, var(--accent) 50%, transparent);
  cursor: pointer; white-space: nowrap; align-self: center;
  transition: transform .15s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow .15s ease, background .15s ease;
}
.daygroup h2 .share-list-btn svg { width: 12px; height: 12px; }
.daygroup h2 .share-list-btn:hover,
.daygroup h2 .share-list-btn:focus-visible {
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(212,154,15,0.22);
  background: var(--accent-soft, var(--panel-2));
}
/* Narrow phones: keep the icon, drop the words rather than wrap the heading. */
@media (max-width: 400px) {
  .daygroup h2 .share-list-btn span { display: none; }
  .daygroup h2 .share-list-btn { padding: 5px 8px; }
}

/* "Play park on site" — the one fact a parent scans for. Given the play-park
   green so it reads as the same thing as the play-park pins on the map. */
.pill.playpark {
  background: color-mix(in srgb, #a0e85c 22%, var(--panel));
  border-color: color-mix(in srgb, #a0e85c 60%, transparent);
  color: var(--ink, #24333f); font-weight: 700;
}

/* "Has a play park" chip — rides at the end of the category pills. Dashed like
   the other opt-in layers so it reads as a power-user extra, not a category. */
.chip.chip-playpark { --chip-color: #a0e85c; }

/* ODbL requires the OpenStreetMap credit on the map, so it can't be removed —
   and MapLibre deliberately re-asserts it if you collapse it. Made as quiet as
   it can honestly be instead: small, half opacity, no box, no ⓘ button. */
#mapCanvas .maplibregl-ctrl-attrib {
  font-size: 9px; line-height: 1.3; padding: 0 5px; margin: 0 0 2px 2px;
  background: none; opacity: .5;
}
#mapCanvas .maplibregl-ctrl-attrib a { text-decoration: none; }
#mapCanvas .maplibregl-ctrl-attrib-button { display: none; }
