: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;
}

* { 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;
}
::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: #1A2233;
  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; }

.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: #FFFFFF;
  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: #FFFFFF; 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: #FFFFFF; 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); }
.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; }
.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; }

.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: #1A2233;
  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: #FFFFFF;
  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: #FFFFFF; border-color: var(--accent-2-soft); }
.event .pill.cat {
  color: var(--cat-color);
  background: #FFFFFF;
  border-color: color-mix(in srgb, var(--cat-color) 38%, transparent);
  font-weight: 700;
}
.event .pill.ongoing { color: var(--muted); background: #FFFFFF; border-color: var(--border-strong); }
.event .pill.age { color: var(--accent-4); background: #FFFFFF; border-color: color-mix(in srgb, var(--accent-4) 32%, transparent); }
.event .pill.family { color: var(--accent-3); background: #FFFFFF; border-color: color-mix(in srgb, var(--accent-3) 38%, transparent); }
.event .pill.big { color: var(--accent-deep); background: #FFFFFF; border-color: color-mix(in srgb, var(--accent) 50%, transparent); font-weight: 700; }
.event .pill.estate { color: #6840BD; background: #FFFFFF; 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: #FFFFFF; border-color: color-mix(in srgb, var(--accent-3) 45%, transparent); font-weight: 700; }
.event .pill.price { color: var(--muted); background: #FFFFFF; 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%, #fff),
    color-mix(in srgb, var(--cat-color) 8%, #fff));
  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: #1A2233;
  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; }

.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: #1A2233;
}
.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: #1A2233;
  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;
}

.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: #1A2233;
  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: #1A2233;
  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: #FFFFFF;
  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: #1A2233;
  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, #ffffff 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: #fff;
}
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: #1A2233;
  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: #FFFFFF;
  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: #FFFFFF;
  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: #1A2233;
  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 #presetBig    { 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: #FFFFFF;
  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: #fff; 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; }

/* --- 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 #presetBig,
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: #1A2233;
  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 #presetBig,
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: #1A2233;
  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%, #fff),
    color-mix(in srgb, var(--cat-color) 9%, #fff));
}
.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: rgba(255,255,255,0.92); 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: #fff; 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);
}
.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: #1A2233; font-size: 15px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.24);
}

.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; }

.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%, #fff); 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%, #fff); 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;
}

/* 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: #1A2233;
  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: #FFFFFF;
  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: #1A2233;
  background: var(--accent);
  border-color: var(--accent-deep);
}
.place-action.events-here:hover {
  background: #FFCB4F;
  color: #1A2233;
}

/* Map popup version of the events-here link */
.popup-events-link {
  display: inline-block;
  margin-top: 10px;
  padding: 6px 12px;
  background: var(--accent);
  color: #1A2233 !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: #1A2233;
  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;
}
.map-hint {
  margin: 0 0 8px;
  padding: 8px 12px;
  background: rgba(123,240,177,0.08);
  border: 1px solid rgba(123,240,177,0.2);
  border-radius: 10px;
  color: var(--accent-3);
  font-size: 12.5px;
  text-align: center;
}

/* 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; }
}

/* 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;
  background: transparent; border: 0; color: var(--muted);
  font-size: 20px; cursor: pointer; padding: 6px 10px; border-radius: 8px;
}
.event-dialog .dialog-close:hover { color: var(--text); background: var(--panel-2); }
.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: #ffffff;
}
.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); line-height: 1.55; font-size: 14px;
}
.event-dialog-desc.muted { color: var(--muted); font-style: italic; }
.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 */
