Event essentials

Content stays in the Event Info Source. Native disclosures work without JavaScript; search opens matching topics. Keep source provenance in docs/event-info-sources.md.

<section class="event-info">
  <header class="info-search">
    <label class="search-field">
      <icp-search />
      <input
        type="search"
        data-info-search
        placeholder="Search event info"
        aria-label="Search event information"
      />
    </label>
  </header>
  <slot />
  <p data-info-empty hidden>No matching information.</p>
</section>
.event-info {
  max-width: 820px;
  margin: 16px auto 0;
}
.info-search {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--paper);
  padding: 8px 0;
}
.info-search .search-field {
  width: 100%;
  margin: 0;
}
.info-search input {
  font-size: 16px;
}
.event-info h1 {
  font-size: 26px;
  margin: 20px 0 6px;
}
.event-info .info-address {
  font-size: 14px;
  margin-bottom: 16px;
}
.event-info .info-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 16px 0 24px;
}
.event-info .info-actions a {
  text-decoration: none;
  display: inline-flex;
  gap: 8px;
  align-items: center;
  border: 1px solid var(--line);
  border-radius: 7px;
  min-height: 44px;
  padding: 8px 12px;
  font-size: 13px;
}
.event-info details {
  border-top: 1px solid var(--line);
  padding: 4px 0;
  scroll-margin-top: 80px;
}
.event-info summary {
  cursor: pointer;
  padding: 16px 0;
  font-size: 17px;
  font-weight: 500;
}
.event-info details > :not(summary) {
  margin: 0 0 16px;
  font-size: 14px;
  line-height: 1.65;
}
.event-info ul {
  padding-left: 20px;
}
.event-info li {
  margin: 8px 0;
}
.event-info a {
  text-decoration: underline;
  text-underline-offset: 3px;
}
.event-info img {
  display: block;
  width: 100%;
  height: auto;
}
.event-info .info-updated {
  margin-top: 22px;
  font-size: 11px;
  color: #61756a;
}
.event-info [hidden] {
  display: none !important;
}
const input = el.querySelector("[data-info-search]")
const topics = [...el.querySelectorAll("details[data-info-topic]")]
let previous
function openLinkedTopic() {
  const topic = topics.find(topic => "#" + topic.id === location.hash)
  if (topic) {
    topic.hidden = false
    topic.open = true
    requestAnimationFrame(() => topic.scrollIntoView({ block: "start" }))
  }
}
openLinkedTopic()
on(window, "hashchange", openLinkedTopic)
on(input, "input", () => {
  const query = input.value.trim().toLowerCase()
  if (query && !previous) previous = topics.map((topic) => topic.open)
  let matches = 0
  topics.forEach((topic, index) => {
    topic.hidden = !!query && !topic.textContent.toLowerCase().includes(query)
    if (!topic.hidden) matches++
    if (query) topic.open = !topic.hidden
    else if (previous) topic.open = previous[index]
  })
  if (!query) previous = undefined
  el.querySelector("[data-info-empty]").hidden = matches > 0
})