:root {
  --violet: #7c3aed;
  --violet-dark: #6d28d9;
  --violet-light: #9f67ff;
  --violet-pale: #c4b5fd;
  --tint: #f5f1fe;
  --tint-bg: #f8f6fd;
  --ink: #16181d;
  --gray: #6b7280;
  --border: #edeaf5;
  /* Status colours — the public counterparts of admin.css's --ok-fg/--danger-fg/--warn-fg/--info-fg, so a success toast is the same
     green on the site as it is in the admin. */
  --ok-fg: #0b7a3b;
  --danger-fg: #c02626;
  --warn-fg: #b25e09;
  --info-fg: #2563eb;
  --surface: #ffffff;
}
* {
  box-sizing: border-box;
}
/* Sticky footer. Without this a short page (booking-lookup's "Find my tickets",
   a 404, an empty list) left the footer floating mid-screen with blank space
   below it. The footer is the last flex child and `margin-top:auto` pushes it
   to the bottom whenever the content is shorter than the viewport. */
body {
  margin: 0;
  font-family: "Familjen Grotesk", sans-serif;
  color: var(--ink);
  background: #fff;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
}
body > .footer {
  margin-top: auto;
}
/* Direct children of a flex body are FLEX ITEMS, so they shrink to their content
   instead of filling the row — a `.container` with `max-width` + `margin:0 auto`
   then centres itself, which is what shrank the event-detail breadcrumb to 510px
   and made it look centred. Forcing full width keeps normal block behaviour
   while the sticky footer still works. */
body > * {
  width: 100%;
  flex-shrink: 0;
}
body > .nav,
body > .footer {
  flex: none;
}
h1,
h2,
h3,
.display {
  font-family: "Bricolage Grotesque", sans-serif;
  letter-spacing: -0.03em;
}
a {
  color: var(--violet);
  text-decoration: none;
}
a:hover {
  color: var(--violet-dark);
}
/* --gutter is the page's horizontal breathing room. Vertical padding on a
   .container MUST be written as padding-block (or padding-top/bottom) — using
   the `padding` shorthand silently resets left/right to 0 and slams the content
   against the screen edge, which is exactly what happened to every hero. */
:root {
  --gutter: clamp(16px, 5vw, 32px);
}
.container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 var(--gutter);
}
.btn {
  display: inline-block;
  border-radius: 11px;
  font-weight: 700;
  padding: 15px 32px;
  font-size: 15px;
  border: none;
  cursor: pointer;
  font-family: inherit;
}
.btn-primary {
  background: var(--violet);
  color: #fff;
}
.btn-primary:hover {
  background: #8b4df7;
  color: #fff;
}
.btn-outline {
  border: 1px solid rgba(255, 255, 255, 0.25);
  color: #fff;
}
.btn-outline:hover {
  border-color: var(--violet-light);
  color: var(--violet-pale);
}
.btn-ghost {
  background: var(--tint);
  color: var(--violet);
}
.btn-sm {
  padding: 10px 20px;
  border-radius: 9px;
  font-size: 14px;
  font-weight: 600;
}
.nav {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid #f0edf7;
}
.nav-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-top: 10px;
  padding-bottom: 10px;
}
.nav-links {
  display: flex;
  align-items: center;
  gap: 28px;
  font-size: 14px;
  font-weight: 500;
}
.nav-links a {
  color: var(--ink);
}
.nav-links a.active {
  color: var(--violet);
  font-weight: 700;
}
.nav-links a.muted {
  color: var(--gray);
}
.logo {
  font-family: "Bricolage Grotesque", sans-serif;
  font-size: 19px;
  font-weight: 800;
  color: var(--ink);
  letter-spacing: -0.03em;
  line-height: 1;
  display: flex;
  align-items: center;
}
.logo-dial {
  position: relative;
  display: inline-flex;
  width: 0.92em;
  height: 0.92em;
  margin: 0 0.03em;
}
.logo-dial svg {
  position: absolute;
  width: 100%;
  height: 100%;
}
.logo-360 {
  font-size: 0.62em;
  font-weight: 700;
  color: var(--violet);
  margin-left: 0.08em;
  align-self: flex-start;
  margin-top: -0.1em;
}
.logo-360.light {
  color: var(--violet-light);
}
.logo-dark {
  color: #fff;
}
.hero {
  background: linear-gradient(175deg, #16181d 0%, #241536 55%, #4c1d95 100%);
  color: #fff;
  overflow: hidden;
  position: relative;
}
.hero-dial {
  position: absolute;
  right: -200px;
  top: -160px;
  opacity: 0.14;
  width: 720px;
  height: 720px;
}
.hero-inner {
  padding-block: clamp(32px, 5vw, 56px) clamp(28px, 4vw, 48px);
  position: relative;
}
.pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: rgba(159, 103, 255, 0.15);
  border: 1px solid rgba(159, 103, 255, 0.4);
  border-radius: 100px;
  padding: 7px 16px;
  font-size: 13px;
  color: var(--violet-pale);
  margin-bottom: 20px;
}
.pill .dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--violet-light);
}
.hero h1 {
  font-size: clamp(32px, 6vw, 58px);
  font-weight: 800;
  letter-spacing: -0.04em;
  line-height: 1.04;
  margin: 0 0 16px;
  max-width: 20ch;
  text-wrap: balance;
}
.hero .accent {
  color: var(--violet-light);
}
.hero p {
  font-size: clamp(15px, 2vw, 19px);
  line-height: 1.55;
  color: rgba(255, 255, 255, 0.72);
  max-width: 52ch;
  margin: 0 0 clamp(20px, 3vw, 30px);
}
.hero-ctas {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
}
/* Hero stats: one compact inline run. Four large stat blocks shouting single
   digits looked weak on a young platform, so the figures sit at text size and
   read as a sentence of live activity. */
.hero-stats {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 22px;
  margin: clamp(22px, 3vw, 34px) 0 0;
  padding-top: clamp(16px, 2.2vw, 22px);
  border-top: 1px solid rgba(255, 255, 255, 0.12);
}
.hero-stat {
  display: flex;
  align-items: baseline;
  gap: 6px;
}
.hero-stat-num {
  margin: 0;
  font-family: "Bricolage Grotesque", sans-serif;
  font-size: clamp(16px, 1.8vw, 19px);
  font-weight: 800;
  color: #fff;
  letter-spacing: -0.02em;
}
.hero-stat-lbl {
  margin: 0;
  font-size: clamp(13px, 1.5vw, 14.5px);
  color: rgba(255, 255, 255, 0.55);
}
/* The old .stats block is kept for the about page's own stat row. */
.stats {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(20px, 4vw, 44px);
  margin-top: clamp(26px, 3.4vw, 44px);
  padding-top: clamp(18px, 2.4vw, 26px);
  border-top: 1px solid rgba(255, 255, 255, 0.12);
}
.stats .num {
  font-family: "Bricolage Grotesque", sans-serif;
  font-size: clamp(22px, 3.4vw, 32px);
  font-weight: 800;
  line-height: 1.1;
}
.stats .lbl {
  font-size: clamp(11.5px, 1.4vw, 13px);
  color: rgba(255, 255, 255, 0.5);
  line-height: 1.3;
}
.section {
  padding-block: clamp(40px, 6vw, 76px);
}
.section-tint {
  background: var(--tint-bg);
}
/* Section padding modifiers, so pages stop hardcoding inline pixel padding
   (which cannot scale on a phone). Compose them: class="section is-tight". */
.section.is-tight {
  padding-block: clamp(26px, 3.4vw, 44px);
}
.section.is-tight-top {
  padding-top: clamp(26px, 3.4vw, 44px);
}
.section.is-flush-top {
  padding-top: 0;
}
.section.is-flush-bottom {
  padding-bottom: 0;
}
.kicker {
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--violet);
  font-weight: 700;
  margin: 0 0 12px;
}
.h2 {
  font-size: clamp(24px, 3.8vw, 38px);
  font-weight: 800;
  line-height: 1.12;
  letter-spacing: -0.03em;
  margin: 0 0 clamp(20px, 3vw, 36px);
  text-wrap: balance;
}
/* --cols lets a caller cap the track count when it has fewer items than 3,
   so one card does not stretch across a third of the page beside two empty
   columns. Defaults to 3 when unset. */
.grid-3 {
  display: grid;
  grid-template-columns: repeat(var(--cols, 3), minmax(0, 1fr));
  gap: 24px;
}
.grid-feat {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}
.card {
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 28px;
  background: #fff;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.card:hover {
  border-color: var(--violet-pale);
  box-shadow: 0 8px 24px rgba(124, 58, 237, 0.08);
}
.card .glyph {
  width: 40px;
  height: 40px;
  border-radius: 10px;
  background: var(--tint);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--violet);
  font-family: "Bricolage Grotesque", sans-serif;
  font-weight: 800;
  font-size: 15px;
}
.card h3 {
  font-size: 17px;
  margin: 0;
  font-family: "Familjen Grotesk", sans-serif;
  letter-spacing: 0;
}
.card p {
  font-size: 14px;
  line-height: 1.55;
  color: var(--gray);
  margin: 0;
}
.card-cta {
  border-radius: 14px;
  padding: 28px;
  background: var(--violet);
  color: #fff;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 16px;
}
.card-cta a {
  color: #fff;
  font-weight: 700;
  font-size: 14px;
}
.step {
  background: #fff;
  border-radius: 14px;
  padding: 32px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.step .num {
  font-family: "Bricolage Grotesque", sans-serif;
  font-size: 40px;
  font-weight: 800;
  color: var(--violet-pale);
  line-height: 1;
}
.dark-section {
  background: var(--ink);
  color: #fff;
}
.quote {
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 14px;
  padding: 28px;
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.quote p {
  font-size: 15px;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.85);
  margin: 0;
}
.avatar {
  width: 36px;
  height: 36px;
  border-radius: 10px;
  background: var(--violet);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 13px;
}
.plan {
  border: 1px solid var(--border);
  border-radius: 18px;
  padding: 36px;
  display: flex;
  flex-direction: column;
  gap: 22px;
  background: #fff;
  position: relative;
}
.plan.featured {
  border-color: var(--violet);
  background: var(--ink);
  color: #fff;
}
.plan .badge {
  position: absolute;
  top: -12px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--violet-light);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  padding: 5px 14px;
  border-radius: 100px;
  letter-spacing: 0.06em;
}
.plan .price {
  font-family: "Bricolage Grotesque", sans-serif;
  font-size: clamp(30px, 4.4vw, 42px);
  font-weight: 800;
  line-height: 1.05;
}
.plan .per {
  font-size: 14px;
  opacity: 0.6;
}
.plan ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 11px;
  font-size: 14px;
  flex: 1;
}
.plan li::before {
  content: "✓";
  color: var(--violet-light);
  font-weight: 800;
  margin-right: 9px;
}
faq-x {
  display: none;
}
details {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 20px 24px;
}
details summary {
  font-size: 16px;
  font-weight: 700;
  cursor: pointer;
  list-style: none;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
details summary::-webkit-details-marker {
  display: none;
}
details summary::after {
  content: "+";
  color: var(--violet);
  font-size: 20px;
}
details[open] summary::after {
  content: "–";
}
details div {
  font-size: 14px;
  line-height: 1.6;
  color: var(--gray);
  padding-top: 12px;
}
.cta-band {
  background: linear-gradient(135deg, #7c3aed 0%, #4c1d95 100%);
  border-radius: 20px;
  padding: 56px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 40px;
  flex-wrap: wrap;
  color: #fff;
}
.cta-band h2 {
  font-size: 36px;
  margin: 0 0 10px;
}
.cta-band p {
  font-size: 15px;
  color: rgba(255, 255, 255, 0.75);
  margin: 0;
}
.cta-band input {
  padding: 14px 18px;
  border-radius: 10px;
  border: none;
  font-size: 14px;
  font-family: inherit;
  width: 240px;
  outline: none;
}
.cta-band .btn {
  background: var(--ink);
  color: #fff;
}
.footer {
  background: var(--ink);
  color: #fff;
  margin-top: 0;
}
.footer-inner {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-block: clamp(26px, 3.4vw, 40px);
  flex-wrap: wrap;
  gap: 18px;
}
.footer-brand {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.footer-tagline {
  margin: 0;
  font-size: 12.5px;
  color: rgba(255, 255, 255, 0.42);
  letter-spacing: 0.01em;
}
.footer-meta {
  font-size: 12.5px;
  color: rgba(255, 255, 255, 0.4);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 2px 4px;
}
/* Each link gets real padding so it is a comfortable tap target: nine links
   on one 12px line with no padding were ~15px tall, far under the 44px
   guideline, and effectively un-tappable on a phone. */
.footer-meta a {
  color: rgba(255, 255, 255, 0.62);
  padding: 9px 6px;
  border-radius: 6px;
  transition:
    color 0.15s,
    background 0.15s;
}
.footer-meta a:hover,
.footer-meta a:focus-visible {
  color: #fff;
  background: rgba(255, 255, 255, 0.08);
}
/* The interpuncts are decoration between links, not content to tap around. */
.footer-sep {
  color: rgba(255, 255, 255, 0.22);
  user-select: none;
}

@media (max-width: 700px) {
  /* Stack the two halves and let the links breathe. */
  .footer-inner {
    flex-direction: column;
    align-items: flex-start;
    gap: 14px;
  }
  .footer-meta {
    gap: 0 2px;
  }
  .footer-sep {
    display: none;
  } /* the padding already separates them */
  .footer-meta a {
    padding: 10px 10px 10px 0;
  }
}
.chip {
  display: inline-block;
  padding: 9px 18px;
  border-radius: 100px;
  font-size: 13px;
  font-weight: 600;
  border: 1px solid #e4e0ef;
  background: #fff;
  color: var(--ink);
}
.chip.active {
  background: var(--violet);
  border-color: var(--violet);
  color: #fff;
}
.event-card {
  border: 1px solid var(--border);
  border-radius: 14px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  background: #fff;
  transition:
    box-shadow 0.16s,
    border-color 0.16s,
    transform 0.16s;
}
.event-card:hover {
  box-shadow: 0 10px 26px rgba(124, 58, 237, 0.13);
  border-color: var(--violet-pale);
  transform: translateY(-2px);
}
.provider-card {
  display: grid;
  grid-template-columns: 110px minmax(0, 1fr);
  align-items: stretch;
  gap: 16px;
  padding: 12px 12px 14px;
}
.provider-banner {
  aspect-ratio: 1;
  width: 110px;
  height: 110px;
  border-radius: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  box-shadow: inset 0 0 0 1px rgba(124, 58, 237, 0.08);
}
.event-banner {
  /* 16:9 — the same family as the event page's cover banner and the 1200×630
     the upload asks for, so one picture suits the card and the page. */
  aspect-ratio: 16/9;
  width: 100%;
  display: flex;
  align-items: flex-end;
  /* One row along the bottom holding the date and the category. */
  gap: 6px;
  padding: 12px;
  position: relative;
}
/* The date and the category are a MATCHED PAIR on one line along the bottom of
   the poster. They used to be two different species — a white pill pinned to
   the top-left corner and a dark rounded box at the bottom — which read as two
   unrelated labels stuck on the same picture, and on a short poster they
   overlapped each other. Same pill shape, same size, same blur; the date leads
   because it is the fact people scan for, and colour is the only thing that
   separates them. */
.event-cat,
.event-date {
  font-size: 11px;
  font-weight: 700;
  line-height: 1.35;
  padding: 4px 10px;
  border-radius: 100px;
  letter-spacing: 0.01em;
  backdrop-filter: blur(6px);
  white-space: nowrap;
}
.event-date {
  background: rgba(22, 24, 29, 0.82);
  color: #fff;
}
.event-cat {
  /* Second in the row, so it reads after the date even though the markup puts
     it first — the category is the softer of the two facts. */
  order: 2;
  background: rgba(255, 255, 255, 0.92);
  color: var(--ink);
  /* A long category must not push the date off the card. */
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
.event-body {
  padding: 13px 14px 15px;
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.provider-body {
  padding: 0;
  gap: 10px;
}
.provider-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
  flex-wrap: wrap;
}
.provider-copy {
  min-width: 0;
  flex: 1 1 180px;
}
.provider-side {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
  flex: none;
  flex-wrap: wrap;
}
.provider-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 6px 10px;
  border-radius: 100px;
  background: #f5f3ff;
  color: var(--violet);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.01em;
}
.provider-pill-soft {
  background: #f8fafc;
  color: var(--gray);
}
.provider-meta {
  padding-top: 2px;
}
/* Cards carry name + location only — keep the title to two lines so every card
   in a row stays the same height regardless of title length. */
.event-title {
  font-size: 14.5px;
  font-weight: 700;
  line-height: 1.35;
  margin: 0;
  letter-spacing: -0.01em;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: 2.7em;
}
.event-card:hover .event-title {
  color: var(--violet);
}
.event-where {
  display: flex;
  align-items: flex-start;
  gap: 5px;
  font-size: 12.5px;
  color: var(--gray);
  line-height: 1.4;
}
.event-where svg {
  width: 13px;
  height: 13px;
  flex: none;
  margin-top: 2px;
  opacity: 0.7;
}
/* Venue on its own row, location under it. Each row clamps to one line so a long
   venue name cannot push cards in the grid out of alignment. */
.event-where-lines {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}
.event-where span {
  display: -webkit-box;
  -webkit-line-clamp: 1;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.event-where-venue {
  font-weight: 600;
  color: var(--ink);
}
.event-where-loc {
  color: var(--gray);
}
.event-price {
  font-family: "Bricolage Grotesque", sans-serif;
  font-size: 17px;
  font-weight: 800;
  color: var(--violet);
}
.compare {
  border: 1px solid var(--border);
  border-radius: 14px;
  overflow: hidden;
}
.compare .row {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr 1fr;
  font-size: 14px;
  padding: 13px 24px;
  border-top: 1px solid #f3f0fa;
  align-items: center;
}
.compare .row.head {
  background: var(--tint-bg);
  font-size: 13px;
  font-weight: 700;
  border-top: none;
}
.compare .row div:not(:first-child) {
  text-align: center;
}
.toggle {
  display: inline-flex;
  background: #fff;
  border: 1px solid #e4e0ef;
  border-radius: 100px;
  padding: 4px;
  gap: 4px;
}
.toggle a {
  padding: 9px 22px;
  border-radius: 100px;
  font-size: 13px;
  font-weight: 700;
  color: var(--gray);
}
.toggle a.on {
  background: var(--violet);
  color: #fff;
}
@media (max-width: 900px) {
  .grid-3,
  .grid-feat {
    grid-template-columns: 1fr;
  }
  .nav-links {
    gap: 14px;
    flex-wrap: wrap;
  }
}
@media (max-width: 560px) {
  /* The hero run stays inline and simply wraps; the about page's block stats
     go two-up rather than four-across. */
  .hero-stats {
    gap: 4px 16px;
  }
  .stats {
    gap: 16px 20px;
  }
  /* Buttons go full width so neither is clipped and both are easy to tap. */
  .hero-ctas {
    flex-direction: column;
    align-items: stretch;
  }
  .hero-ctas .btn {
    width: 100%;
    text-align: center;
  }
}

/* ---- Eventio360 app additions ---- */
.nav .brand-img {
  height: 26px;
  display: block;
}
.footer .brand-img {
  height: 30px;
  display: block;
}
/* The poster, WHOLE — the same treatment the event page's banner uses. `cover`
   cut 44% off a square poster (they are square or portrait as often as they are
   1.91:1), taking the title with it.

   Three layers, because a pseudo-element always paints ABOVE its parent's own
   background — putting the poster there and the blur in ::before simply hid the
   poster. So: ::before is the blurred backdrop, ::after is the whole poster, and
   the chips sit above both. Both read the picture from --cover, which the card
   sets; a card without one sets nothing and neither layer paints, leaving the
   element's own background (a gradient, or another card type's image) alone. */
.event-banner {
  background-size: cover;
  background-position: center;
  /* CLIP THE LAYERS TO THE BANNER. ::before is scaled 1.15 and blurred 18px,
     so without this it painted ~15% beyond the banner on every side — the
     darkened, blurred poster bled down over the card body and greyed the area
     behind the event title, which read as the title being faded out. The
     card's own overflow:hidden does not help: the spill lands INSIDE the card,
     on top of the text. */
  overflow: hidden;
}
.event-banner::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: var(--cover, none);
  background-size: cover;
  background-position: center;
  filter: blur(18px) saturate(1.25) brightness(0.72);
  transform: scale(1.15);
  z-index: 0;
}
.event-banner::after {
  content: "";
  position: absolute;
  inset: 0;
  /* The readability gradient rides on top of the poster so the date chip stays
     legible over a pale one. */
  background-image: linear-gradient(180deg, rgba(22, 24, 29, 0) 45%, rgba(22, 24, 29, 0.5)), var(--cover, none);
  background-size: auto, contain;
  background-repeat: no-repeat, no-repeat;
  background-position: center, center;
  z-index: 1;
}
/* The chips sit above both picture layers. `position: relative` here used to
   be blanket, which silently overrode .event-cat's `position: absolute` — the
   category pill dropped out of its top-left corner into the flex flow and
   collided with the date chip at the bottom of every card. z-index alone does
   the layering for anything already positioned, so only promote the ones that
   are still static. */
.event-banner > *:not(.event-cat) {
  position: relative;
}
.event-banner > * {
  z-index: 2;
}
.user-menu {
  position: relative;
  padding: 0;
  border: none;
  background: transparent;
  border-radius: 0;
}
.user-menu summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  color: var(--ink);
}
.user-menu summary::-webkit-details-marker {
  display: none;
}
.user-menu summary::after {
  content: "▾";
  font-size: 10px;
  color: var(--gray);
}
.user-menu .avatar-sm {
  width: 30px;
  height: 30px;
  border-radius: 8px;
  object-fit: cover;
  background: var(--tint);
  color: var(--violet);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 12px;
}
.user-menu .menu {
  position: absolute;
  right: 0;
  top: calc(100% + 10px);
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 12px 32px rgba(22, 24, 29, 0.12);
  min-width: 210px;
  padding: 8px;
  display: flex;
  flex-direction: column;
  z-index: 60;
}
.user-menu .menu a {
  padding: 9px 12px;
  border-radius: 8px;
  color: var(--ink);
  font-size: 14px;
  font-weight: 500;
}
.user-menu .menu a:hover {
  background: var(--tint-bg);
  color: var(--violet);
}
.user-menu .menu a.danger {
  color: #dc2626;
}
.user-menu .menu .menu-head {
  padding: 9px 12px;
  font-size: 12px;
  color: var(--gray);
  border-bottom: 1px solid var(--border);
  margin-bottom: 6px;
}
.search-input {
  padding: 11px 16px;
  border-radius: 10px;
  border: 1px solid #e4e0ef;
  font-size: 14px;
  font-family: inherit;
  outline: none;
  min-width: 220px;
  background: #fff;
}
.search-input:focus {
  border-color: var(--violet-pale);
}
.empty-state {
  text-align: center;
  padding: 64px 0;
  color: var(--gray);
}
.empty-state .display {
  font-size: 20px;
  font-weight: 800;
  color: var(--ink);
  margin-bottom: 8px;
}
@media (max-width: 900px) {
  .nav-inner {
    flex-wrap: wrap;
    gap: 12px;
  }
  .section {
    padding-block: 44px;
  }
}

/* ---- Mobile fixes (verified at 375px) ---- */
/* Pricing compare table: scroll horizontally instead of crushing 4 columns */
.compare {
  overflow-x: auto;
}
.compare .row {
  min-width: 540px;
}
/* Auth pages: decorative shapes must not create horizontal scroll */
body.auth-page {
  overflow-x: hidden;
}
/* Keep the nav CTA compact on legacy pages whose template CSS restyles .btn */
.nav .btn-primary {
  display: inline-block;
  width: auto;
  background: var(--violet);
  color: #fff;
  border: none;
  line-height: normal;
  padding: 9px 18px;
  border-radius: 9px;
  font-size: 14px;
}
.nav .btn-primary:hover {
  background: #8b4df7;
  color: #fff;
}

/* ---- Mobile nav: hamburger toggle + dropdown panel ---- */
.nav-toggle {
  display: none;
  background: none;
  border: 0;
  cursor: pointer;
  padding: 8px;
  margin-left: auto;
}
.nav-toggle span {
  display: block;
  width: 22px;
  height: 2px;
  background: var(--ink);
  margin: 5px 0;
  border-radius: 2px;
  transition:
    transform 0.25s,
    opacity 0.25s;
}
.nav-toggle.open span:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}
.nav-toggle.open span:nth-child(2) {
  opacity: 0;
}
.nav-toggle.open span:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}
@media (max-width: 900px) {
  .nav-toggle {
    display: block;
  }
  .nav-inner {
    flex-wrap: nowrap;
    gap: 0;
  }
  .nav-links {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    background: #fff;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 8px 20px 16px;
    border-bottom: 1px solid var(--border);
    box-shadow: 0 16px 32px rgba(22, 24, 29, 0.1);
  }
  .nav-links.open {
    display: flex;
  }
  .nav-links a {
    padding: 12px 4px;
    font-size: 15px;
  }
  .nav-links a.btn {
    margin-top: 10px;
    text-align: center;
    padding: 13px 20px;
  }
  .user-menu {
    padding: 6px 0;
  }
  .user-menu .menu {
    position: static;
    box-shadow: none;
    border: none;
    border-top: 1px solid var(--border);
    border-radius: 0;
    margin-top: 8px;
    padding: 6px 0 0;
    min-width: 0;
  }
}

/* ---- Auth screens (shared by login / register / password pages) ---- */
.auth-screen {
  min-height: 100vh;
  background: linear-gradient(175deg, #16181d 0%, #241536 55%, #4c1d95 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 48px 20px;
  position: relative;
  overflow: hidden;
}
.auth-dial {
  position: absolute;
  left: -220px;
  top: -180px;
  opacity: 0.12;
  width: 640px;
  height: 640px;
  pointer-events: none;
}
.auth-card {
  width: 420px;
  max-width: 100%;
  background: #fff;
  border-radius: 18px;
  padding: 40px 44px;
  position: relative;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.3);
}
.auth-card .auth-logo {
  display: flex;
  justify-content: center;
  margin-bottom: 24px;
}
.auth-card .auth-logo img {
  height: 28px;
}
.auth-card h1 {
  font-size: 24px;
  font-weight: 800;
  letter-spacing: -0.02em;
  margin: 0 0 4px;
  text-align: center;
}
.auth-sub {
  font-size: 14px;
  color: var(--gray);
  margin: 0 0 24px;
  text-align: center;
}
.auth-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 14px;
}
.auth-field label {
  font-size: 13px;
  font-weight: 600;
}
.auth-field .label-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
}
.auth-field .label-row a {
  font-size: 12px;
  font-weight: 600;
}
/* ── iOS focus-zoom fix ──────────────────────────────────────────────────────
   Safari on iPhone force-zooms the page whenever a focused control has a
   font under 16px — and every form control here is 14px, so typing in
   login/register/forgot, the booking form, the comment box, or opening any
   searchable dropdown (it focuses a hidden filter input) lurched the whole
   viewport. The fix is the control size, NOT user-scalable=no, which would
   break pinch-zoom for people who need it.
   (hover:none) scopes it to touch devices, so desktop keeps the 14px look;
   !important is required to outrank every component's own 14px rule. */
@media (hover: none) {
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not(
      [type="file"]
    ),
  select,
  textarea {
    font-size: 16px !important;
  }
}

.auth-input {
  padding: 13px 16px;
  border: 1px solid #e4e0ef;
  border-radius: 10px;
  font-size: 14px;
  font-family: inherit;
  outline: none;
  width: 100%;
  box-sizing: border-box;
  background: #fff;
  color: var(--ink);
}
.auth-input:focus {
  border-color: var(--violet);
}
.auth-input.is-invalid {
  border-color: #dc2626;
}
.password-wrap {
  position: relative;
}
.password-wrap .auth-input {
  padding-right: 56px;
}
/* A standalone control, so it gets a real tap target: 6px of padding made it
   27px tall, under the 36px guideline for something you actually poke on a
   phone. Inline links inside a sentence are exempt — they cannot grow without
   breaking the line. */
.password-wrap .password-toggle {
  position: absolute;
  right: 6px;
  top: 50%;
  transform: translateY(-50%);
  background: none;
  border: 0;
  cursor: pointer;
  color: #9ca3af;
  padding: 10px 12px;
  min-height: 38px;
  font-size: 12px;
  font-weight: 600;
  font-family: inherit;
  border-radius: 8px;
}
.password-wrap .password-toggle:hover {
  color: var(--violet);
}
.auth-check {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--gray);
  margin: 2px 0 20px;
  cursor: pointer;
}
.auth-check input {
  accent-color: var(--violet);
  width: 15px;
  height: 15px;
}
.auth-switch {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 2px 0 16px;
  cursor: pointer;
  user-select: none;
}
.auth-switch .auth-switch-label {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink, #1a1a2e);
}
.auth-switch input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}
.auth-switch .auth-switch-track {
  position: relative;
  flex: 0 0 auto;
  width: 44px;
  height: 24px;
  border-radius: 999px;
  background: #d6d6e0;
  transition: background 0.18s ease;
}
.auth-switch .auth-switch-track::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
  transition: transform 0.18s ease;
}
.auth-switch input:checked + .auth-switch-track {
  background: var(--violet);
}
.auth-switch input:checked + .auth-switch-track::after {
  transform: translateX(20px);
}
.auth-switch input:focus-visible + .auth-switch-track {
  box-shadow: 0 0 0 3px rgba(159, 103, 255, 0.35);
}
.auth-submit {
  width: 100%;
  background: var(--violet);
  color: #fff;
  border: none;
  padding: 15px;
  border-radius: 11px;
  font-weight: 700;
  font-size: 15px;
  font-family: inherit;
  cursor: pointer;
  margin-bottom: 18px;
}
.auth-submit:hover {
  background: var(--violet-dark);
}
/* The secondary action ("Sign in" on register, and vice versa) gets the same
   size and shape as the primary button so it is an easy target — as a 13px
   inline link inside a sentence it was far too small to tap. Outlined, so the
   primary action still clearly leads. */
.auth-submit.is-secondary {
  background: #fff;
  color: var(--violet);
  border: 1.5px solid #e4e0ef;
  margin-bottom: 0;
  display: block;
  text-align: center;
  text-decoration: none;
  line-height: 1.2;
}
.auth-submit.is-secondary:hover {
  background: var(--tint);
  border-color: var(--violet-pale);
}
.auth-alt-sep {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 14px;
  font-size: 12px;
  color: #9ca3af;
}
.auth-alt-sep::before,
.auth-alt-sep::after {
  content: "";
  flex: 1;
  height: 1px;
  background: #edeaf5;
}
/* Superseded by .auth-submit.is-secondary + .auth-alt-sep — the auth pages now
   give the secondary action a full-size button instead of a 13px inline link. */
.auth-msg {
  border-radius: 10px;
  padding: 12px 14px;
  font-size: 13px;
  margin-bottom: 16px;
}
.auth-msg.error {
  background: #fef2f2;
  color: #b91c1c;
  border: 1px solid #fecaca;
}
.auth-msg.success {
  background: #f0fdf4;
  color: #15803d;
  border: 1px solid #bbf7d0;
}
@media (max-width: 520px) {
  .auth-card {
    padding: 32px 24px;
  }
}

/* ---- Auth split card (sign up) ---- */
.auth-split {
  width: 1100px;
  max-width: 100%;
  display: flex;
  border-radius: 20px;
  overflow: hidden;
  box-shadow: 0 24px 60px rgba(22, 24, 29, 0.18);
  background: #fff;
  position: relative;
}
.auth-brand-panel {
  width: 430px;
  flex: 0 0 430px;
  background: linear-gradient(175deg, #16181d 0%, #241536 55%, #4c1d95 100%);
  color: #fff;
  padding: clamp(32px, 3.4vw, 46px);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 28px;
  position: relative;
  overflow: hidden;
}
.auth-brand-panel .panel-dial {
  position: absolute;
  right: -160px;
  bottom: -160px;
  opacity: 0.14;
  width: 460px;
  height: 460px;
}
.auth-panel-logo {
  position: relative;
  align-self: flex-start;
  display: block;
}
.auth-brand-panel .brand-img {
  height: 42px;
  width: auto;
  display: block;
}
.auth-panel-body {
  position: relative;
}
.auth-brand-panel h2 {
  font-size: clamp(24px, 2.6vw, 34px);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.12;
  margin: 0 0 14px;
  text-wrap: balance;
}
.auth-brand-panel .panel-copy {
  font-size: 15px;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.65);
  margin: 0 0 28px;
}
.auth-brand-panel .panel-checks {
  display: flex;
  flex-direction: column;
  gap: 12px;
  font-size: 14px;
  color: rgba(255, 255, 255, 0.8);
}
.auth-brand-panel .panel-checks div {
  display: flex;
  gap: 10px;
  align-items: baseline;
}
.auth-brand-panel .panel-checks span {
  color: var(--violet-light);
  font-weight: 800;
}
.auth-brand-panel .panel-foot {
  font-size: 12px;
  color: rgba(255, 255, 255, 0.35);
  position: relative;
}
.auth-form-panel {
  flex: 1;
  padding: clamp(28px, 3.4vw, 46px) clamp(24px, 4vw, 58px);
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
}
.auth-form-panel h1 {
  font-size: clamp(21px, 2.4vw, 27px);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin: 0 0 6px;
}
.auth-form-panel .auth-sub {
  text-align: left;
  margin-bottom: 24px;
}
.type-select {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin-bottom: 20px;
}
.type-btn {
  border: 2px solid #e4e0ef;
  background: #fff;
  border-radius: 12px;
  padding: 14px 16px;
  text-align: left;
  cursor: pointer;
  font-family: inherit;
}
.type-btn.active {
  border-color: var(--violet);
  background: var(--tint);
}
.type-btn strong {
  display: block;
  font-size: 14px;
  font-weight: 700;
  color: var(--ink);
  margin-bottom: 2px;
}
.type-btn small {
  font-size: 12px;
  color: var(--gray);
}
.field-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}
/* Title + Full name. The title is a short fixed-width control and the name
   must keep the rest; min-width:0 stops the name's input forcing the column
   wider than its share. Stacks on a phone — an inline style here would beat
   the media query and leave the name box ~143px wide. */
.name-grid {
  display: grid;
  grid-template-columns: 132px 1fr;
  gap: 14px;
  align-items: start;
}
.name-grid > * {
  min-width: 0;
}
@media (max-width: 600px) {
  .name-grid {
    grid-template-columns: 1fr;
  }
}
.strength {
  display: flex;
  gap: 5px;
  margin: 8px 0 6px;
}
.strength div {
  height: 4px;
  flex: 1;
  border-radius: 2px;
  background: #edeaf5;
}
.strength div.on {
  background: var(--violet);
}
.auth-terms {
  font-size: 12px;
  color: #9ca3af;
  margin: 16px 0 0;
  text-align: center;
  line-height: 1.5;
}
.auth-terms a {
  color: var(--gray);
}
@media (max-width: 900px) {
  /* On a phone the brand panel's marketing copy would push the form below the
     fold, so the panel is dropped and the LOGO is lifted to the top of the PAGE
     — over the gradient, above the card, not attached to it.
     The screen becomes a plain top-to-bottom column: logo, then form card.
     NB `display:contents` on .auth-split was tried and is wrong: it removes the
     box, so the card loses its own background/rounding/overflow clip and the
     decorative .auth-dial bleeds through it. The split keeps its box and simply
     stops being the visual card; .auth-form-panel becomes the card instead. */
  /* The LOGO sits at the top of the page; the FORM stays vertically CENTRED.
     Two different jobs, so the logo is taken out of the centring flow with
     position:absolute and the screen keeps `justify-content:center` for the
     card. (`justify-content:flex-start` pinned both to the top, and an auto
     margin on the logo does not lift it out of a centred column.)
     The top padding reserves the logo's band so a tall form never slides
     underneath it. */
  .auth-screen {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: calc(
        clamp(22px, 7vw, 34px) + clamp(42px, 13vw, 56px) +
          clamp(18px, 5vw, 26px)
      )
      var(--gutter) clamp(28px, 8vw, 44px);
    gap: 0;
  }
  /* The panel contributes only its logo, hoisted above the card. */
  .auth-brand-panel {
    display: contents;
  }
  .auth-brand-panel .auth-panel-body,
  .auth-brand-panel .panel-foot,
  .auth-brand-panel .panel-dial {
    display: none;
  }
  .auth-panel-logo {
    position: absolute;
    top: clamp(22px, 7vw, 34px);
    left: 0;
    right: 0;
    display: block;
    z-index: 1;
    text-align: center;
  }
  .auth-brand-panel .brand-img {
    height: clamp(42px, 13vw, 56px);
    width: auto;
    margin: 0 auto;
    display: block;
  }
  /* The split is now just the column wrapper; the form panel is the card, and
     it keeps its own clip so nothing shows through it. */
  /* static, so it stops being the containing block for the absolutely
     positioned logo — otherwise the logo anchors to the CARD instead of the
     page and lands in the middle of the screen. */
  .auth-split {
    flex-direction: column;
    width: 100%;
    max-width: 460px;
    background: none;
    box-shadow: none;
    border-radius: 0;
    overflow: visible;
    position: static;
  }
  /* z-index lifts the card above the decorative .auth-dial. Without a stacking
     context the dial (a sibling that comes later in the DOM) painted straight
     over the white card. */
  .auth-form-panel {
    width: 100%;
    background: #fff;
    border-radius: 18px;
    overflow: hidden;
    box-shadow: 0 20px 50px rgba(0, 0, 0, 0.3);
    padding: 28px 22px 30px;
    justify-content: flex-start;
    position: relative;
    z-index: 1;
  }
  .field-grid {
    grid-template-columns: 1fr;
  }
}

/* Events pager */
.pager-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 38px;
  height: 38px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: #fff;
  color: var(--ink);
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
  transition:
    background 0.12s,
    border-color 0.12s,
    color 0.12s;
}
.pager-btn:hover {
  background: var(--tint);
  border-color: var(--violet-pale);
}
.pager-btn.is-active {
  background: var(--violet);
  border-color: var(--violet);
  color: #fff;
}
.pager-gap {
  color: var(--gray);
  padding: 0 4px;
}

/* hidden attribute must always win over component display rules */
[hidden] {
  display: none !important;
}

/* ── Event detail page (.ed-) ────────────────────────────────────── */
/* Layout */
.ed-page {
  padding-top: 16px;
  padding-bottom: 72px;
}
.ed-crumb {
  padding-top: 18px;
  font-size: 13px;
  color: var(--gray);
}
.ed-crumb a {
  color: var(--gray);
}
.ed-crumb a:hover {
  color: var(--violet);
}
.ed-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 360px;
  gap: 28px;
  align-items: start;
}
/* The ticket panel is far taller than the cover+title column beside it, and a
   grid ROW is as tall as its tallest cell — which left ~220px of blank space
   under the meta strip before the next section began.
   Fix: the whole page is ONE grid. The sidebar is placed explicitly in column 2
   spanning BOTH rows, and the content column holds the headline (row 1) then
   every section (row 2). Nothing has to guess an overhang, and the sections
   start immediately under the meta strip. */
.ed-top {
  align-items: start;
  margin: 16px 0 0;
}
@media (min-width: 901px) {
  .ed-top {
    grid-template-rows: auto 1fr;
  }
  .ed-top > .ed-headline {
    grid-column: 1;
    grid-row: 1;
  }
  .ed-top > .ed-side-top {
    grid-column: 2;
    grid-row: 1 / span 2;
    align-self: start;
    position: sticky;
    top: 76px;
  }
  /* Taller than the window? Scroll inside the rail instead of stranding the
     bottom of it off-screen. No scrollbar appears when it fits. */
  /* overscroll-behavior stays at the default (auto) on purpose: contain would
     stop the wheel chaining to the PAGE once the rail bottoms out, so a
     visitor with the cursor over the sidebar could not scroll on. */
  .ed-top > .ed-side-top {
    max-height: calc(100vh - 92px);
    overflow-y: auto;
    scrollbar-width: thin;
  }
  .ed-top > .ed-main-flow {
    grid-column: 1;
    grid-row: 2;
    margin-top: 14px;
  }
}
.ed-side {
  position: sticky;
  top: 76px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-width: 0;
}
/* This used to blanket-reset every .ed-side inside .ed-top to static, which
   also killed the sticky on .ed-side-top declared above — so the ticket panel
   scrolled away and "Book now" was off screen for the remaining ~2,500px of
   the page. Only the NON-sticky siblings (related events) are reset. */
.ed-top .ed-side:not(.ed-side-top) {
  position: static;
}
.ed-main {
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-width: 0;
}
@media (max-width: 900px) {
  .ed-layout {
    grid-template-columns: 1fr;
  }
  .ed-side {
    position: static;
  }
  /* Single column: the DOM order is headline, ticket panel, sections, related.
     Reordering puts the sections directly under the meta strip and moves the
     ticket panel below them — on a phone the visitor reads what the event IS
     before the booking form, and the 900px-tall panel no longer sits between
     the title and the content. `order` works because the grid is 1-column. */
  /* min-width:0 on the items: a flex column does not constrain its children's
     intrinsic width, so a wide table or long code inside a section pushed the
     page 238px sideways. */
  .ed-top {
    display: flex;
    flex-direction: column;
    gap: 0;
  }
  .ed-top > * {
    min-width: 0;
    max-width: 100%;
  }
  .ed-top > .ed-headline {
    order: 1;
  }
  .ed-top > .ed-main-flow {
    order: 2;
    margin-top: 14px;
  }
  .ed-top > .ed-side-top {
    order: 3;
    margin-top: 14px;
  }
}
/* Panels + headings */
/* break-word: event descriptions carry pasted URLs and emails, and one
   45-character token is enough to force a 360px phone to scroll sideways. */
.ed-panel {
  border: 1px solid var(--border);
  border-radius: 14px;
  background: #fff;
  padding: 20px 22px;
  min-width: 0;
  overflow-wrap: break-word;
}
.ed-h {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 17px;
  font-weight: 750;
  margin: 0 0 12px;
  letter-spacing: -0.02em;
}
.ed-h svg {
  color: var(--violet);
  flex: none;
}
.ed-sub {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 15px;
  font-weight: 700;
  margin: 22px 0 10px;
}
.ed-sub svg {
  color: var(--violet);
  flex: none;
}
.ed-muted {
  color: var(--gray);
}
.ed-text-success,
.ed-ok-text {
  color: #15803d;
}
.ed-err-text {
  color: var(--danger-fg, #c02626);
}
.ed-warn-text {
  color: #b45309;
}
.ed-danger-text {
  color: #dc2626;
}
/* Hero */
/* Cover art in its own frame; heading and meta read below it on white. */
.ed-headline {
  display: flex;
  flex-direction: column;
  gap: 0;
}
/* Cover banner — full width above the two-column layout, in the proportions
   a cover photo is composed for (the form asks for 1200×630). It used to be a
   16:9 box inside the left column, which squeezed a wide poster into
   two-thirds of the page. */
.ed-covers {
  position: relative;
  margin: 16px 0 0;
  border-radius: 18px;
  overflow: hidden;
  background: var(--tint);
  border: 1px solid var(--border);
  line-height: 0;
}
/* A FIXED frame, not a ratio: at full container width a 1.91:1 banner came out
   ~600px tall and pushed everything below the fold, and a square poster would
   be 1100px. The height is therefore set directly — aspect-ratio + max-height
   shrinks the WIDTH instead. */
.ed-cover-slide {
  position: relative;
  margin: 0;
  height: clamp(190px, 27vw, 360px);
  overflow: hidden;
}
/* The poster, WHOLE. contain — not cover — because event posters are square or
   portrait as often as they are wide, and cropping one to a letterbox cuts the
   title out of it. A 1.91:1 cover fills the frame exactly and never reveals
   the backdrop below. */
.ed-cover-slide img {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center;
  display: block;
}
/* …and the space either side is the same picture, blurred and dimmed, so the
   frame reads as one composed image rather than a poster floating on a slab.
   scale() hides the soft edges blur leaves behind. */
.ed-cover-bg {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  filter: blur(26px) saturate(1.25) brightness(0.72);
  transform: scale(1.18);
  z-index: 0;
}
@media (max-width: 640px) {
  .ed-cover-slide { height: clamp(170px, 56vw, 260px); }
  .ed-cover-bg { filter: blur(18px) saturate(1.25) brightness(0.72); }
}
.ed-title {
  font-size: 32px;
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.15;
  margin: 0;
  color: var(--ink);
  text-wrap: balance;
}
.ed-lede {
  margin: 10px 0 0;
  font-size: 15.5px;
  line-height: 1.6;
  color: var(--gray);
  max-width: 64ch;
}
/* "by <organiser>" credit under the title. Quieter than the lede, but the name
   itself carries weight — it is who the attendee is trusting with their money. */
.ed-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
  margin-top: 16px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}
/* Written for the old chip strip; scoped so it cannot flatten the fact rows
   below, whose label sits ABOVE its value. */
.ed-meta > span {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--ink);
}
.ed-meta svg {
  color: var(--violet);
  flex: none;
}
.ed-hero-cat {
  position: absolute;
  left: 14px;
  top: 14px;
  z-index: 2;
  background: rgba(255, 255, 255, 0.94);
  color: var(--ink);
  font-size: 11px;
  font-weight: 700;
  padding: 5px 12px;
  border-radius: 100px;
}
.ed-hero-flag {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 2;
  background: var(--violet);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  padding: 5px 12px;
  border-radius: 100px;
}
@media (max-width: 900px) {
  .ed-hero {
    min-height: 240px;
  }
  .ed-hero-body h1 {
    font-size: 27px;
  }
}
/* Tags, notes, alerts */
.ed-tag {
  display: inline-block;
  background: var(--tint);
  color: var(--violet);
  font-size: 12px;
  font-weight: 700;
  padding: 4px 10px;
  border-radius: 100px;
}
.ed-tag-warn {
  background: #fffbeb;
  color: #b45309;
}
.ed-tag-danger {
  background: #fef2f2;
  color: #b91c1c;
}
.ed-note {
  background: var(--tint-bg);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px 14px;
  font-size: 13px;
  color: var(--ink);
}
.ed-ok {
  background: #f0fdf4;
  border: 1px solid #bbf7d0;
  border-radius: 10px;
  padding: 12px 14px;
  font-size: 13px;
  color: #15803d;
}
.ed-warn {
  background: #fffbeb;
  border: 1px solid #fde68a;
  border-radius: 10px;
  padding: 12px 14px;
  font-size: 13px;
  color: #b45309;
}
.ed-danger {
  background: #fef2f2;
  border: 1px solid #fecaca;
  border-radius: 10px;
  padding: 12px 14px;
  font-size: 13px;
  color: #b91c1c;
}
/* Buttons (page-scoped variants; base .btn comes from brand.css) */
.ed-w100 {
  width: 100%;
  display: block;
  text-align: center;
}
.ed-btn-outline {
  background: #fff;
  border: 1px solid var(--violet-pale);
  color: var(--violet);
}
.ed-btn-outline:hover {
  background: var(--tint);
}
.ed-btn-saved {
  background: var(--tint);
  border: 1px solid var(--violet-pale);
  color: var(--violet);
}
.ed-btn-ok {
  background: #f0fdf4;
  border: 1px solid #bbf7d0;
  color: #15803d;
}
.ed-btn-pending {
  background: #fffbeb;
  border: 1px solid #fde68a;
  color: #b45309;
}
.ed-btn-mute {
  background: #f3f4f6;
  border: 1px solid #e5e7eb;
  color: #6b7280;
  cursor: not-allowed;
}
/* Stats */
/* Detail lines + meta grid */
.ed-line {
  display: flex;
  gap: 8px;
  align-items: flex-start;
  font-size: 14px;
  color: var(--ink);
  margin: 0 0 6px;
}
.ed-line svg {
  flex: none;
  color: var(--violet);
  margin-top: 2px;
}
.ed-meta {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}
/* A fact is an icon beside its label and value — the shape .op-hero-facts
   uses on a profile, applied to the same kind of content here. */
.ed-fact-row {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  min-width: 0;
}
.ed-fact-ic {
  display: inline-flex;
  flex: none;
  margin-top: 2px;
  color: var(--violet);
}
.ed-meta .k {
  display: block;
  font-size: 12px;
  color: var(--gray);
  margin-bottom: 3px;
}
.ed-meta .v {
  display: block;
  font-size: 14px;
  font-weight: 600;
  overflow-wrap: anywhere;
}
@media (max-width: 700px) {
  .ed-meta {
    grid-template-columns: 1fr 1fr;
  }
}
/* Tickets sidebar */
.ed-ticket {
  border: 1px solid var(--border);
  border-radius: 11px;
  padding: 13px 14px;
  background: #fff;
  margin-bottom: 9px;
  transition: border-color 0.14s;
}
.ed-ticket:hover {
  border-color: var(--violet-pale);
}
.ed-ticket-top {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: flex-start;
}
.ed-ticket-name {
  font-weight: 650;
  font-size: 14px;
  color: var(--ink);
  line-height: 1.3;
}
.ed-ticket-desc {
  font-size: 12px;
  color: var(--gray);
  margin: 2px 0 0;
  display: -webkit-box;
  -webkit-line-clamp: 1;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.ed-ticket-price {
  text-align: right;
  flex: none;
}
.ed-price {
  font-family: "Bricolage Grotesque", sans-serif;
  font-size: 24px;
  font-weight: 800;
  color: var(--ink);
  line-height: 1.15;
}
.ed-avail {
  margin-top: 12px;
}
.ed-progress {
  height: 6px;
  background: var(--tint);
  border-radius: 3px;
  overflow: hidden;
}
.ed-progress span {
  display: block;
  height: 100%;
  background: var(--violet);
  border-radius: 3px;
}
.ed-reg-item {
  margin-bottom: 10px;
  font-size: 14px;
}
.ed-count {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  text-align: center;
}
.ed-count .box {
  background: var(--tint);
  border-radius: 10px;
  padding: 10px 4px;
}
.ed-count .n {
  font-family: "Bricolage Grotesque", sans-serif;
  font-size: 20px;
  font-weight: 800;
  color: var(--violet);
  display: block;
}
.ed-count .l {
  font-size: 11px;
  color: var(--gray);
}
/* Rows (shared by sidebar + booking summary) */
.ed-row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-size: 14px;
  margin-bottom: 6px;
}
.ed-row-total {
  font-size: 15px;
}
.ed-hr {
  border: none;
  border-top: 1px solid var(--border);
  margin: 10px 0;
}
/* Workshops */
.ed-ws-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 20px;
}
@media (max-width: 700px) {
  .ed-ws-grid {
    grid-template-columns: 1fr;
  }
}
.ed-ws {
  border: 1px solid var(--border);
  border-radius: 14px;
  overflow: hidden;
  background: #fff;
  display: flex;
  flex-direction: column;
}
.ed-ws:hover {
  border-color: var(--violet-pale);
  box-shadow: 0 8px 24px rgba(124, 58, 237, 0.08);
}
.ed-ws-media {
  height: 160px;
  position: relative;
  overflow: hidden;
  background: var(--tint);
}
.ed-ws-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.ed-ws-ph {
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--violet);
  opacity: 0.7;
}
.ed-ws-flag {
  position: absolute;
  top: 10px;
  right: 10px;
  font-size: 11px;
  font-weight: 700;
  padding: 4px 10px;
  border-radius: 100px;
}
.ed-flag-danger {
  background: #fef2f2;
  color: #b91c1c;
}
.ed-flag-warn {
  background: #fffbeb;
  color: #b45309;
}
.ed-ws-body {
  padding: 18px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  flex: 1;
}
.ed-ws-title {
  font-weight: 700;
  font-size: 15px;
}
.ed-ws-foot {
  margin-top: auto;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}
/* Schedule table */
/* Public event stats (events.display_stats). A compact inline run rather than
   big numerals: on a young event the figures are small, and 26px digits
   announcing "4" read as weakness. Same treatment as .hero-stats. */
/* Event stats: each figure carries its own icon so the row is scannable
   instead of a run of bare numbers. align-items is CENTER now, not
   baseline — an icon has no text baseline to sit on. */
/* (legacy .ed-stats block removed — its .ed-stat-ico/.num/.lbl markup is emitted
   nowhere; the live rules are with the Event-at-a-glance styles further down) */

.ed-table-wrap {
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: 12px;
  -webkit-overflow-scrolling: touch;
  background: linear-gradient(to left, #fff, rgba(255, 255, 255, 0)) right/22px
    100% no-repeat;
  background-attachment: local;
}
.ed-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
  min-width: 560px;
}
.ed-table th {
  background: var(--tint-bg);
  text-align: left;
  padding: 12px 16px;
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--gray);
}
.ed-table td {
  padding: 14px 16px;
  border-top: 1px solid var(--border);
  vertical-align: top;
}

@media (max-width: 640px) {
  /* The schedule is a 3-column table with min-width:560px, so on a phone it
     scrolled sideways and each cell was a cramped column. Stacked as cards it
     reads top-to-bottom with no horizontal scroll: the header row is hidden and
     each cell is labelled from its data-label. */
  .ed-table-wrap.is-stack {
    overflow: visible;
    border: 0;
    background: none;
  }
  .ed-table-wrap.is-stack .ed-table {
    min-width: 0;
    width: 100%;
    display: block;
  }
  .ed-table-wrap.is-stack .ed-table thead {
    display: none;
  }
  .ed-table-wrap.is-stack .ed-table tbody,
  .ed-table-wrap.is-stack .ed-table tr,
  .ed-table-wrap.is-stack .ed-table td {
    display: block;
    width: auto;
  }
  .ed-table-wrap.is-stack .ed-table tr {
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 12px 14px;
    margin-bottom: 10px;
    background: #fff;
  }
  .ed-table-wrap.is-stack .ed-table tr:last-child {
    margin-bottom: 0;
  }
  .ed-table-wrap.is-stack .ed-table td {
    border: 0;
    padding: 0 0 8px;
  }
  .ed-table-wrap.is-stack .ed-table td:last-child {
    padding-bottom: 0;
  }
  .ed-table-wrap.is-stack .ed-table td:empty {
    display: none;
  }
  /* The column name, so a stacked cell still says what it is. */
  .ed-table-wrap.is-stack .ed-table td[data-label]::before {
    content: attr(data-label);
    display: block;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--gray);
    margin-bottom: 3px;
  }
}
.ed-duration {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  background: linear-gradient(135deg, #7c3aed, #4c1d95);
  color: #fff;
  border-radius: 12px;
  padding: 14px 18px;
  margin-bottom: 16px;
  font-size: 14px;
}
/* Gallery */
.ed-gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 10px;
}
/* Phones: 160px minimum forced ONE giant image per row inside a ~300px
   panel; two-up thumbnails read as a gallery again. */
@media (max-width: 560px) {
  .ed-gallery {
    grid-template-columns: repeat(2, 1fr);
    gap: 8px;
  }
}
.ed-gallery a {
  display: block;
  aspect-ratio: 4/3;
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid var(--border);
  background: var(--tint-bg);
}
.ed-gallery img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.25s;
}
.ed-gallery a:hover img {
  transform: scale(1.05);
}
/* Venue / organizer */
.ed-venue {
  display: flex;
  gap: 20px;
  flex-wrap: wrap;
}
.ed-venue-media {
  width: 220px;
  flex: none;
}
/* On a phone the panel is only ~320px wide inside its padding. A fixed 220px
   picture left about 80px for the text beside it, which is too narrow to wrap
   — so it BROKE WORDS instead: "Central Confer/ence Hall", "Tankisinu/wari",
   "Mana/ged by". The picture takes the full width and the details sit under
   it. `flex: none` is why the media never gave ground on its own. */
@media (max-width: 640px) {
  .ed-venue {
    gap: 14px;
  }
  .ed-venue-media {
    width: 100%;
  }
  /* The details column is .ed-org-body, shared with the organizer block.
     A flex child will not shrink below its content without this. */
  .ed-venue .ed-org-body {
    min-width: 0;
    flex: 1 1 100%;
  }
}
.ed-venue-media img {
  width: 100%;
  height: 140px;
  object-fit: cover;
  border-radius: 12px;
  display: block;
}
.ed-venue-ph {
  height: 140px;
  border-radius: 12px;
  background: var(--tint);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--violet);
}
.ed-mgr {
  display: flex;
  gap: 12px;
  align-items: center;
  flex-wrap: wrap;
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 12px;
  margin-bottom: 12px;
  background: var(--tint-bg);
}
/* The text block had min-width:0 but no flex basis, so it collapsed to zero
   width inside a narrow card and its content — the star rating — spilled past
   the viewport, which is what made the whole page scroll sideways on a phone. */
.ed-mgr > div {
  flex: 1 1 160px;
  min-width: 0;
}
.ed-mgr img,
.ed-mgr .ed-glyph {
  flex: none;
}
.ed-mgr img {
  width: auto;
  max-width: 130px;
  height: 48px;
  border-radius: 10px;
  object-fit: contain;
  background: #fff;
  flex: none;
}
.ed-org {
  display: flex;
  gap: 16px;
  align-items: flex-start;
  flex-wrap: wrap;
}
.ed-org-body {
  flex: 1;
  min-width: 240px;
}
.ed-org-desc {
  margin: 0 0 10px;
  font-size: 13px;
  line-height: 1.55;
}
/* Organized-by sits in the hero, straight after the title and the lede,
   where the one-line "by <organiser>" byline used to be. .ed-headline is a
   zero-gap flex column, so the card carries its own top margin. */
.ed-org-hero {
  margin-top: 16px;
}
.ed-org-logo {
  width: 56px;
  height: 56px;
  border-radius: 12px;
  object-fit: cover;
  flex: none;
}
/* Company marks are not faces: never crop them to a square. Height is
   fixed, width follows the artwork's own aspect ratio. */
.ed-brandmark {
  width: auto;
  max-width: 150px;
  object-fit: contain;
  background: #fff;
}
.ed-org-ph {
  width: 56px;
  height: 56px;
  border-radius: 12px;
  background: var(--tint);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--violet);
  flex: none;
}
.ed-glyph {
  width: 40px;
  height: 40px;
  border-radius: 10px;
  background: var(--tint);
  color: var(--violet);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  font-size: 11px;
  font-family: "Bricolage Grotesque", sans-serif;
  flex: none;
}
/* Share buttons */
.ed-share {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--border);
  border-radius: 100px;
  padding: 8px 16px;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
  background: #fff;
  cursor: pointer;
  font-family: inherit;
}
.ed-share:hover {
  border-color: var(--violet-pale);
  color: var(--violet);
}
/* Files */
.ed-files {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}
@media (max-width: 700px) {
  .ed-files {
    grid-template-columns: 1fr;
  }
}
/* min-width:0: a grid item defaults to min-width auto, so one long unbroken
   filename widened its whole column and pushed the card out of the panel. */
.ed-file {
  display: flex;
  gap: 12px;
  align-items: center;
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px;
  min-width: 0;
}
.ed-file-name {
  font-size: 14px;
  font-weight: 700;
  overflow-wrap: anywhere;
  word-break: break-word;
}
/* Reviews */
.ed-review {
  border-top: 1px solid var(--border);
  padding: 14px 0;
}
.ed-review:first-of-type {
  border-top: none;
  padding-top: 0;
}
/* Related events */
.ed-rel {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  padding: 12px 0;
  border-top: 1px solid var(--border);
  color: inherit;
}
.ed-rel:first-of-type {
  border-top: none;
  padding-top: 0;
}
.ed-rel-thumb {
  width: 76px;
  height: 56px;
  border-radius: 10px;
  background-size: cover;
  background-position: center;
  flex: none;
}
.ed-rel-title {
  font-size: 14px;
  font-weight: 700;
  color: var(--ink);
  display: block;
  line-height: 1.3;
}
.ed-rel:hover .ed-rel-title {
  color: var(--violet);
}
/* Speakers / sponsors (conference sections partial) */
.ed-people {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}
@media (max-width: 900px) {
  .ed-people {
    grid-template-columns: 1fr 1fr;
  }
}
@media (max-width: 600px) {
  .ed-people {
    grid-template-columns: 1fr;
  }
}
.ed-person {
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 20px;
  text-align: center;
  background: #fff;
}
.ed-person-photo {
  width: 96px;
  height: 96px;
  border-radius: 16px;
  overflow: hidden;
  background: var(--tint);
  margin: 0 auto 12px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.ed-person-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.ed-person-photo span {
  font-family: "Bricolage Grotesque", sans-serif;
  font-size: 32px;
  font-weight: 800;
  color: var(--violet);
}
.ed-person-name {
  font-weight: 700;
  font-size: 15px;
  margin-bottom: 6px;
}
.ed-person-role {
  font-size: 13px;
  margin-top: 8px;
}
.ed-person-inst {
  font-size: 12px;
  color: var(--gray);
  margin-top: 2px;
}
.ed-person-bio {
  font-size: 12px;
  color: var(--gray);
  line-height: 1.55;
  margin: 10px 0 0;
}
.ed-tier {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin: 18px 0 10px;
}
.ed-tier:first-of-type {
  margin-top: 0;
}
.ed-tier-amount {
  font-size: 13px;
  font-weight: 600;
  color: var(--violet);
}
.ed-sponsor-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px;
}
@media (max-width: 700px) {
  .ed-sponsor-grid {
    grid-template-columns: 1fr 1fr;
  }
}
.ed-sponsor {
  height: 100px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 14px;
}
.ed-sponsor img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}
.ed-sponsor-name {
  font-size: 13px;
  margin-top: 6px;
  color: var(--ink);
}
/* Sponsorship packages — shown while an event has defined tiers but no
   signed sponsors yet. The top tier is featured. */
.ed-tiercard-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: 14px;
  margin-top: 4px;
}
/* Two columns on a phone is not enough for a tier name and a six-figure price.
   The media query has to beat .ed-tiercard-grid's own auto-fit, which still
   produced two ~145px columns at 320px and CLIPPED "Rs.1,500,000" at the card
   edge — nowrap stops a price splitting but cannot stop it being cut off. One
   column below 560px, which is where two of them stop being readable. */
@media (max-width: 560px) {
  .ed-tiercard-grid {
    grid-template-columns: 1fr;
    gap: 10px;
  }
  .ed-tiercard {
    padding: 16px 16px 14px;
  }
}
.ed-tiercard {
  position: relative;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: #fff;
  padding: 22px 16px 18px;
  text-align: center;
  overflow: hidden;
}
.ed-tiercard::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 4px;
  background: var(--violet-pale);
}
.ed-tiercard.is-top {
  background: var(--tint-bg);
  border-color: var(--violet-pale);
}
.ed-tiercard.is-top::before {
  background: var(--violet);
}
.ed-tiercard-rank {
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--gray);
  margin-bottom: 6px;
}
.ed-tiercard.is-top .ed-tiercard-rank {
  color: var(--violet);
}
.ed-tiercard-name {
  font-family: "Bricolage Grotesque", sans-serif;
  font-weight: 800;
  font-size: 16px;
  letter-spacing: -0.01em;
  margin-bottom: 10px;
}
.ed-tiercard-amt {
  font-family: "Bricolage Grotesque", sans-serif;
  font-weight: 800;
  font-size: 20px;
  color: var(--violet);
  /* A price must NEVER break across lines. In a narrow card "Rs.1,500,000"
     wrapped after the last comma and read as "Rs.1,500,00" on the first line —
     a different number, and the reader has no way to tell it was wrapped.
     Shrink the type to fit rather than split the figure. */
  white-space: nowrap;
  font-size: clamp(15px, 5.2vw, 20px);
}
.ed-tiercard-cta {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  margin-top: 18px;
}
.ed-tiercard-cta p {
  margin: 0;
  font-size: 14px;
  color: var(--gray);
}
/* Two-up on a tablet. This used to run all the way down, and being LATER in
   the file it beat the one-column rule above on source order — which is why a
   320px phone still got two ~145px columns and clipped "Rs.1,500,000" at the
   card edge. Floored at 561px so the one-column rule owns everything below. */
@media (max-width: 700px) and (min-width: 561px) {
  .ed-tiercard-grid {
    grid-template-columns: 1fr 1fr;
  }
}
.ed-abstract {
  background: var(--tint-bg);
  border: 1px solid var(--violet-pale);
  border-radius: 12px;
  padding: 20px;
}
/* Modals (replaces Bootstrap modal) */
.ed-modal {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: none;
  align-items: flex-start;
  justify-content: center;
  background: rgba(22, 24, 29, 0.55);
  padding: 32px 16px;
  overflow-y: auto;
}
.ed-modal.show {
  display: flex;
}
.ed-modal-dialog {
  background: #fff;
  border-radius: 16px;
  max-width: 640px;
  width: 100%;
  margin: auto;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.3);
  /* Never taller than the screen: the BODY scrolls and the footer stays put,
     so the primary action is always reachable. A long booking form used to
     grow the dialog to 1233px on a 780px phone and push Continue out of
     sight — you had to scroll the whole overlay to find it. */
  display: flex;
  flex-direction: column;
  max-height: calc(100vh - 64px);
}
.ed-modal-head {
  display: flex;
  flex: none;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding: 20px 24px;
  border-bottom: 1px solid var(--border);
}
.ed-modal-title {
  font-family: "Bricolage Grotesque", sans-serif;
  font-size: 18px;
  font-weight: 800;
  margin: 0;
  letter-spacing: -0.02em;
}
.ed-modal-close {
  background: none;
  border: 0;
  font-size: 24px;
  cursor: pointer;
  color: var(--gray);
  line-height: 1;
  padding: 2px 6px;
}
.ed-modal-close:hover {
  color: var(--ink);
}
.ed-modal-body {
  padding: 24px;
  overflow-y: auto;
  /* The part that scrolls when the form is longer than the screen. */
  flex: 1 1 auto;
  -webkit-overflow-scrolling: touch;
}
.ed-modal-foot {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  padding: 16px 24px;
  border-top: 1px solid var(--border);
  flex: none;
  background: #fff;
  border-radius: 0 0 16px 16px;
}
body.ed-modal-open {
  overflow: hidden;
}
.ed-check {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  font-size: 14px;
  cursor: pointer;
  color: var(--ink);
}
.ed-check input {
  accent-color: var(--violet);
  width: 16px;
  height: 16px;
  margin-top: 2px;
  flex: none;
}
.ed-accompany {
  background: var(--tint-bg);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px;
  margin-bottom: 14px;
}
.ed-accompany-title {
  font-size: 13px;
  font-weight: 700;
  color: var(--violet);
  margin-bottom: 10px;
}
.ed-summary {
  background: var(--tint-bg);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px;
  margin-top: 16px;
}
.ed-summary-title {
  font-weight: 700;
  font-size: 14px;
  margin-bottom: 10px;
}
.ed-pay-title {
  font-weight: 700;
  font-size: 14px;
  margin-bottom: 6px;
}
.ed-bank {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px;
  margin: 10px 0;
}
.ed-bank-title {
  font-weight: 700;
  font-size: 13px;
  margin-bottom: 8px;
  color: var(--violet);
}
.ed-bank-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px 14px;
}
.ed-bank-grid p {
  margin: 0;
  font-size: 13px;
}
.ed-bank-grid p span {
  display: block;
  color: var(--gray);
  font-size: 11px;
}
.ed-bank-qr {
  text-align: center;
  margin-top: 12px;
}
.ed-bank-qr img {
  max-width: 200px;
  border: 1px solid var(--border);
  border-radius: 10px;
}
.invalid-feedback {
  display: none;
  font-size: 12px;
  color: #dc2626;
  margin-top: 4px;
}
.was-validated input:invalid ~ .invalid-feedback,
.was-validated select:invalid ~ .invalid-feedback {
  display: block;
}
.was-validated input:invalid,
.was-validated select:invalid {
  border-color: #dc2626;
}
/* Toasts (booking/save/notify feedback) */
.notification-toast {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 200;
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--border);
  border-left: 4px solid var(--violet);
  border-radius: 12px;
  box-shadow: 0 12px 32px rgba(22, 24, 29, 0.18);
  padding: 14px 18px;
  max-width: 380px;
  opacity: 0;
  transform: translateY(12px);
  transition:
    opacity 0.25s,
    transform 0.25s;
  font-size: 14px;
}
.notification-toast.show {
  opacity: 1;
  transform: none;
}
.notification-toast.error {
  border-left-color: var(--danger-fg);
}
.notification-toast.ok {
  border-left-color: var(--ok-fg);
}
.notification-toast.warn {
  border-left-color: var(--warn-fg);
}
.notification-toast.info {
  border-left-color: var(--info-fg);
}

/* ── Events listing page (.ev-) ──────────────────────────────────── */
/* ---- shell ---------------------------------------------------------- */
.ev-hero {
  position: relative;
  overflow: hidden;
  background: #fff;
  border-bottom: 1px solid var(--border);
}
.ev-hero > .container {
  position: relative;
  z-index: 1;
}
.ev-hero-in {
  padding-block: clamp(24px, 3.4vw, 38px) clamp(18px, 2.4vw, 26px);
}
.ev-hero h1 {
  /* The page-title tier — see .pg-head h1. This was clamp(24px,4vw,34px),
     a whole step smaller than every other page title on the site. */
  font-size: clamp(26px, 4.6vw, 44px);
  font-weight: 800;
  margin: 0 0 5px;
  letter-spacing: -0.03em;
  line-height: 1.12;
  text-wrap: balance;
}
.ev-hero p {
  color: var(--gray);
  margin: 0 0 clamp(14px, 2vw, 18px);
  /* The page-lede tier — matches About, Contact and the account page heads. */
  font-size: clamp(15px, 1.8vw, 17px);
  line-height: 1.55;
}
.ev-searchbar {
  display: flex;
  align-items: center;
  gap: 8px;
  background: #fff;
  border: 1px solid #e4e0ef;
  border-radius: 12px;
  padding: 5px 5px 5px 14px;
  max-width: 520px;
  transition:
    border-color 0.15s,
    box-shadow 0.15s;
}
.ev-searchbar:focus-within {
  border-color: var(--violet);
  box-shadow: 0 0 0 4px rgba(124, 58, 237, 0.09);
}
.ev-searchbar svg {
  width: 17px;
  height: 17px;
  color: var(--gray);
  flex: none;
}
.ev-searchbar input {
  flex: 1;
  border: none;
  outline: none;
  font-family: inherit;
  font-size: 14.5px;
  color: var(--ink);
  background: transparent;
  padding: 9px 0;
  min-width: 0;
}
.ev-searchbar button {
  flex: none;
}

.ev-layout {
  display: grid;
  grid-template-columns: 236px 1fr;
  gap: 34px;
  align-items: start;
}

/* ---- sidebar -------------------------------------------------------- */
/* Right padding keeps the date inputs clear of the scrollbar gutter. */
.ev-side {
  position: sticky;
  top: 70px;
  max-height: calc(100vh - 94px);
  overflow-y: auto;
  padding: 2px 14px 8px 0;
  scrollbar-width: thin;
}
.ev-side::-webkit-scrollbar {
  width: 5px;
}
.ev-side::-webkit-scrollbar-thumb {
  background: #e4e0ef;
  border-radius: 3px;
}
.ev-side-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border);
}
.ev-side-head h2 {
  font-size: 13px;
  margin: 0;
  font-weight: 700;
  letter-spacing: 0.02em;
}
.ev-clear {
  font-size: 12px;
  font-weight: 600;
}
/* Collapsible filter groups. Each is a <details>; the summary is the header
     with a chevron and, when collapsed, a count of what's active inside.
     brand.css styles bare <details> as an FAQ accordion card (border, padding
     and a +/- ::after marker), so those have to be reset here. */
.ev-fgroup {
  border: none;
  border-bottom: 1px solid var(--border);
  border-radius: 0;
  padding: 0;
  background: transparent;
}
.ev-fgroup:last-of-type {
  border-bottom: none;
}
details.ev-fgroup > summary::after,
details.ev-fgroup[open] > summary::after {
  content: "";
  display: none;
}
.ev-fgroup .ev-fbody,
.ev-fgroup .ev-fbody div {
  font-size: inherit;
  line-height: inherit;
  color: inherit;
  padding-top: 0;
}
.ev-fgroup > summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 13px 0;
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #7a7488;
  font-weight: 700;
  user-select: none;
}
.ev-fgroup > summary::-webkit-details-marker {
  display: none;
}
.ev-fgroup > summary:hover {
  color: var(--violet);
}
.ev-fgroup > summary .chev {
  margin-left: auto;
  flex: none;
  width: 14px;
  height: 14px;
  color: #b4aec0;
  transition: transform 0.18s;
}
.ev-fgroup[open] > summary .chev {
  transform: rotate(180deg);
}
.ev-fgroup > summary .badge-n {
  background: var(--violet);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  min-width: 16px;
  height: 16px;
  border-radius: 100px;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 0 5px;
  letter-spacing: 0;
}
.ev-fgroup[data-active]:not([open]) > summary .badge-n {
  display: inline-flex;
}
.ev-fbody {
  padding: 0 0 14px;
}

.ev-opt {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 4px 0;
  font-size: 13.5px;
  color: var(--ink);
  cursor: pointer;
  line-height: 1.35;
}
.ev-opt input {
  accent-color: var(--violet);
  width: 14px;
  height: 14px;
  flex: none;

  margin: 0;
  cursor: pointer;
}
.ev-opt:hover {
  color: var(--violet);
}
.ev-opt .n {
  margin-left: auto;
  font-size: 11.5px;
  color: #a8a2b4;
  font-variant-numeric: tabular-nums;
}
.ev-scroll {
  max-height: 186px;
  overflow-y: auto;
  margin: 0 -4px;
  padding: 0 4px;
  scrollbar-width: thin;
}
.ev-scroll::-webkit-scrollbar {
  width: 5px;
}
.ev-scroll::-webkit-scrollbar-thumb {
  background: #e4e0ef;
  border-radius: 3px;
}
/* Type-to-filter box for long option lists (categories) */
.ev-find {
  position: relative;
  margin-bottom: 8px;
}
.ev-find input {
  width: 100%;
  padding: 7px 9px 7px 27px;
  border: 1px solid #e4e0ef;
  border-radius: 8px;
  font-size: 12.5px;
  font-family: inherit;
  color: var(--ink);
  background: #fff;
  outline: none;
  box-sizing: border-box;
}
.ev-find input:focus {
  border-color: var(--violet);
}
.ev-find svg {
  position: absolute;
  left: 8px;
  top: 50%;
  transform: translateY(-50%);
  width: 13px;
  height: 13px;
  color: #b4aec0;
  pointer-events: none;
}
.ev-nohit {
  font-size: 12px;
  color: #a8a2b4;
  padding: 4px 0;
  display: none;
}

/* Searchable single-select (native <select> stays the source of truth for the
     form; this is a light custom UI over it — no jQuery/Select2 needed). */
.ev-ss {
  position: relative;
}
.ev-ss > select {
  position: absolute;
  opacity: 0;
  pointer-events: none;
  width: 1px;
  height: 1px;
}
/* Filters on a TOUCH screen. The rows are 22px tall on a desktop, which is
   fine for a cursor and half what a finger needs. Keyed off the pointer, not
   the width, so a small laptop window keeps the compact rail. */
@media (pointer: coarse) {
  .ev-opt {
    padding: 9px 0;
    font-size: 14.5px;
  }
  .ev-opt input {
    width: 18px;
    height: 18px;
  }
  .ev-fgroup > summary {
    padding: 15px 0;
  }
  .ev-ss-btn {
    padding: 11px 12px;
    font-size: 14px;
  }
  .ev-ss-item {
    padding: 10px 10px;
  }
}

.ev-ss-btn {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 11px;
  border: 1px solid #e4e0ef;
  border-radius: 9px;
  background: #fff;
  font-family: inherit;
  font-size: 13px;
  color: var(--ink);
  cursor: pointer;
  text-align: left;
}
.ev-ss-btn:hover {
  border-color: var(--violet-pale);
}
/* In a form the proxy button has to be the same height as the inputs it sits
     beside, or Title and Country read as 34px next to 45px text fields. Keyed on
     the wrapped select carrying .auth-input, which is exactly the form contexts
     (register, my-profile, the dynamic registration form, booking lookup) and
     NOT the events.php facet filters, where compact is deliberate. */
.ev-ss:has(> select.auth-input) .ev-ss-btn {
  padding: 13px 16px;
  border-radius: 10px;
  font-size: 14px;
}

.ev-ss-btn .lbl {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ev-ss-btn .lbl.is-ph {
  color: #a8a2b4;
}
.ev-ss-btn .chev {
  flex: none;
  width: 13px;
  height: 13px;
  color: #b4aec0;
}
.ev-ss[data-open="1"] .ev-ss-btn {
  border-color: var(--violet);
  box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.09);
}
.ev-ss-pop {
  position: absolute;
  z-index: 40;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 10px 26px rgba(22, 24, 29, 0.13);
  padding: 7px;
  display: none;
}
.ev-ss[data-open="1"] .ev-ss-pop {
  display: block;
}
.ev-ss-pop input {
  width: 100%;
  padding: 7px 9px;
  border: 1px solid #e4e0ef;
  border-radius: 7px;
  font-size: 12.5px;
  font-family: inherit;
  outline: none;
  box-sizing: border-box;
  margin-bottom: 5px;
}
.ev-ss-pop input:focus {
  border-color: var(--violet);
}
.ev-ss-list {
  max-height: 194px;
  overflow-y: auto;
  scrollbar-width: thin;
}
.ev-ss-list::-webkit-scrollbar {
  width: 5px;
}
.ev-ss-list::-webkit-scrollbar-thumb {
  background: #e4e0ef;
  border-radius: 3px;
}
.ev-ss-item {
  padding: 7px 9px;
  border-radius: 7px;
  font-size: 13px;
  cursor: pointer;
  line-height: 1.3;
}
.ev-ss-item:hover,
.ev-ss-item.is-cursor {
  background: var(--tint);
  color: var(--violet);
}
.ev-ss-item.is-sel {
  color: var(--violet);
  font-weight: 600;
}

/* Abstract guidelines download: a real target, not a text link buried at
     the end of several hundred words of rules. */
.ed-abs-doc {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 16px;
  padding: 13px 15px;
  border: 1px solid #e4e0ef;
  border-radius: 11px;
  background: #f8f6fd;
  text-decoration: none;
  color: var(--ink);
  transition:
    border-color 0.15s ease,
    background 0.15s ease;
}
.ed-abs-doc:hover {
  border-color: var(--violet);
  background: #f3eeff;
}
.ed-abs-doc svg {
  flex: none;
  color: var(--violet);
}
.ed-abs-doc span {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.ed-abs-doc strong {
  font-size: 14px;
  font-weight: 600;
  overflow-wrap: anywhere;
}
.ed-abs-doc small {
  font-size: 12px;
  color: var(--gray);
}

/* Footer "We accept" strip. Logos sit on a light plate because several of
     the brand marks are dark and the footer is dark; without it Fonepay and
     the card art disappear into the background. */
/* .footer-inner is a wrapping flex row (brand | links); flex-basis:100%
     forces the strip onto its own line instead of squeezing in beside them. */
.footer-pay {
  flex: 0 0 100%;
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  margin-top: 2px;
  padding-top: 16px;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
}
/* .footer-pay-label removed with the "We accept" text — the logos say it.
   The name survives as an aria-label on the list, which costs no pixels. */
.footer-pay-list {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  list-style: none;
  margin: 0;
  padding: 0;
}
.footer-pay-item {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 32px;
  min-width: 50px;
  padding: 3px 8px;
  border-radius: 7px;
  background: #fff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
}
.footer-pay-item img {
  display: block;
  width: auto;
  height: 22px;
  max-width: 56px;
  object-fit: contain;
}
.footer-pay-text {
  font-size: 11.5px;
  font-weight: 600;
  color: #16181d;
  white-space: nowrap;
}
@media (max-width: 560px) {
  .footer-pay {
    gap: 10px;
  }
  .footer-pay-item {
    height: 28px;
    min-width: 44px;
  }
  .footer-pay-item img {
    height: 18px;
    max-width: 46px;
  }
}
.ev-ss-item[hidden] {
  display: none;
}
.ev-ss-empty {
  padding: 8px 9px;
  font-size: 12.5px;
  color: #a8a2b4;
  display: none;
}
.ev-select,
.ev-date {
  width: 100%;
  padding: 8px 11px;
  border: 1px solid #e4e0ef;
  border-radius: 9px;
  font-size: 13px;
  font-family: inherit;
  color: var(--ink);
  background: #fff;
  outline: none;
  box-sizing: border-box;
}
.ev-select:focus,
.ev-date:focus {
  border-color: var(--violet);
}
/* min-width:0 lets the native date input shrink inside its grid cell instead of
     forcing its intrinsic width and overflowing the sidebar. */
.ev-dates {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 7px;
  margin-top: 9px;
}
.ev-dates > div {
  min-width: 0;
}
.ev-dates label {
  font-size: 10.5px;
  color: #9a94a8;
  display: block;
  margin-bottom: 3px;
  font-weight: 600;
}
.ev-date {
  min-width: 0;
  padding: 8px;
  font-size: 12px;
}

/* ---- results -------------------------------------------------------- */
.ev-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}
.ev-count {
  font-size: 13.5px;
  color: var(--gray);
}
.ev-sort {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 12.5px;
  color: var(--gray);
}
.ev-sort .ev-select {
  width: auto;
  min-width: 158px;
  font-size: 12.5px;
  padding: 7px 10px;
}
.ev-chips {
  display: flex;
  gap: 7px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}
.ev-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 9px 4px 11px;
  border-radius: 100px;
  background: var(--tint);
  color: var(--violet);
  font-size: 12px;
  font-weight: 600;
  border: 1px solid transparent;
  transition:
    border-color 0.14s,
    background 0.14s;
}
.ev-chip span {
  font-size: 13px;
  line-height: 1;
  opacity: 0.55;
}
.ev-chip:hover {
  border-color: var(--violet-pale);
  background: #efe8fe;
}
.ev-chip:hover span {
  opacity: 1;
}
.ev-grid {
  display: grid;
  /* Three, not four: at this inventory a four-column grid was one short row
     and a large blank area under the filters. */
  grid-template-columns: repeat(3, 1fr);
  gap: 18px;
}
.ev-mobile-toggle {
  display: none;
}

@media (max-width: 1200px) {
  .ev-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (max-width: 980px) {
  .ev-layout {
    grid-template-columns: 1fr;
    gap: 18px;
  }
  .ev-side {
    position: static;
    max-height: none;
    overflow: visible;
    padding-right: 0;
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 16px;
  }
  .ev-mobile-toggle {
    display: inline-flex;
    margin-bottom: 14px;
  }
  .ev-side[hidden] {
    display: none;
  }
  .ev-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (max-width: 560px) {
  .ev-grid {
    grid-template-columns: 1fr;
    gap: 14px;
  }
}

/* ── Venue detail page (.vn-) ────────────────────────────────────── */
.vn-crumbs {
  font-size: 13px;
  color: var(--gray);
  margin: 28px 0 18px;
}
.vn-crumbs a {
  color: var(--gray);
}
.vn-crumbs a:hover {
  color: var(--violet);
}
.vn-cover {
  aspect-ratio: 16/9;
  border-radius: 16px;
  overflow: hidden;
  background: linear-gradient(135deg, #7c3aed, #4c1d95);
}
.vn-cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.vn-thumbs {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 10px;
  margin-top: 10px;
}
.vn-thumbs button {
  padding: 0;
  border: 2px solid transparent;
  border-radius: 10px;
  overflow: hidden;
  cursor: pointer;
  background: none;
  aspect-ratio: 4/3;
}
.vn-thumbs button.on {
  border-color: var(--violet);
}
.vn-thumbs img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.vn-h1 {
  /* The page-title tier — see .pg-head h1. */
  font-size: clamp(26px, 4.6vw, 44px);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.1;
  margin: 22px 0 10px;
  text-wrap: balance;
}
.vn-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
  align-items: center;
  font-size: 14px;
  color: var(--gray);
}
.vn-meta span {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.vn-meta svg {
  flex: none;
}
.vn-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 360px;
  gap: 40px;
  align-items: start;
  margin-top: 36px;
  padding-bottom: 90px;
}
.vn-section {
  margin-bottom: 40px;
}
.vn-section h2 {
  font-size: 24px;
  font-weight: 800;
  margin: 0 0 16px;
}
.vn-desc {
  font-size: 15px;
  line-height: 1.7;
  color: #4b5563;
  margin: 0;
}
.vn-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.vn-card {
  border: 1px solid var(--border);
  border-radius: 14px;
  background: #fff;
  padding: 24px;
  margin-bottom: 16px;
}
.vn-card h3 {
  font-size: 16px;
  margin: 0 0 14px;
  font-family: "Familjen Grotesk", sans-serif;
  letter-spacing: 0;
}
.vn-rows {
  display: flex;
  flex-direction: column;
}
.vn-row {
  display: flex;
  justify-content: space-between;
  gap: 14px;
  font-size: 14px;
  padding: 8px 0;
  border-bottom: 1px solid #f3f0fa;
}
.vn-row:last-child {
  border-bottom: none;
  padding-bottom: 0;
}
.vn-row .k {
  color: var(--gray);
  flex: none;
}
.vn-row .v {
  font-weight: 600;
  text-align: right;
  min-width: 0;
  overflow-wrap: anywhere;
}
.vn-contact-line {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 14px;
  padding: 6px 0;
}
.vn-contact-line svg {
  flex: none;
  color: var(--violet);
}
.vn-org {
  display: flex;
  gap: 12px;
  align-items: center;
  margin-bottom: 14px;
}
.vn-org img {
  /* CONTAIN, not cover. Org logos range from a square crest to a wide
     wordmark; cover cropped a wordmark to its middle, so "Birat Medical
     College Teaching Hospital" rendered as the unreadable fragments
     "BIR / MEDICAL / TEACH / HOSPI". A wider box so a wordmark has room,
     with the artwork fitted inside it. */
  width: 64px;
  height: 44px;
  flex: none;
  border-radius: 10px;
  object-fit: contain;
  background: #fff;
}
.vn-org .ph {
  width: 44px;
  height: 44px;
  border-radius: 10px;
  background: var(--tint);
  color: var(--violet);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  font-family: "Bricolage Grotesque", sans-serif;
}
.vn-org small {
  display: block;
  font-size: 12px;
  color: var(--gray);
}
.vn-org strong {
  font-size: 15px;
}
.vn-cta .btn {
  display: block;
  width: 100%;
  text-align: center;
  box-sizing: border-box;
}
.vn-share {
  margin-top: 10px;
  border: none;
}
.vn-policy {
  font-size: 13px;
  line-height: 1.6;
  color: var(--gray);
}
.vn-policy strong {
  display: block;
  color: var(--ink);
  font-size: 14px;
  margin-bottom: 4px;
}
.vn-policy + .vn-policy {
  margin-top: 14px;
}
.vn-toast {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--ink);
  color: #fff;
  font-size: 13px;
  padding: 10px 18px;
  border-radius: 100px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s;
  z-index: 80;
}
.vn-toast.show {
  opacity: 1;
}
@media (max-width: 900px) {
  .vn-layout {
    grid-template-columns: 1fr;
    gap: 0;
  }
  .vn-thumbs {
    grid-template-columns: repeat(4, 1fr);
  }
}

/* Profile tabs: quiet underline bar above the form cards. On phones the bar
   scrolls sideways rather than wrapping — three labels stay one gesture. */
.mp-tabs {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid var(--border);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.mp-tabs::-webkit-scrollbar {
  display: none;
}
.mp-tab {
  appearance: none;
  background: none;
  border: 0;
  border-bottom: 2.5px solid transparent;
  padding: 10px 14px;
  margin-bottom: -1px;
  font: inherit;
  font-size: 14px;
  font-weight: 650;
  color: var(--gray);
  cursor: pointer;
  white-space: nowrap;
}
.mp-tab:hover {
  color: var(--ink);
}
.mp-tab.is-active {
  color: var(--violet);
  border-bottom-color: var(--violet);
}
.mp-pane {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

/* ── My profile page (.mp-) ──────────────────────────────────────── */
.mp-layout {
  display: grid;
  grid-template-columns: 1fr 340px;
  gap: 24px;
  align-items: start;
}
.mp-form {
  display: flex;
  flex-direction: column;
  gap: 20px;
}
.mp-card {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 28px;
}
.mp-card h2 {
  font-size: 18px;
  font-weight: 800;
  margin: 0 0 4px;
}
.mp-card .mp-sub {
  font-size: 13px;
  color: var(--gray);
  margin: 0 0 20px;
}
.mp-hint {
  font-size: 12px;
  color: var(--gray);
  margin-top: 4px;
}
/* Dial code + national number, one visual field. The code select sizes to
   its content and never squeezes the number on phones. */
.mp-phone {
  display: flex;
  gap: 8px;
}
.mp-phone-dial {
  flex: 0 0 auto;
  width: 132px;
  min-width: 0;
}
.mp-phone input {
  flex: 1;
  min-width: 0;
}
@media (max-width: 560px) {
  .mp-phone-dial {
    width: 112px;
  }
}
.mp-grid-3 {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 14px;
}
.mp-photo-row {
  display: flex;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
}
.profile-photo,
.mp-photo-lg {
  border-radius: 16px;
  object-fit: cover;
  border: 3px solid var(--border);
}
.profile-photo {
  width: 96px;
  height: 96px;
}
.profile-photo-placeholder {
  border-radius: 16px;
  background: var(--tint);
  color: var(--violet);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: "Bricolage Grotesque", sans-serif;
  font-weight: 800;
  border: 3px solid var(--border);
}
.mp-photo-row .profile-photo-placeholder {
  width: 96px;
  height: 96px;
  font-size: 32px;
  flex: 0 0 96px;
}
.mp-file {
  font-size: 13px;
  font-family: inherit;
  color: var(--gray);
}
.mp-file::file-selector-button {
  background: var(--tint);
  color: var(--violet);
  border: none;
  border-radius: 9px;
  padding: 9px 16px;
  font-weight: 600;
  font-size: 13px;
  font-family: inherit;
  cursor: pointer;
  margin-right: 12px;
}
.mp-file::file-selector-button:hover {
  background: #ede5fd;
}
.mp-addr-row {
  display: flex;
  gap: 10px;
  align-items: stretch;
}
.mp-addr-row .auth-input {
  flex: 1;
}
.mp-addr-row .btn-sm {
  white-space: nowrap;
  flex: 0 0 auto;
  align-self: center;
}
.mp-check {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  cursor: pointer;
  margin-bottom: 14px;
}
.mp-check input {
  accent-color: var(--violet);
  width: 16px;
  height: 16px;
  margin-top: 2px;
  flex: 0 0 auto;
}
.mp-check strong {
  display: block;
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
}
.mp-check small {
  font-size: 12px;
  color: var(--gray);
  line-height: 1.5;
}
.mp-submit-bar {
  display: flex;
  gap: 12px;
  align-items: center;
}
.mp-aside {
  display: flex;
  flex-direction: column;
  gap: 20px;
  position: sticky;
  top: 84px;
}
.mp-overview {
  text-align: center;
}
.mp-overview .profile-photo-placeholder {
  width: 112px;
  height: 112px;
  font-size: 38px;
  margin: 0 auto;
}
.mp-overview img {
  width: 112px;
  height: 112px;
  border-radius: 50%;
  object-fit: cover;
  border: 4px solid var(--border);
  display: block;
  margin: 0 auto;
}
.mp-overview h3 {
  font-size: 18px;
  margin: 16px 0 2px;
  font-family: "Familjen Grotesk", sans-serif;
  letter-spacing: 0;
}
.mp-overview p {
  font-size: 13px;
  color: var(--gray);
  margin: 0;
}
.mp-info-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 0;
}
.mp-info-row + .mp-info-row {
  border-top: 1px solid #f3f0fa;
}
.mp-info-glyph {
  width: 38px;
  height: 38px;
  border-radius: 10px;
  background: var(--tint);
  color: var(--violet);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 38px;
}
.mp-info-row b {
  display: block;
  font-size: 14px;
  font-weight: 600;
  word-break: break-word;
}
.mp-info-row small {
  font-size: 12px;
  color: var(--gray);
}
.mp-links {
  display: flex;
  flex-direction: column;
}
.mp-links a {
  padding: 10px 12px;
  border-radius: 9px;
  color: var(--ink);
  font-size: 14px;
  font-weight: 500;
  display: flex;
  align-items: center;
  gap: 10px;
}
.mp-links a:hover {
  background: var(--tint-bg);
  color: var(--violet);
}
.mp-links svg {
  color: var(--violet);
  flex: 0 0 auto;
}
.mp-msg {
  border-radius: 12px;
  padding: 14px 16px;
  font-size: 14px;
  margin-bottom: 24px;
  border: 1px solid;
}
.mp-msg.success {
  background: #f0fdf4;
  color: #15803d;
  border-color: #bbf7d0;
}
.mp-msg.error {
  background: #fef2f2;
  color: #b91c1c;
  border-color: #fecaca;
}

/* KYC banner: shown when this page was opened from a booking whose event
   issues badges. It says which event is asking and what is still outstanding,
   and keeps a way back to that booking — someone sent here from a locked
   ticket should never have to find their way back by hand. */
.mp-kyc {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  border-radius: 12px;
  padding: 15px 17px;
  margin-bottom: 22px;
  border: 1px solid #fde68a;
  background: #fffdf7;
}
.mp-kyc.is-done {
  border-color: #bbf7d0;
  background: #f0fdf4;
}
.mp-kyc-ico {
  flex: none;
  width: 38px;
  height: 38px;
  border-radius: 10px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: #fef3c7;
  color: #92400e;
}
.mp-kyc.is-done .mp-kyc-ico {
  background: #dcfce7;
  color: #166534;
}
.mp-kyc-txt {
  flex: 1;
  min-width: 0;
}
.mp-kyc-txt strong {
  display: block;
  font-size: 15px;
  letter-spacing: -0.01em;
}
.mp-kyc-txt p {
  margin: 4px 0 0;
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--gray);
}
.mp-kyc-txt p strong {
  display: inline;
  font-size: inherit;
  color: var(--ink);
}
.mp-kyc .btn {
  flex: none;
  align-self: center;
  white-space: nowrap;
}
@media (max-width: 640px) {
  /* Stack it: a "Back to booking" button beside two lines of text leaves the
     text about eight characters wide on a phone. */
  .mp-kyc {
    flex-wrap: wrap;
    padding: 13px 14px;
    gap: 11px;
  }
  .mp-kyc-txt {
    flex: 1 1 auto;
  }
  .mp-kyc .btn {
    width: 100%;
    justify-content: center;
    margin-left: 0;
  }
}
@media (max-width: 900px) {
  .mp-layout {
    grid-template-columns: 1fr;
  }
  .mp-aside {
    position: static;
  }
  .mp-grid-3 {
    grid-template-columns: 1fr;
  }
  .mp-addr-row {
    flex-direction: column;
    align-items: stretch;
  }
}

/* ── My bookings page (.mb-) ─────────────────────────────────────── */
.mb-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
/* Compact rows: a list of bookings is scanned, not read. The row stays on ONE
   line until 700px — the actions column is sized so it never wraps under the
   title at laptop widths. */
.mb-card {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px 16px;
  display: flex;
  gap: 16px;
  align-items: center;
  justify-content: space-between;
  flex-wrap: nowrap;
}
.mb-card:hover {
  border-color: var(--violet-pale);
  box-shadow: 0 8px 24px rgba(124, 58, 237, 0.08);
}
.mb-main {
  display: flex;
  gap: 13px;
  align-items: center;
  flex: 1 1 auto;
  min-width: 0;
}
/* min-width:0 so a long event title ellipses instead of shoving the actions
   off the row. */
.mb-main > div:last-child {
  min-width: 0;
  flex: 1;
}
.mb-thumb {
  width: 64px;
  height: 64px;
  border-radius: 10px;
  object-fit: cover;
  flex: 0 0 64px;
  background: var(--tint);
}
.mb-thumb-fallback {
  width: 64px;
  height: 64px;
  border-radius: 10px;
  flex: 0 0 64px;
  background: var(--tint);
  color: var(--violet);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: "Bricolage Grotesque", sans-serif;
  font-weight: 800;
  font-size: 18px;
}
.mb-title-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 6px;
}
/* The title WRAPS; it is never truncated to a single line.
   It used to be nowrap + ellipsis, which failed twice over. It had no
   min-width:0, so as a flex item its min-content (448px for a 64-character
   conference name) became its floor and the title ran off the card instead
   of ellipsising at all. And once that was fixed, the ellipsis itself was
   wrong in the middle band: between 700px and ~1000px the title shares the
   row with the badges and the actions, so it was cut to "The XVth National
   Conferen…" with visible empty space beside it while the address below
   wrapped to four lines. Two lines of real title beats one line of guess.
   min-width:0 stays: it is what lets the box shrink at all. */
.mb-title-row h3 {
  font-size: 15.5px;
  margin: 0;
  font-family: "Familjen Grotesk", sans-serif;
  letter-spacing: 0;
  min-width: 0;
  max-width: 100%;
  line-height: 1.3;
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.mb-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 14px;
  font-size: 12.5px;
  color: var(--gray);
}
/* Same trap: a long venue address is one flex item, and without min-width:0
   it refuses to wrap and pushes past the card edge. */
.mb-meta span {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}
.mb-meta svg {
  flex: 0 0 auto;
  color: var(--violet);
}
.mb-ref {
  font-size: 11.5px;
  color: var(--gray);
  margin-top: 5px;
}
.mb-ref b {
  color: var(--ink);
  font-weight: 600;
}
.mb-side {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 7px;
  flex: 0 0 auto;
}
.mb-amount {
  font-family: "Bricolage Grotesque", sans-serif;
  font-size: 16px;
  font-weight: 800;
  color: var(--ink);
  white-space: nowrap;
}
/* Every action is a real button. Bare text links read as an afterthought
   beside a filled primary; the hierarchy comes from FILL instead — the
   primary is tinted, the others outlined, destructive outlined red. */
.mb-actions {
  display: flex;
  gap: 7px;
  align-items: center;
  justify-content: flex-end;
  white-space: nowrap;
}
.mb-actions .btn-sm {
  padding: 7px 13px;
  font-size: 12.5px;
}
.mb-link {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 7px 12px;
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink);
  cursor: pointer;
  text-decoration: none;
  line-height: 1.2;
}
.mb-link:hover {
  border-color: var(--violet);
  color: var(--violet);
}
.mb-link.is-danger {
  color: #b91c1c;
  border-color: #fecaca;
  background: #fef2f2;
}
.mb-link.is-danger:hover {
  background: #fee2e2;
  border-color: #fca5a5;
  color: #991b1b;
}
.mb-btn-danger {
  background: #fef2f2;
  color: #b91c1c;
  border: 1px solid #fecaca;
  cursor: pointer;
  font-family: inherit;
}
.mb-btn-danger:hover {
  background: #fee2e2;
  color: #991b1b;
}
.mb-btn-download {
  background: #ecfdf5;
  color: #047857;
  border: 1px solid #a7f3d0;
  cursor: pointer;
  font-family: inherit;
}
.mb-btn-download:hover {
  background: #d1fae5;
}
.mb-pill {
  display: inline-flex;
  align-items: center;
  padding: 4px 12px;
  border-radius: 100px;
  font-size: 12px;
  font-weight: 700;
}
.mb-pill.st-confirmed {
  background: #ecfdf5;
  color: #047857;
  border: 1px solid #a7f3d0;
}
.mb-pill.st-pending {
  background: #fffbeb;
  color: #b45309;
  border: 1px solid #fde68a;
}
.mb-pill.st-cancelled {
  background: #fef2f2;
  color: #b91c1c;
  border: 1px solid #fecaca;
}
.mb-pill.st-other {
  background: #f3f4f6;
  color: #4b5563;
  border: 1px solid #e5e7eb;
}
.mb-pill.tickets {
  background: var(--tint);
  color: var(--violet);
  border: 1px solid #e4dafa;
  font-weight: 600;
}
.mb-highlight {
  border-color: #a7f3d0;
  box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.15);
}
@keyframes mb-flash {
  0%,
  100% {
    background: #fff;
  }
  50% {
    background: #ecfdf5;
  }
}
.mb-highlight.flash {
  animation: mb-flash 2s ease-in-out;
}
.mb-aside {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
  margin-top: 36px;
}
.mb-aside ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 9px;
  font-size: 14px;
  color: var(--gray);
}
.mb-aside li::before {
  content: "\2713";
  color: var(--violet);
  font-weight: 800;
  margin-right: 9px;
}
.mb-overlay {
  position: fixed;
  inset: 0;
  background: rgba(22, 24, 29, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 100;
  padding: 20px;
}
.mb-modal {
  background: #fff;
  border-radius: 16px;
  max-width: 460px;
  width: 100%;
  padding: 28px;
}
.mb-modal h3 {
  font-size: 19px;
  margin: 0 0 12px;
}
.mb-modal p {
  font-size: 14px;
  line-height: 1.55;
  color: var(--gray);
  margin: 0 0 14px;
}
.mb-modal .warn {
  background: #fffbeb;
  border: 1px solid #fde68a;
  color: #b45309;
  border-radius: 10px;
  padding: 12px 14px;
  font-size: 13px;
  margin-bottom: 20px;
}
.mb-modal-actions {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
}
/* 760, not 700: between those two the card is still a row, and the amount
   plus four nowrap action buttons take ~330px of it — enough to squeeze a
   64-character conference name down to "The XVth National Conference of
   the…" with empty space beside it. Above 760 the full title fits in two
   lines beside the actions; below it, the card stacks and the title gets
   the width. */
@media (max-width: 760px) {
  .mb-card {
    flex-direction: column;
    align-items: stretch;
    flex-wrap: wrap;
  }
  .mb-side {
    align-items: flex-start;
    width: 100%;
    flex-direction: row;
    justify-content: space-between;
    gap: 10px;
    padding-top: 11px;
    border-top: 1px solid var(--border);
  }
  .mb-actions {
    justify-content: flex-end;
    flex: 1;
  }
  .mb-aside {
    grid-template-columns: 1fr;
  }
  /* A stacked card has the width for a third line, and no competing column
     to protect. */
  .mb-title-row h3 {
    -webkit-line-clamp: 3;
  }
  /* Top-align the media object: beside a title that now wraps, a vertically
     centred photo floats against the badges with nothing left of the title. */
  .mb-main {
    align-items: flex-start;
  }
}
/* Phones. The amount and up to four actions in one nowrap row is ~75px wider
   than the screen, and it dragged the whole page sideways. Below 560px the
   amount takes its own line and the actions wrap, with the row's ONE primary
   action spanning the full width — the easiest thing to hit with a thumb. */
@media (max-width: 560px) {
  .mb-side {
    flex-direction: column;
    align-items: stretch;
    gap: 9px;
  }
  .mb-actions {
    flex-wrap: wrap;
    white-space: normal;
    justify-content: flex-start;
    gap: 6px;
  }
  .mb-actions .mb-link {
    flex: 0 0 auto;
  }
  .mb-actions .btn {
    flex: 1 0 100%;
    justify-content: center;
  }
}

/* ── About page (.ab-) ───────────────────────────────────────────── */
.ab-hero {
  background: var(--tint-bg);
  border-bottom: 1px solid #f0edf7;
}
.ab-hero .container {
  padding-block: clamp(26px, 4vw, 52px) clamp(20px, 3vw, 38px);
}
.ab-hero h1 {
  font-size: clamp(26px, 4.6vw, 44px);
  line-height: 1.1;
  letter-spacing: -0.03em;
  font-weight: 800;
  margin: 0 0 12px;
  text-wrap: balance;
}
.ab-hero p {
  font-size: 17px;
  line-height: 1.6;
  color: var(--gray);
  max-width: 640px;
  margin: 0 0 32px;
}
.ab-stats {
  display: flex;
  gap: 56px;
  flex-wrap: wrap;
  padding-top: 24px;
  border-top: 1px solid #e4e0ef;
}
.ab-stats .num {
  font-family: "Bricolage Grotesque", sans-serif;
  font-size: 32px;
  font-weight: 800;
  color: var(--violet);
  line-height: 1.1;
}
.ab-stats .lbl {
  font-size: 13px;
  color: var(--gray);
}
.ab-grid2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
}
.ab-grid4 {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 20px;
}
.ab-role {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--violet);
  margin: 0;
}
@media (max-width: 1000px) {
  .ab-grid4 {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (max-width: 900px) {
  .ab-grid2 {
    grid-template-columns: 1fr;
  }
  .ab-stats {
    gap: 28px;
  }
}
@media (max-width: 640px) {
  .ab-grid4 {
    grid-template-columns: 1fr;
  }
}

/* ── Contact page (.ct-) ─────────────────────────────────────────── */
.ct-hero {
  background: var(--tint-bg);
  border-bottom: 1px solid #f0edf7;
}
.ct-hero .container {
  padding-block: clamp(26px, 4vw, 52px) clamp(22px, 3.4vw, 44px);
}
.ct-hero h1 {
  font-size: clamp(26px, 4.6vw, 44px);
  line-height: 1.1;
  letter-spacing: -0.03em;
  font-weight: 800;
  margin: 0 0 12px;
  text-wrap: balance;
}
.ct-hero p {
  font-size: 17px;
  line-height: 1.6;
  color: var(--gray);
  max-width: 620px;
  margin: 0;
}
.ct-cols {
  display: grid;
  grid-template-columns: 380px 1fr;
  gap: 56px;
  align-items: start;
}
.ct-info {
  display: flex;
  flex-direction: column;
  gap: 24px;
}
.ct-item {
  display: flex;
  gap: 14px;
  align-items: flex-start;
}
.ct-item .ct-ic {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  border-radius: 10px;
  background: var(--tint);
  color: var(--violet);
  display: flex;
  align-items: center;
  justify-content: center;
}
.ct-item h3 {
  font-size: 15px;
  font-weight: 700;
  margin: 0 0 4px;
  font-family: "Familjen Grotesk", sans-serif;
  letter-spacing: 0;
}
.ct-item p,
.ct-item address {
  font-size: 14px;
  line-height: 1.55;
  color: var(--gray);
  margin: 0;
  font-style: normal;
}
.ct-item small {
  display: block;
  font-size: 12px;
  color: var(--gray);
  margin-top: 4px;
}
.ct-social {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}
.ct-social a {
  display: inline-block;
  padding: 8px 16px;
  border: 1px solid var(--border);
  border-radius: 100px;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
}
.ct-social a:hover {
  border-color: var(--violet-pale);
  color: var(--violet);
}
.ct-form-card {
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 36px;
  background: #fff;
}
.ct-form textarea.auth-input {
  resize: vertical;
  min-height: 140px;
}
.ct-msg {
  border-radius: 10px;
  padding: 13px 16px;
  font-size: 14px;
  margin-bottom: 18px;
}
.ct-msg.success {
  background: #f0fdf4;
  color: #15803d;
  border: 1px solid #bbf7d0;
}
.ct-msg.error {
  background: #fef2f2;
  color: #b91c1c;
  border: 1px solid #fecaca;
}
@media (max-width: 900px) {
  .ct-cols {
    grid-template-columns: 1fr;
    gap: 28px;
  }
  .ct-form-card {
    padding: 22px;
  }
}

/* ── Organizers listing page (.og-) ──────────────────────────────── */
.og-hero {
  background: var(--tint-bg);
  border-bottom: 1px solid #f0edf7;
}
.og-hero .container {
  padding-block: clamp(26px, 4vw, 52px) clamp(18px, 2.6vw, 34px);
}
.og-hero-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 24px;
  flex-wrap: wrap;
  margin-bottom: 24px;
}
.og-hero h1 {
  font-size: clamp(26px, 4.6vw, 44px);
  line-height: 1.1;
  letter-spacing: -0.03em;
  font-weight: 800;
  margin: 0 0 12px;
  text-wrap: balance;
}
.og-sub {
  /* The page-lede tier — see .ev-hero p. */
  font-size: clamp(15px, 1.8vw, 17px);
  line-height: 1.55;
  color: var(--gray);
  max-width: 560px;
  margin: 0;
}
.og-filter {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  align-items: center;
}
.og-select {
  padding: 11px 14px;
  border-radius: 10px;
  border: 1px solid #e4e0ef;
  font-size: 14px;
  font-family: inherit;
  background: #fff;
  color: var(--ink);
  outline: none;
}
.og-select:focus {
  border-color: var(--violet-pale);
}
.og-count {
  font-size: 13px;
  color: var(--gray);
  margin-bottom: 20px;
  display: flex;
  gap: 14px;
  align-items: baseline;
  flex-wrap: wrap;
}
.og-card {
  gap: 14px;
}
.og-head {
  display: flex;
  align-items: center;
  gap: 14px;
}
.og-head .glyph {
  width: 48px;
  height: 48px;
  font-size: 16px;
  flex: 0 0 auto;
}
/* contain, not cover: a wordmark logo (the hospital one is 1029x544) was
   cropped to a square of its leftmost letters. Fixed height, free width. */
.og-logo {
  width: auto;
  max-width: 110px;
  height: 48px;
  border-radius: 10px;
  object-fit: contain;
  border: 1px solid var(--border);
  background: #fff;
  padding: 3px;
  flex: 0 0 auto;
}
.og-card h3 {
  font-size: 17px;
}
.og-card h3 a {
  color: var(--ink);
}
.og-card h3 a:hover {
  color: var(--violet);
}
.og-loc {
  font-size: 13px;
  color: var(--gray);
  margin-top: 2px;
}
.og-stats {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  font-size: 13px;
  color: var(--gray);
}
.og-stats strong {
  color: var(--ink);
  font-weight: 700;
}
.og-view {
  margin-top: auto;
  text-align: center;
}

/* ── Saved events page (.sv-) ────────────────────────────────────── */
.sv-hero {
  background: var(--tint-bg);
  border-bottom: 1px solid #f0edf7;
}
.sv-hero .container {
  padding-block: clamp(26px, 4vw, 52px) clamp(18px, 2.6vw, 34px);
}
/* Fluid, so the heading isn't stuck at 48px on a phone. */
.sv-hero h1 {
  font-size: clamp(26px, 4.6vw, 44px);
  line-height: 1.1;
  letter-spacing: -0.03em;
  font-weight: 800;
  margin: 0 0 8px;
  text-wrap: balance;
}
.sv-sub {
  font-size: clamp(14px, 1.5vw, 15.5px);
  line-height: 1.55;
  color: var(--gray);
  max-width: 60ch;
  margin: 0;
}
.sv-item {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.sv-item .event-card {
  flex: 1;
}
.sv-meta {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
}
.sv-date {
  font-size: 13px;
  color: var(--gray);
}
.sv-remove {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: #fff;
  border: 1px solid var(--border);
  color: #dc2626;
  cursor: pointer;
}
.sv-remove:hover {
  border-color: #fca5a5;
  background: #fef2f2;
}
.sv-remove[disabled] {
  opacity: 0.5;
  cursor: default;
}

/* ── Error pages (404 / access-denied) ─────────────────── */
.error-state {
  padding-block: clamp(48px, 9vw, 110px);
}
.error-state .display {
  font-size: 44px;
  line-height: 1.1;
  color: var(--violet);
  margin-bottom: 12px;
}
.error-state.is-404 .display {
  font-size: 96px;
  line-height: 1;
}
.error-state h1 {
  font-size: 24px;
  font-weight: 800;
  color: var(--ink);
  margin: 0 0 10px;
}
.error-state p {
  font-size: 15px;
  max-width: 460px;
  margin: 0 auto 28px;
  line-height: 1.6;
}
.error-actions {
  display: flex;
  gap: 12px;
  justify-content: center;
  flex-wrap: wrap;
}
.error-foot {
  font-size: 13px;
  color: var(--gray);
  margin-top: 28px;
}
@media (max-width: 520px) {
  .error-state.is-404 .display {
    font-size: 64px;
  }
}

/* Ticket rows: compact enough that a long ticket list stays scannable. The
   inline margin on .ed-ticket-action is overridden here on purpose. */
.ed-ticket-action {
  margin-top: 10px !important;
}
.ed-ticket-action .btn {
  padding: 7px 14px;
  font-size: 12.5px;
  border-radius: 9px;
}
.ed-ticket .ed-price {
  font-size: 16px;
  line-height: 1.15;
}
.ed-ticket .ed-avail {
  margin-top: 9px;
}
.ed-w100 {
  width: 100%;
}
/* Panel heading row — title left, optional action right (see includes/public/panel.php) */
.ed-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
}
.ed-panel-head .ed-h {
  margin-bottom: 0;
}
.ed-panel-act {
  display: flex;
  gap: 8px;
  flex: none;
}
/* Label/value fact grid used by panel_facts() */
.ed-facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 16px 22px;
  margin: 16px 0 0;
}
.ed-fact dt {
  font-size: 11.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--gray);
  font-weight: 700;
  margin-bottom: 4px;
}
.ed-fact dd {
  margin: 0;
  font-size: 14.5px;
  color: var(--ink);
  font-weight: 600;
  line-height: 1.45;
}
@media (max-width: 900px) {
  .ed-title {
    font-size: 25px;
  }
  .ed-cover img {
    max-height: 280px;
  }
  .ed-meta {
    gap: 8px 14px;
  }
}
.ed-panel.is-tight {
  padding: 14px 22px;
}
/* Slim "browse all" prompt used when there are no related events to show. */
.ed-browse-all {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 14px;
  border: 1px dashed var(--border);
  border-radius: 12px;
  background: #fff;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--violet);
  transition:
    border-color 0.14s,
    background 0.14s;
}
.ed-browse-all:hover {
  border-color: var(--violet-pale);
  background: var(--tint);
  color: var(--violet);
}

/* Ticket list: compact rows so a long list stays readable without clipping. */
#booking-section .ed-tickets {
  display: flex;
  flex-direction: column;
  gap: 0;
}
/* Event website link + promo hashtags in the Event details panel */
.ed-detail-extra {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}
.ed-chip-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 12px;
  border-radius: 100px;
  background: var(--tint);
  color: var(--violet);
  font-size: 12.5px;
  font-weight: 650;
  border: 1px solid transparent;
  transition: border-color 0.14s;
}
.ed-chip-link:hover {
  border-color: var(--violet-pale);
  color: var(--violet);
}
.ed-hashtag {
  display: inline-flex;
  align-items: center;
  padding: 5px 11px;
  border-radius: 100px;
  background: #fff;
  border: 1px solid var(--border);
  color: var(--gray);
  font-size: 12.5px;
  font-weight: 600;
}

/* ==========================================================================
   Dynamic registration form + payment options (public booking modal)
   Renders event_form_fields on event-detail.php: a width-aware grid (full /
   half / third), the composite address block, choice groups, the accompanying-
   person toggle switch and the selectable payment-gateway cards.
   ========================================================================== */
.ed-dyn-grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 14px;
  margin-bottom: 16px;
}
.ed-dyn-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
  grid-column: span 6;
}
.ed-dyn-field.ed-w-half {
  grid-column: span 3;
}
.ed-dyn-field.ed-w-third {
  grid-column: span 2;
}
.ed-dyn-field[hidden] {
  display: none !important;
}
.ed-dyn-label {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
}
.ed-dyn-req {
  color: #dc2626;
}
.ed-dyn-field > small.ed-muted {
  font-size: 12px;
  line-height: 1.4;
}
/* Address block: street on its own line, then city/state/postal, then country. */
.ed-dyn-address {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.ed-dyn-address-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}
/* Radio / checkbox groups from the field's options list. */
.ed-dyn-choices {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 18px;
  padding: 4px 0;
}
.ed-dyn-choice {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 14px;
  color: var(--ink);
  cursor: pointer;
}
.ed-dyn-choice input {
  accent-color: var(--violet);
  width: 16px;
  height: 16px;
  flex: none;
  margin: 0;
}
@media (max-width: 640px) {
  .ed-dyn-grid {
    grid-template-columns: 1fr;
    gap: 12px;
  }
  .ed-dyn-field,
  .ed-dyn-field.ed-w-half,
  .ed-dyn-field.ed-w-third {
    grid-column: span 1;
  }
  .ed-dyn-address-row {
    grid-template-columns: 1fr;
  }
}

/* Accompanying-person toggle switch */
.ed-toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 12px 14px;
  margin-bottom: 14px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--tint-bg);
}
.ed-toggle-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.ed-toggle-text strong {
  font-size: 14px;
  color: var(--ink);
}
.ed-toggle-text small {
  font-size: 12.5px;
}
.ed-switch {
  position: relative;
  flex: none;
  display: inline-flex;
  cursor: pointer;
}
.ed-switch input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}
.ed-switch-track {
  display: block;
  width: 44px;
  height: 24px;
  border-radius: 100px;
  background: #d7d2e4;
  transition: background 0.16s;
}
.ed-switch-knob {
  display: block;
  width: 18px;
  height: 18px;
  margin: 3px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgba(15, 10, 40, 0.25);
  transition: transform 0.16s;
}
.ed-switch input:checked + .ed-switch-track {
  background: var(--violet);
}
.ed-switch input:checked + .ed-switch-track .ed-switch-knob {
  transform: translateX(20px);
}
.ed-switch input:focus-visible + .ed-switch-track {
  outline: 2px solid var(--violet);
  outline-offset: 2px;
}

/* Payment gateway option cards (only enabled gateways are rendered) */
.ed-pay-options {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.ed-pay-option {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 12px 14px;
  cursor: pointer;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: #fff;
  transition:
    border-color 0.14s,
    background 0.14s;
}
.ed-pay-option:hover {
  border-color: var(--violet-pale);
  background: var(--tint);
}
.ed-pay-option input {
  accent-color: var(--violet);
  width: 17px;
  height: 17px;
  flex: none;
  margin: 1px 0 0;
}
.ed-pay-option:has(input:checked) {
  border-color: var(--violet);
  background: var(--tint);
}
.ed-pay-option-body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  flex: 1;
}
/* Provider mark at checkout (pg_logo_html). The row is top-aligned for the
   radio, so nudge the mark down to sit level with the method name. */
.ed-pay-option > img,
.ed-pay-option > span:not(.ed-pay-option-body) {
  margin-top: 1px;
}
.ed-pay-option-name {
  font-size: 14px;
  font-weight: 650;
  color: var(--ink);
}
.ed-pay-option-body small {
  font-size: 12.5px;
}

/* ==========================================================================
   Guest checkout — booking modal notice + public ticket page
   Serves booking-lookup.php (the magic-link ticket page, "Find my tickets"
   and the printable ticket) plus the "booking as a guest" note in the
   event-detail booking modal. Prefixes: .ed-guest-* (modal) and .bk-* (page).
   ========================================================================== */

/* "Booking as a guest — your tickets will be emailed to you." */
.ed-guest-note {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin-bottom: 16px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--tint-bg);
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--gray);
}
.ed-guest-note strong {
  color: var(--ink);
  font-weight: 700;
}
.ed-guest-note a {
  color: var(--violet);
  font-weight: 650;
}
.ed-guest-note-icon {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 8px;
  background: var(--tint);
  color: var(--violet);
}

/* ---- Ticket page shell ---- */
.bk-page {
  max-width: 1080px;
}
.bk-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
  margin: 8px 0 18px;
}
.bk-head h1 {
  font-size: 34px;
  font-weight: 800;
  letter-spacing: -0.02em;
  margin: 6px 0 4px;
  line-height: 1.15;
}
.bk-head-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  flex: none;
}
.bk-head-actions .btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}
.bk-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 12px;
  border-radius: 100px;
  background: var(--tint);
  color: var(--violet);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.bk-ref {
  margin: 0;
  font-size: 14px;
  color: var(--gray);
}
.bk-ref strong {
  color: var(--ink);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-weight: 700;
}

.bk-status-row {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}
.bk-pill {
  display: inline-flex;
  align-items: center;
  padding: 5px 12px;
  border-radius: 100px;
  font-size: 12.5px;
  font-weight: 650;
  border: 1px solid transparent;
}
.bk-pill-ok {
  background: #ecfdf5;
  border-color: #a7f3d0;
  color: #047857;
}
.bk-pill-wait {
  background: #fffbeb;
  border-color: #fde68a;
  color: #b45309;
}
.bk-pill-bad {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c;
}
.bk-pill-neutral {
  background: var(--tint);
  border-color: var(--border);
  color: var(--gray);
}

.bk-guest-tip {
  margin-bottom: 18px;
  line-height: 1.6;
}
.bk-guest-tip a {
  color: var(--violet);
  font-weight: 650;
}

.bk-layout {
  align-items: start;
}
/* Phones: the aside stacks BEFORE the detail panels. The ticket is what this
   page is opened for on a phone — at a venue door, nobody wants to scroll
   past event details to reach the QR. Desktop keeps DOM order (details left,
   ticket right), so this is a mobile-only reversal. */
@media (max-width: 900px) {
  .bk-layout {
    display: flex;
    flex-direction: column;
  }
  .bk-layout > .bk-side {
    order: 1;
  }
  .bk-layout > .bk-main {
    order: 2;
  }
}
.bk-main {
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-width: 0;
}
.bk-side {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* Ticket lines table */
/* Scrolls on a narrow screen rather than breaking the page. The right-edge
   fade tells the reader there IS more — a table that scrolls with no visual
   cue reads as truncated. It sits only while the content overflows. */
.bk-table-wrap {
  overflow-x: auto;
  margin-top: 14px;
  -webkit-overflow-scrolling: touch;
  background: linear-gradient(
      to left,
      var(--surface, #fff),
      rgba(255, 255, 255, 0)
    )
    right/22px 100% no-repeat;
  background-attachment: local;
}
.bk-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
  min-width: 420px;
}
.bk-table th {
  text-align: left;
  font-size: 11.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--gray);
  font-weight: 700;
  padding: 0 12px 8px 0;
  border-bottom: 1px solid var(--border);
}
.bk-table td {
  padding: 11px 12px 11px 0;
  border-bottom: 1px solid var(--border);
  color: var(--ink);
  font-weight: 600;
}
.bk-table tr:last-child td {
  border-bottom: 0;
}

/* Phones: the 420px floor above is wider than the screen, and a grid/flex
   ancestor grows to its content's minimum rather than letting the wrapper
   scroll — so the whole PAGE slid sideways. Restacked, the table has no
   floor at all: one block per line item, each figure labelled from its
   column heading. */
@media (max-width: 560px) {
  .bk-table-wrap {
    overflow-x: visible;
    background: none;
  }
  .bk-table {
    min-width: 0;
    display: block;
  }
  .bk-table thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
  }
  .bk-table tbody,
  .bk-table tr,
  .bk-table td {
    display: block;
    width: auto;
  }
  .bk-table tr {
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 10px 12px;
    margin-bottom: 10px;
    background: #fff;
  }
  .bk-table tr:last-child {
    margin-bottom: 0;
  }
  .bk-table td {
    border: 0;
    padding: 3px 0;
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 14px;
    font-size: 13.5px;
  }
  /* The ticket name is the row's title, not another label/value pair. */
  .bk-table td:first-child {
    display: block;
    font-size: 14.5px;
    font-weight: 700;
    padding-bottom: 7px;
    margin-bottom: 5px;
    border-bottom: 1px solid var(--border);
  }
  .bk-table td:first-child::before {
    display: none;
  }
  .bk-table td::before {
    content: attr(data-label);
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--gray);
  }
}

/* Issued ticket codes */
.bk-codes {
  list-style: none;
  margin: 14px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.bk-codes li {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--tint-bg);
  font-size: 13.5px;
}
.bk-code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-weight: 700;
  color: var(--ink);
}

/* Generic not-found + "Find my tickets" */
.bk-empty {
  max-width: 520px;
  margin: 48px auto 64px;
  text-align: center;
}
.bk-empty-glyph {
  width: 60px;
  height: 60px;
  border-radius: 16px;
  margin: 0 auto 18px;
  background: var(--tint);
  color: var(--violet);
  display: flex;
  align-items: center;
  justify-content: center;
}
.bk-empty h1 {
  font-size: 26px;
  font-weight: 800;
  letter-spacing: -0.02em;
  margin: 0 0 10px;
}
.bk-empty p {
  color: var(--gray);
  font-size: 15px;
  line-height: 1.65;
  margin: 0 0 20px;
}

.bk-find {
  max-width: 520px;
  margin: 40px auto 72px;
}
.bk-find-intro {
  text-align: center;
  margin-bottom: 26px;
}
.bk-find-intro h1 {
  font-size: 30px;
  font-weight: 800;
  letter-spacing: -0.02em;
  margin: 12px 0 10px;
}
.bk-find-intro p {
  color: var(--gray);
  font-size: 15px;
  line-height: 1.65;
  margin: 0;
}
.bk-find-form {
  border: 1px solid var(--border);
  border-radius: 14px;
  background: #fff;
  padding: 22px;
}
.bk-find-form .btn {
  width: 100%;
}
.bk-find-alt {
  margin-top: 18px;
  text-align: center;
  font-size: 13.5px;
  color: var(--gray);
}
.bk-find-alt a {
  color: var(--violet);
  font-weight: 650;
}

/* Neutral confirmation — identical for known and unknown addresses. */
.bk-neutral-ok {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  padding: 18px 20px;
  border: 1px solid #a7f3d0;
  border-radius: 14px;
  background: #ecfdf5;
}
.bk-neutral-ok-icon {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 10px;
  background: #d1fae5;
  color: #047857;
}
.bk-neutral-ok strong {
  display: block;
  font-size: 15px;
  color: #065f46;
  margin-bottom: 4px;
}
.bk-neutral-ok p {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.6;
  color: #047857;
}

@media (max-width: 900px) {
  .bk-head h1 {
    font-size: 27px;
  }
  .bk-head-actions {
    width: 100%;
  }
}

/* ============================================================
   Page header  (.pg-head)
   The tinted band with an H1 + optional lead and an action on the
   right. index/events/venues/pricing/my-bookings/my-profile/
   saved-events each repeated this as inline styles, which meant the
   H1 was stuck at 48-52px on a phone — an inline style cannot be
   overridden by a media query. One class, one responsive scale.
   ============================================================ */
/* The brand ring as a quiet backdrop. Decorative: it sits behind everything at
   low opacity, and every band that carries one is position:relative and clips
   its overflow. `currentColor` means each band picks the tone up from its own
   text colour — violet on a light band, white on the dark hero. */
.brand-dial {
  position: absolute;
  right: -90px;
  top: 50%;
  transform: translateY(-50%);
  width: 420px;
  height: 420px;
  color: var(--violet);
  opacity: 0.09;
  pointer-events: none;
  z-index: 0;
}
.brand-dial.is-left {
  right: auto;
  left: -120px;
}
.brand-dial.is-sm {
  width: 300px;
  height: 300px;
  right: -70px;
}
/* A phone has no room to spare beside the heading. */
@media (max-width: 700px) {
  .brand-dial { width: 260px; height: 260px; right: -110px; opacity: 0.07; }
  .brand-dial.is-left { right: auto; left: -110px; }
}

.pg-head {
  position: relative;
  overflow: hidden;
  background: var(--tint-bg);
  border-bottom: 1px solid #f0edf7;
}
.pg-head > .container {
  position: relative;
  z-index: 1;
}
.pg-head-inner {
  padding-block: clamp(26px, 4vw, 52px) clamp(18px, 2.6vw, 34px);
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 18px;
  flex-wrap: wrap;
}
.pg-head h1 {
  font-family: "Bricolage Grotesque", sans-serif;
  font-size: clamp(26px, 4.6vw, 44px);
  line-height: 1.1;
  letter-spacing: -0.03em;
  font-weight: 800;
  margin: 0;
  text-wrap: balance;
}
.pg-head .pg-lead {
  margin: 6px 0 0;
  color: var(--gray);
  /* The page-lede tier — see .ev-hero p. */
  font-size: clamp(15px, 1.8vw, 17px);
  line-height: 1.55;
  max-width: 60ch;
}
.pg-head-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
/* Centred variant (pricing, marketing pages). */
.pg-head.is-center .pg-head-inner {
  flex-direction: column;
  align-items: center;
  text-align: center;
}
.pg-head.is-center .pg-lead {
  margin-inline: auto;
}
/* A header whose body is a search form or filter row, not an action. */
.pg-head.is-stack .pg-head-inner {
  flex-direction: column;
  align-items: stretch;
}

@media (max-width: 600px) {
  /* The action drops below the heading and spans the width, so it is a
     comfortable tap target rather than a small button squeezed to the right. */
  .pg-head-actions {
    width: 100%;
  }
  .pg-head-actions .btn {
    flex: 1 1 auto;
    text-align: center;
  }
}

/* ---- Ticket cards on the booking page ----
   The ticket lives on the page itself: the same .tk artifact serves the screen,
   the print dialog (see @media print below) and, redrawn with GD, the JPG
   download. There is no separate print route. */
/* In the aside now, so the card fits the narrower column and the gap between
   several tickets tightens. */
/* Sub-headings inside the merged Booking panel — the four fact groups that
   used to be four separate panels. */
.bk-invoice-row {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 14px;
}
.bk-sub {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--gray);
  margin: 20px 0 8px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}
.ed-panel > .bk-sub:first-of-type {
  margin-top: 16px;
}

.bk-tickets {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.bk-side .tk {
  max-width: 100%;
}
/* Phones: the whole page is one column — trim the ticket panel padding and
   the tool buttons so the ticket itself gets the width. */
@media (max-width: 560px) {
  .bk-tickets {
    gap: 12px;
  }
  /* The tear-line notches hang 10px past each edge of the card. At full
     width on a phone that overhang lands off-screen and widens the page,
     so the ticket keeps a gutter to sit in. Desktop is untouched — there
     the 360px aside already leaves the notches room. */
  .bk-ticket-item {
    padding-inline: 12px;
  }
  .bk-ticket-tools {
    gap: 6px;
  }
  .bk-ticket-tools .btn {
    padding: 7px 11px;
    font-size: 12.5px;
  }
  .bk-ticket-note {
    font-size: 12px;
    margin-top: 12px;
  }
}
.bk-ticket-item {
  break-inside: avoid;
  page-break-inside: avoid;
}
.bk-ticket-item .tk {
  margin: 0 auto;
}
.bk-ticket-tools {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 10px;
}
.bk-ticket-tools .btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.bk-ticket-note {
  margin: 16px 0 0;
  font-size: 12.5px;
  color: var(--gray);
  line-height: 1.55;
}
.bk-ticket-note strong {
  color: var(--ink);
  font-weight: 700;
}

/* Long values (email addresses, ticket codes) must wrap inside their fact cell
   instead of running into the next column. */
.bk-page .ed-fact dd {
  overflow-wrap: anywhere;
  word-break: break-word;
}

/* ============================================================================
   TICKETS  (.tk-*)
   The event ticket artifact: a violet gradient body, a perforated white QR
   stub, and the notch circles that make the tear line read as a tear line.
   Deliberately always violet-on-white — it is a document, not a themed
   surface — so it carries its own colors and ignores dark mode.
   Two orientations share the block: .tk-landscape (body + right stub) and
   .tk-portrait (violet header + white QR face).
   ========================================================================= */
.tk {
  --tk-grad: linear-gradient(
    135deg,
    #3f1878 0%,
    #5c24ae 42%,
    #6d28d9 74%,
    var(--violet) 100%
  );
  --tk-notch: #eeecef; /* the page showing through the tear */
  font-family: "Familjen Grotesk", sans-serif;
  color: #fff;
  background: #fff;
  border-radius: 20px;
  box-shadow: 0 18px 44px rgba(76, 29, 149, 0.14);
  break-inside: avoid;
  page-break-inside: avoid;
  -webkit-print-color-adjust: exact;
  print-color-adjust: exact;
}

/* -- shared pieces --------------------------------------------------------- */
.tk-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px;
}
.tk-org {
  display: flex;
  align-items: center;
  gap: 11px;
  min-width: 0;
}
.tk-avatar {
  flex: none;
  width: 34px;
  height: 34px;
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.17);
  border: 1px solid rgba(255, 255, 255, 0.22);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  font-family: "Bricolage Grotesque", sans-serif;
  font-weight: 800;
  font-size: 12.5px;
  letter-spacing: -0.01em;
  color: #fff;
}
.tk-avatar.has-logo {
  background: #fff;
  border-color: rgba(255, 255, 255, 0.4);
  padding: 4px;
}
.tk-avatar img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}
.tk-org-name {
  font-size: 15px;
  font-weight: 700;
  color: #fff;
  letter-spacing: -0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tk-tier {
  flex: none;
  border: 1.5px solid rgba(255, 255, 255, 0.45);
  border-radius: 100px;
  padding: 8px 18px;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: #fff;
  white-space: nowrap;
}
.tk-tier-plain {
  flex: none;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.82);
  white-space: nowrap;
  align-self: center;
  padding-top: 1px;
}
.tk .tk-title {
  font-family: "Bricolage Grotesque", sans-serif;
  font-weight: 800;
  letter-spacing: -0.035em;
  color: #fff;
  margin: 0;
  text-transform: none;
}
.tk-label {
  display: block;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.6);
  margin-bottom: 5px;
}
.tk-value {
  display: block;
  font-size: 15.5px;
  font-weight: 700;
  color: #fff;
  letter-spacing: -0.01em;
  line-height: 1.25;
}
.tk-powered {
  font-size: 11.5px;
  color: rgba(255, 255, 255, 0.42);
  letter-spacing: 0.01em;
}
/* The eventio360 wordmark replaces the "Powered by" text. Held to a small,
   fixed height so it reads as a mark rather than competing with the event
   title, and toned back so it sits behind the ticket's own content. */
.tk-powered img {
  display: block;
  height: 13px;
  width: auto;
}
/* On the violet body the white mark needs most of its opacity to read at all —
   .5 left it almost invisible against the lighter end of the gradient. */
.tk-landscape .tk-powered img {
  height: 13px;
  opacity: 0.85;
}
.tk-portrait .tk-powered img {
  height: 15px;
  margin: 0 auto;
  opacity: 0.75;
}
/* The soft off-centre ring behind the right of the violet area. */
.tk-watermark {
  position: absolute;
  border-radius: 50%;
  pointer-events: none;
  border: 36px solid rgba(255, 255, 255, 0.075);
}
.tk-qr {
  display: block;
  background: #fff;
  image-rendering: crisp-edges;
}
.tk-qr.is-missing {
  background: repeating-linear-gradient(45deg, #f1edfb 0 6px, #fff 6px 12px);
  border-radius: 6px;
}
/* The tear-line circles: page-coloured discs straddling the perforation. */
.tk-notch {
  position: absolute;
  background: var(--tk-notch);
  border-radius: 50%;
  pointer-events: none;
  z-index: 2;
}

/* -- landscape ------------------------------------------------------------- */
.tk-landscape {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 30.5%;
  align-items: stretch;
  overflow: visible;
  position: relative;
  width: 100%;
  max-width: 880px;
  container-type: inline-size;
}
.tk-landscape .tk-body {
  position: relative;
  overflow: hidden;
  background: var(--tk-grad);
  border-radius: 20px 0 0 20px;
  padding: 26px 30px 24px;
  /* Reference proportion: the card is 2.66:1, so its body is 37.6% of the
     card width tall. A floor, not a cage — a long title grows past it. */
  min-height: 37.6cqw;
  display: flex;
  flex-direction: column;
}
.tk-landscape .tk-watermark {
  width: 66%;
  aspect-ratio: 1;
  right: -13%;
  top: 50%;
  transform: translateY(-50%);
}
.tk-landscape .tk-title {
  font-size: clamp(20px, 3.05cqw, 40px);
  line-height: 1.07;
  margin: 20px 0 0;
  max-width: 14ch;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.tk-landscape .tk-meta {
  display: flex;
  flex-wrap: nowrap;
  gap: 10px 34px;
  padding-top: 24px;
  position: relative;
}
/* The first meta row carries the gap, so DATE/DOORS/VENUE and ATTENDEE/ORDER
   stay a single block pinned to the bottom of the card. */
.tk-landscape .tk-meta:not(.tk-meta-last) {
  margin-top: auto;
}
.tk-landscape .tk-meta-last {
  padding-top: 20px;
  align-items: flex-end;
}
.tk-landscape .tk-field {
  min-width: 0;
}
.tk-landscape .tk-field-wide {
  flex: 1 1 auto;
  min-width: 0;
}
.tk-landscape .tk-field-wide .tk-value {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tk-landscape .tk-powered {
  margin-left: auto;
  padding-bottom: 2px;
}
/* The stub: a white card whose left edge is the perforation. */
.tk-landscape .tk-stub {
  position: relative;
  background: #fff;
  border-radius: 0 20px 20px 0;
  border-left: 2px dashed #ccc;
  padding: 26px 20px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0;
}
.tk-landscape .tk-notch {
  width: 26px;
  height: 26px;
  left: -15px;
}
.tk-landscape .tk-notch-top {
  top: -13px;
}
.tk-landscape .tk-notch-bottom {
  bottom: -13px;
}
.tk-landscape .tk-qr {
  width: calc(52% + 21px);
  max-width: 170px;
  height: auto;
  aspect-ratio: 1;
}
.tk-landscape .tk-scan {
  margin-top: 16px;
  font-size: 12.5px;
  color: var(--gray);
}
.tk-landscape .tk-code {
  margin-top: 3px;
  font-size: 14.5px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.01em;
  text-align: center;
  overflow-wrap: anywhere;
}

/* -- portrait -------------------------------------------------------------- */
/* Portrait is the ticket the ATTENDEE sees: on screen, in the print dialog and
   as the saved JPG. Type is deliberately compact and NOTHING is clamped — a
   long conference title or a full street address must fit rather than clip,
   because the card grows to hold it. */
.tk-portrait {
  position: relative;
  overflow: visible;
  max-width: 392px;
  display: flex;
  flex-direction: column;
}
.tk-portrait .tk-head {
  position: relative;
  overflow: hidden;
  background: var(--tk-grad);
  border-radius: 18px 18px 0 0;
  padding: 18px 22px 20px;
}
.tk-portrait .tk-watermark {
  width: 88%;
  aspect-ratio: 1;
  right: -30%;
  top: -40%;
  border-width: 30px;
}
/* No line-clamp: the title wraps to as many lines as it needs. balance keeps
   the wrap from leaving one orphaned word. */
/* A long ticket-type ("Accompanying Delegate (Non-Residential)") must wrap
   rather than run under the logo: flex:none + nowrap made it unshrinkable, so
   it overlapped the avatar. It keeps the right-hand side and wraps there. */
.tk-portrait .tk-tier-plain {
  flex: 0 1 auto;
  min-width: 0;
  white-space: normal;
  text-align: right;
  line-height: 1.3;
  font-size: 10px;
  letter-spacing: 0.08em;
  align-self: flex-start;
  padding-top: 3px;
  overflow-wrap: break-word;
}
.tk-portrait .tk-title {
  font-size: clamp(17px, 4.3vw, 22px);
  line-height: 1.2;
  margin: 12px 0 0;
  letter-spacing: -0.025em;
  text-wrap: balance;
  overflow-wrap: break-word;
}
.tk-portrait .tk-face {
  background: #fff;
  border-radius: 0 0 18px 18px;
  padding: 16px 22px 12px;
  display: flex;
  flex-direction: column;
  flex: 1;
}
.tk-portrait .tk-row {
  display: flex;
  align-items: flex-start;
  gap: 26px;
  padding-bottom: 14px;
}
.tk-portrait .tk-field-end {
  text-align: right;
}
/* Full-width labelled rows for the long values (venue, organizer). */
.tk-portrait .tk-field-block {
  padding-bottom: 12px;
}
.tk-portrait .tk-label {
  color: var(--gray);
  font-size: 9px;
  letter-spacing: 0.13em;
  margin-bottom: 3px;
}
.tk-portrait .tk-value {
  color: var(--ink);
  font-size: 13.5px;
  line-height: 1.4;
  overflow-wrap: break-word;
  white-space: normal;
}
.tk-portrait .tk-row .tk-value {
  font-size: 14.5px;
}
/* The horizontal tear line, with a notch biting in from each edge. */
.tk-portrait .tk-perf {
  position: relative;
  height: 0;
  border-top: 1.5px dashed #d6d2e2;
  margin: 2px -22px 0;
}
.tk-portrait .tk-notch {
  width: 20px;
  height: 20px;
  top: -10px;
}
.tk-portrait .tk-notch-left {
  left: -10px;
}
.tk-portrait .tk-notch-right {
  right: -10px;
}
.tk-portrait .tk-qr-wrap {
  padding: 18px 0 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  flex: 1;
  justify-content: center;
}
.tk-portrait .tk-qr {
  width: calc(42% + 20px);
  max-width: 168px;
  height: auto;
  aspect-ratio: 1;
}
.tk-portrait .tk-scan {
  margin-top: 10px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--gray);
}
.tk-portrait .tk-code {
  margin-top: 2px;
  font-size: 14px;
  font-weight: 800;
  color: var(--ink);
  letter-spacing: -0.01em;
  overflow-wrap: anywhere;
  text-align: center;
}
.tk-portrait .tk-under {
  margin-top: 8px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink);
  text-align: center;
  overflow-wrap: break-word;
}
.tk-portrait .tk-powered {
  margin-top: 14px;
  text-align: center;
  color: #b4b0c0;
  font-size: 11px;
}

/* -- phones: the stub tears off downwards instead of sideways -------------- */
@media (max-width: 560px) {
  .tk-landscape {
    grid-template-columns: 1fr;
    max-width: none;
  }
  .tk-landscape .tk-body {
    border-radius: 20px 20px 0 0;
    padding: 24px 22px 20px;
    min-height: 0;
  }
  .tk-landscape .tk-title {
    font-size: 30px;
    margin-top: 20px;
    max-width: none;
  }
  .tk-landscape .tk-meta {
    flex-wrap: wrap;
    gap: 14px 26px;
    padding-top: 22px;
  }
  .tk-landscape .tk-meta .tk-field {
    flex: 0 0 auto;
  }
  .tk-landscape .tk-value {
    white-space: nowrap;
  }
  .tk-landscape .tk-field-wide {
    flex: 1 1 100%;
  }
  .tk-landscape .tk-field-wide .tk-value {
    white-space: normal;
  }
  /* Full org name fits once the tier pill is on its own line. */
  .tk-landscape .tk-top {
    flex-wrap: wrap;
    gap: 12px;
  }
  .tk-landscape .tk-org {
    flex: 1 1 100%;
  }
  .tk-landscape .tk-org-name {
    white-space: normal;
    overflow: visible;
  }
  .tk-landscape .tk-field-wide {
    max-width: none;
  }
  .tk-landscape .tk-powered {
    margin-left: 0;
    width: 100%;
    padding-top: 6px;
  }
  .tk-landscape .tk-stub {
    border-radius: 0 0 20px 20px;
    border-left: 0;
    border-top: 2px dashed #ccc;
    padding: 26px 20px 24px;
  }
  .tk-landscape .tk-notch {
    left: auto;
    top: auto;
  }
  .tk-landscape .tk-notch-top {
    left: -13px;
    top: -13px;
  }
  .tk-landscape .tk-notch-bottom {
    right: -13px;
    top: -13px;
  }
  .tk-landscape .tk-qr {
    width: min(52%, 180px);
  }
  .tk-portrait {
    max-width: none;
  }
}

/* -- print: paper, not a web page ----------------------------------------- */
@media print {
  /* Colour is the whole point of this artifact — keep the gradient. */
  .tk,
  .tk * {
    -webkit-print-color-adjust: exact !important;
    print-color-adjust: exact !important;
  }
  /* On white paper the notch has to be drawn, not punched. */
  .tk {
    box-shadow: none;
    --tk-notch: #fff;
    break-inside: avoid;
    page-break-inside: avoid;
  }
  .tk-notch {
    border: 1px solid #c9c4d8;
  }
  /* A4 portrait content width is ~180mm; the landscape ticket fits it whole. */
  .tk-landscape {
    width: 100%;
    max-width: 180mm;
  }
  /* The white stub needs an edge, or it vanishes into the page. */
  .tk-landscape .tk-stub {
    border: 1px solid #c9c4d8;
    border-left: 2px dashed #a9a2be;
  }
  .tk-portrait {
    max-width: 110mm;
  }
  .tk-portrait .tk-face {
    border: 1px solid #c9c4d8;
    border-top: 0;
  }
}

/* -- the ticket design preview page (reference/ticket-preview.php) --------- */
.tk-preview-page {
  background: var(--tk-page, #eeecef);
}
.tk-preview {
  max-width: 1180px;
  margin: 0 auto;
  padding: 48px 24px 72px;
}
.tk-preview-head {
  margin-bottom: 44px;
}
.tk-preview-head h1 {
  font-size: 40px;
  font-weight: 800;
  margin: 0 0 12px;
}
.tk-preview-lede {
  font-size: 15.5px;
  line-height: 1.65;
  color: var(--gray);
  margin: 0;
  max-width: 70ch;
}
.tk-preview-block {
  margin-bottom: 52px;
}
.tk-preview-block > h2 {
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--violet);
  margin: 0 0 6px;
  font-family: "Familjen Grotesk", sans-serif;
}
.tk-preview-block > p {
  font-size: 14.5px;
  color: var(--gray);
  margin: 0 0 22px;
}
.tk-preview-note {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 24px 26px;
}
.tk-preview-note p {
  font-size: 14.5px;
  line-height: 1.7;
  color: var(--gray);
  margin: 0 0 14px;
}
.tk-preview-note p:last-child {
  margin-bottom: 0;
}
.tk-preview-note strong {
  color: var(--ink);
}
.tk-preview-foot {
  font-size: 13px;
  color: var(--gray);
  border-top: 1px solid #e2deec;
  padding-top: 20px;
  line-height: 1.8;
}
.tk-preview code {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 1px 6px;
  font-size: 0.9em;
  color: var(--violet);
}

/* Printing the booking page: the ticket cards go to paper, everything else is
   page furniture and is dropped. This replaces the old ?print=1 route — the
   attendee prints (or "Save as PDF"s) the page they are already looking at.
   Printing a single card marks the others .bk-print-skip; see booking-lookup.php. */
/* :has() scopes these to the booking page only, so printing any other public
   page is untouched. The nav, footer and crumb are OUTSIDE .bk-page, so they
   cannot be selected as its descendants. */
@media print {
  body:has(.bk-panel-tickets) .nav,
  body:has(.bk-panel-tickets) .footer,
  body:has(.bk-panel-tickets) .ed-crumb,
  /* The .bk-head block repeats the event title and reference that the ticket
     itself already carries, so it is page furniture too. */
  .bk-page .bk-head,
  .bk-page .bk-head-actions,.bk-page .bk-ticket-tools,
  .bk-page .bk-status-row,.bk-page .bk-claim,
  .bk-page .ed-panel:not(.bk-panel-tickets),
  .bk-ticket-item.bk-print-skip {
    display: none !important;
  }

  /* Only the ticket panel survives, and it prints as bare cards on white. */
  .bk-page,
  .bk-page .ed-panel {
    background: #fff !important;
    border: 0 !important;
    box-shadow: none !important;
    padding: 0 !important;
    margin: 0 !important;
  }
  .bk-page .ed-panel-head {
    display: none !important;
  }
  .bk-page {
    max-width: none !important;
  }
  .bk-tickets {
    gap: 0;
  }
  /* PORTRAIT on paper too — the same shape the attendee sees on screen and in
     their emailed ticket. Sized in mm against the sheet rather than inheriting
     whatever the print viewport happened to be (which landed the card small in
     the top-left corner), and centred. */
  .bk-ticket-item {
    width: 100%;
  }
  .bk-ticket-item .tk {
    margin: 0 auto 8mm;
    box-shadow: none;
  }
  .bk-ticket-item .tk-portrait {
    width: 92mm;
    max-width: 92mm;
  }
  .bk-ticket-note {
    display: none !important;
  }

  /* Nothing is clipped on paper: there is no hover or tap to reveal the rest,
     and the address is the whole point of printing a ticket. The card grows to
     fit instead. */
  .tk-portrait .tk-value,
  .tk-landscape .tk-field-wide .tk-value,
  .tk-org-name {
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
  }
  .tk .tk-title {
    -webkit-line-clamp: unset;
    line-clamp: unset;
    display: block;
    overflow: visible;
  }
  /* Point sizes, so the printed card is legible regardless of the browser's
     print scaling. Kept compact so a long title still fits one sheet. */
  .tk-portrait .tk-title {
    font-size: 13pt;
    line-height: 1.2;
  }
  .tk-portrait .tk-value {
    font-size: 8.5pt;
  }
  .tk-portrait .tk-row .tk-value {
    font-size: 9pt;
  }
  .tk-portrait .tk-label {
    font-size: 6pt;
  }
  .tk-portrait .tk-code {
    font-size: 9pt;
  }
  .tk-portrait .tk-under {
    font-size: 8pt;
  }
  .tk-portrait .tk-qr {
    max-width: 42mm;
  }
}

/* ============================================================
   Abstract submission  (includes/public/abstract-cta.php)
   The form lives in a modal on the event page and reuses the
   .ed-modal / .ed-dyn-* components; only the pieces with no
   existing equivalent are defined here.
   ============================================================ */

/* Long-form body copy inside a panel (submission guidelines). */
.ed-prose {
  font-size: 14px;
  line-height: 1.75;
  color: var(--ink);
  max-width: 66ch;
}

/* Submit row: status message on the left, actions on the right. */
.ed-form-foot {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 20px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}
.ed-form-msg {
  font-size: 13px;
  color: var(--gray);
  margin-right: auto;
}
.ed-form-msg.is-error {
  color: #b21f1f;
  font-weight: 600;
}
.ed-form-msg.is-ok {
  color: #0b5d1e;
  font-weight: 600;
}

/* ============================================================
   Claim your booking  (booking-lookup.php)
   Turning a guest magic link into an account: choose a password
   and the booking's email becomes the login.
   ============================================================ */
.bk-claim {
  border-color: var(--violet-pale);
}
.bk-claim-lede {
  font-size: 14px;
  line-height: 1.7;
  margin: 0 0 16px;
  max-width: 60ch;
}
.bk-claim-lede strong {
  color: var(--ink);
}

/* Two fields side by side, stacking on narrow screens. */
.bk-claim-fields {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}
.bk-claim-field {
  min-width: 0;
}
.bk-claim-field label {
  display: block;
  font-size: 12px;
  font-weight: 700;
  color: var(--ink);
  margin-bottom: 6px;
}
@media (max-width: 560px) {
  .bk-claim-fields {
    grid-template-columns: 1fr;
  }
}

/* ── Booking modal: stepped flow ─────────────────────────────────────────────
   The booking form used to be one long scroll (registration fields, companion
   toggle, payment method, receipt upload). Split into three panes so a visitor
   sees one decision at a time; .ed-pane[hidden] does the switching. */
.ed-steps {
  display: flex;
  align-items: center;
  gap: 6px;
  list-style: none;
  margin: 0 0 18px;
  padding: 0;
  counter-reset: none;
  overflow-x: auto;
  scrollbar-width: none;
}
.ed-steps::-webkit-scrollbar {
  display: none;
}
.ed-step {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1 1 0;
  min-width: 0;
  color: var(--text-faint);
  font-size: 13px;
}
.ed-step:not(:last-child)::after {
  content: "";
  flex: 1;
  height: 2px;
  background: var(--border);
  border-radius: 2px;
  margin-left: 4px;
}
.ed-step-n {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  flex: none;
  border-radius: 50%;
  background: var(--tint);
  color: var(--text-faint);
  border: 1px solid var(--border);
  font-weight: 700;
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
}
.ed-step-t {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ed-step.is-current {
  color: var(--ink);
}
.ed-step.is-current .ed-step-n {
  background: var(--violet);
  border-color: var(--violet);
  color: #fff;
}
.ed-step.is-done .ed-step-n {
  background: var(--ok-bg);
  border-color: var(--ok-fg);
  color: var(--ok-fg);
}
.ed-step.is-done:not(:last-child)::after {
  background: var(--ok-fg);
}
/* On a narrow screen only the active step needs its label. */
@media (max-width: 560px) {
  .ed-step .ed-step-t {
    display: none;
  }
  .ed-step.is-current .ed-step-t {
    display: block;
  }
}

.ed-pane-nav {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}
.ed-pane-nav .ed-back {
  margin-right: auto;
}
@media (max-width: 480px) {
  .ed-pane-nav {
    flex-direction: column-reverse;
  }
  .ed-pane-nav .btn {
    width: 100%;
  }
  .ed-pane-nav .ed-back {
    margin-right: 0;
  }
}

/* Ticket tier picker — replaces one "Book now" button per tier. Radio cards so
   the price comparison stays visible while choosing. */
.ed-tier-options {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.ed-tier-option {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 14px;
  cursor: pointer;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--surface);
  transition:
    border-color 0.15s,
    background 0.15s;
}
.ed-tier-option:hover {
  border-color: var(--violet-pale);
  background: var(--tint);
}
.ed-tier-option:has(input:checked) {
  border-color: var(--violet);
  background: var(--tint);
}
.ed-tier-option input {
  accent-color: var(--violet);
  width: 17px;
  height: 17px;
  flex: none;
  margin: 0;
}
.ed-tier-body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  flex: 1;
}
.ed-tier-name {
  font-size: 14px;
  font-weight: 650;
  color: var(--ink);
}
.ed-tier-price {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 1px;
  flex: none;
  text-align: right;
}
.ed-tier-price strong {
  font-size: 15px;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.ed-tier-price s {
  font-size: 12px;
}
.ed-tier-price small {
  font-size: 11px;
  letter-spacing: 0.03em;
}
/* Single primary CTA under a multi-tier ticket list. */
.ed-tickets-cta {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  margin-top: 18px;
  padding-top: 18px;
  border-top: 1px solid var(--border);
  text-align: center;
}
.ed-tickets-cta .btn-lg {
  min-width: min(280px, 100%);
  padding: 13px 28px;
  font-size: 15px;
}

/* Ticket summary card for a multi-tier event (replaces the per-tier list).
   Leads with the price RANGE rather than a lone "From" figure, then the facts a
   delegate needs before opening the form. Lives in the narrow sidebar panel, so
   everything has to survive ~300px. */
.ed-tk {
  border: 1px solid var(--border);
  border-radius: 14px;
  overflow: hidden;
  margin-bottom: 16px;
  background: var(--surface);
}
.ed-tk-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
  padding: 15px 16px;
  background: linear-gradient(
    135deg,
    var(--violet) 0%,
    var(--violet-light, #8b5cf6) 100%
  );
  color: #fff;
}
.ed-tk-label {
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  opacity: 0.82;
  margin-bottom: 5px;
}
.ed-tk-range {
  display: flex;
  align-items: baseline;
  gap: 5px;
  flex-wrap: wrap;
}
.ed-tk-amt {
  font-size: 21px;
  font-weight: 750;
  line-height: 1.05;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}
.ed-tk-dash {
  font-size: 16px;
  opacity: 0.65;
  font-weight: 400;
}
.ed-tk-ccy {
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.05em;
  opacity: 0.85;
  margin-left: 1px;
}
.ed-tk-count {
  flex: none;
  font-size: 11.5px;
  font-weight: 650;
  padding: 4px 9px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.2);
  white-space: nowrap;
}
.ed-tk-facts {
  list-style: none;
  margin: 0;
  padding: 12px 16px;
  display: flex;
  flex-direction: column;
  gap: 9px;
}
.ed-tk-facts li {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  font-size: 13px;
  color: var(--gray);
  line-height: 1.4;
}
.ed-tk-facts svg {
  flex: none;
  margin-top: 1px;
  color: var(--violet);
  opacity: 0.85;
}
@media (max-width: 400px) {
  .ed-tk-amt {
    font-size: 19px;
  }
  .ed-tk-top {
    padding: 13px 14px;
  }
}

/* "Your ticket isn't ready yet" — shown in place of the ticket while a booking
   is unpaid. A ticket is proof of admission, so it is withheld until payment is
   confirmed; this explains what is outstanding rather than showing nothing. */
.bk-await {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  padding: 4px 0;
}
/* Pay now and "Already paid? Check again" sit together: someone whose gateway
   tab closed does not know which of the two they need. */
.bk-await-actions {
  display: flex;
  gap: 9px;
  flex-wrap: wrap;
  align-items: center;
}
/* The verify result, in the house dialog rather than a browser alert. */
.bk-verify-modal .ed-modal-dialog {
  max-width: 460px;
}
.bk-verify-modal .ed-modal-foot {
  gap: 8px;
}
.bk-verify-text {
  margin: 0;
  font-size: 14px;
  line-height: 1.65;
  color: var(--gray);
}
.bk-verify-text.is-ok {
  color: #166534;
  font-weight: 600;
}
.bk-verify-text.is-bad {
  color: #b91c1c;
}
/* "The gateway would not answer" is neither good news nor bad — amber,
   because the one thing it must not read as is "your payment failed". */
.bk-verify-text.is-wait {
  color: #92400e;
}
@media (max-width: 560px) {
  .bk-await-actions {
    width: 100%;
  }
  .bk-await-actions .btn {
    flex: 1 1 100%;
    justify-content: center;
  }
}
.bk-await-title {
  font-size: 15px;
  font-weight: 650;
  color: var(--ink);
}
.bk-await-text {
  margin: 0;
  font-size: 14px;
  line-height: 1.55;
  color: var(--gray);
  max-width: 56ch;
}

/* Payment outcome banner on the booking page (?pay=ok|failed&msg=…). Both
   fonepay-return.php and pay-booking.php send the attendee back here with a
   message; nothing used to render it. */
/* Abstract invite on the booking page. Sits between the payment banner and
   the header, so it reads as a next step rather than page furniture. */
.bk-abs {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  padding: 14px 16px;
  margin-bottom: 18px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--tint);
}
.bk-abs-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.bk-abs-text strong {
  font-size: 14.5px;
  color: var(--ink);
}
.bk-abs-text span {
  font-size: 13px;
  color: var(--gray);
}
@media (max-width: 520px) {
  .bk-abs {
    align-items: stretch;
  }
  .bk-abs .btn {
    width: 100%;
    justify-content: center;
  }
}
/* ── The KYC gate ────────────────────────────────────────────────────────────
   Two numbered steps in a normal panel, under the booking header: step 1 sets
   a password (so the details belong to an account the attendee owns), step 2
   collects what a badge and a certificate print. Amber accent while something
   is outstanding — the ticket is held on it — green once it is done. */
.bk-kyc {
  border-left: 4px solid transparent;
  margin-bottom: 18px;
}
.bk-kyc.is-due {
  border-left-color: #b25e09;
  background: #fffdf7;
}
.bk-kyc.is-done {
  border-left-color: #059669;
}
.bk-kyc .ed-h {
  flex-wrap: wrap;
}
.bk-kyc-pill {
  margin-left: auto;
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 4px 10px;
  border-radius: 999px;
  background: #fef3c7;
  color: #92400e;
}
.bk-kyc.is-done .bk-kyc-pill {
  background: #dcfce7;
  color: #166534;
}
.bk-kyc-lede {
  font-size: 14px;
  line-height: 1.7;
  margin: 0;
  max-width: 70ch;
}
.bk-kyc-alert {
  display: flex;
  gap: 8px;
  align-items: center;
  font-size: 13px;
  font-weight: 600;
  color: #92400e;
  background: #fef3c7;
  border-radius: 9px;
  padding: 9px 12px;
  margin: 0 0 12px;
}
.bk-kyc-alert svg {
  flex: none;
}
.bk-kyc-alert.is-ok {
  background: #dcfce7;
  color: #166534;
}

/* The steps. The number column doubles as the rail joining them, so the two
   read as one sequence rather than two unrelated forms. */
.bk-kyc-steps {
  list-style: none;
  margin: 18px 0 0;
  padding: 0;
}
.bk-kyc-step {
  display: flex;
  gap: 14px;
  padding: 0 0 22px;
  position: relative;
  align-items: flex-start;
}
.bk-kyc-step:last-child {
  padding-bottom: 0;
}
.bk-kyc-step:not(:last-child)::before {
  content: "";
  position: absolute;
  left: 14px;
  top: 34px;
  bottom: 6px;
  width: 2px;
  background: var(--border);
}
.bk-kyc-step.is-done:not(:last-child)::before {
  background: #a7f3d0;
}
.bk-kyc-num {
  flex: none;
  width: 29px;
  height: 29px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 800;
  background: var(--tint);
  color: var(--violet);
  border: 1px solid var(--violet-pale);
  position: relative;
  z-index: 1;
  box-sizing: border-box;
}
.bk-kyc-num svg {
  display: block;
}
.bk-kyc-step.is-done .bk-kyc-num {
  background: #dcfce7;
  color: #166534;
  border-color: #a7f3d0;
}
.bk-kyc-step.is-locked .bk-kyc-num {
  background: #f3f4f6;
  color: #9ca3af;
  border-color: var(--border);
}
.bk-kyc-body {
  flex: 1;
  min-width: 0;
}
.bk-kyc-body h3 {
  margin: 5px 0 5px;
  font-size: 14.5px;
  font-weight: 750;
  letter-spacing: -0.01em;
}
.bk-kyc-step.is-locked .bk-kyc-body h3 {
  color: var(--gray);
}
.bk-kyc-note {
  margin: 0;
  font-size: 13px;
  line-height: 1.6;
  color: var(--gray);
}
.bk-kyc-note strong {
  color: var(--ink);
}

/* Each step is one row: what it is on the left, the single thing to do on the
   right. The button is pinned to the row rather than dropped underneath so the
   whole card stays two lines tall on a desktop. */
.bk-kyc-go {
  flex: none;
  align-self: center;
  white-space: nowrap;
}

/* Used by the password modal — the only fields left on this page. */
.bk-kyc-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 13px;
}
.bk-kyc-f {
  min-width: 0;
}
.bk-kyc-f label {
  display: block;
  font-size: 12px;
  font-weight: 700;
  color: var(--ink);
  margin-bottom: 5px;
}
.bk-kyc-req {
  color: #dc2626;
}
/* The gate screen. While KYC is outstanding this REPLACES the booking, so it
   carries the page header itself and the panel is the only thing under it. */
.bk-gate-head {
  margin-bottom: 18px;
}
.bk-gate-form {
  margin-top: 12px;
  max-width: 520px;
}
.bk-kyc-modal {
  max-width: 520px;
}
.bk-kyc-modal .ed-modal-foot {
  align-items: center;
}
.bk-kyc-modal .ed-form-msg {
  margin-right: auto;
  font-size: 12.5px;
}

/* Phones. This block MUST stay below the rules above: a media query carries no
   extra specificity, so an override placed earlier in the file simply loses.
   These rules previously sat 400 lines up (inherited from the card this
   replaced) and none of them applied. */
@media (max-width: 560px) {
  /* One field per line: two password boxes side by side on a 390px screen
     leave neither wide enough to read its own placeholder, and squeeze the
     submit button onto three lines. */
  .bk-kyc-grid {
    grid-template-columns: 1fr;
  }
  .bk-kyc-foot {
    flex-wrap: wrap;
  }
  .bk-kyc-foot .btn {
    width: 100%;
    justify-content: center;
  }
  .bk-kyc-modal .ed-modal-foot {
    flex-wrap: wrap;
  }
  .bk-kyc-modal .ed-modal-foot .btn {
    width: 100%;
    justify-content: center;
  }
  .bk-kyc-lede {
    font-size: 13.5px;
  }
  .bk-kyc-pill {
    margin-left: 0;
  }
  /* Tighter rail so the text column keeps its width. */
  .bk-kyc-step {
    gap: 11px;
    padding-bottom: 18px;
    flex-wrap: wrap;
  }
  .bk-kyc-step:not(:last-child)::before {
    left: 12px;
    top: 30px;
  }
  .bk-kyc-num {
    width: 25px;
    height: 25px;
    font-size: 12px;
  }
  /* No room for text and a button side by side, so the button wraps under its
     own step — indented to line up with the text, and 36px narrower to match,
     because width:100% plus a 36px margin overflows the row. */
  .bk-kyc-go {
    width: calc(100% - 36px);
    justify-content: center;
    margin: 10px 0 0 36px;
  }
}

.bk-flash {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 12px 15px;
  margin-bottom: 18px;
  border: 1px solid var(--border);
  border-left-width: 4px;
  border-radius: 11px;
  font-size: 14px;
  line-height: 1.5;
  background: var(--surface);
}
.bk-flash svg {
  flex: none;
  margin-top: 1px;
}
.bk-flash.is-ok {
  border-left-color: var(--ok-fg);
  background: #f2fbf5;
}
.bk-flash.is-ok svg {
  color: var(--ok-fg);
}
.bk-flash.is-bad {
  border-left-color: var(--danger-fg);
  background: #fef4f4;
}
/* Neither settled nor refused: a card payment the bank approved and the
   platform has not yet confirmed with the gateway. Amber, not green — the
   customer must not read it as a completed purchase. */
.bk-flash.is-wait {
  border-left-color: var(--warn-fg);
  background: #fff8ee;
}
.bk-flash.is-wait svg {
  color: var(--warn-fg);
}
.bk-flash.is-bad svg {
  color: var(--danger-fg);
}

/* Multi-day schedule as a compact list. Was a 3-column table whose Description
   cell read "Details will be updated soon" on every row — 490px of panel for
   345 characters of real content. */
.ed-days {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.ed-day {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 11px 0;
  border-top: 1px solid var(--border);
}
.ed-day:first-child {
  border-top: 0;
  padding-top: 2px;
}
.ed-day-no {
  flex: none;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.03em;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--tint);
  color: var(--violet);
  margin-top: 1px;
}
.ed-day-body {
  min-width: 0;
  flex: 1;
}
.ed-day-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
}
.ed-day-head strong {
  font-size: 14.5px;
  color: var(--ink);
}
.ed-day-when {
  font-size: 13px;
  color: var(--gray);
  font-variant-numeric: tabular-nums;
}
.ed-day-desc {
  margin: 5px 0 0;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--gray);
}

/* Call for abstracts: deadline tag and the submit action on one row — they are
   a single decision. Stacked, they gave a 189px panel for one line of text. */
.ed-abs-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
}
.ed-abs-guide {
  margin-bottom: 14px;
}
@media (max-width: 520px) {
  .ed-abs-row {
    align-items: stretch;
  }
  .ed-abs-row .btn {
    width: 100%;
  }
}

/* Share panel in the right rail, directly under the ticket card. It sits inside
   the STICKY block, so every pixel it adds is a pixel of the ticket card that a
   short laptop viewport can no longer reach — hence the tighter padding and the
   smaller chips. Full-size chips (8px/16px, 13px) made it ~210px tall; these
   make it ~150px. */
.ed-share-panel {
  padding: 16px 18px;
}
.ed-share-panel .ed-h {
  font-size: 15px;
  margin-bottom: 10px;
}
.ed-share-panel .ed-share {
  padding: 6px 12px;
  font-size: 12px;
  gap: 5px;
}
.ed-share-panel .ed-share svg {
  width: 13px;
  height: 13px;
}

/* FAQ as one bordered list. Six separate <details> cards with a 12px gap gave
   537px of panel for six one-line questions. */
.ed-faq {
  display: flex;
  flex-direction: column;
}
/* The bare `details` selector above gives every accordion a white box, a
   border, a 12px radius and 20px/24px padding. Reset those here or the flat
   list still renders as six stacked cards. */
.ed-faq-item {
  background: none;
  border: 0;
  border-top: 1px solid var(--border);
  border-radius: 0;
  padding: 0;
}
.ed-faq-item:first-child {
  border-top: 0;
}
.ed-faq-item > summary {
  list-style: none;
  cursor: pointer;
  padding: 12px 30px 12px 0;
  position: relative;
  font-size: 14.5px;
  font-weight: 600;
  color: var(--ink);
  line-height: 1.45;
}
.ed-faq-item > summary::-webkit-details-marker {
  display: none;
}
.ed-faq-item > summary::after {
  content: "+";
  position: absolute;
  right: 6px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 17px;
  font-weight: 400;
  color: var(--violet);
  line-height: 1;
}
.ed-faq-item[open] > summary::after {
  content: "−";
}
.ed-faq-item > summary:hover {
  color: var(--violet);
}
.ed-faq-a {
  padding: 0 30px 13px 0;
  font-size: 14px;
  line-height: 1.6;
  color: var(--gray);
}
/* …and the element rules also set summary font-size/justify and `details div`
   padding-top, which fight the flat list. */
.ed-faq-item > summary {
  font-size: 14.5px;
  display: block;
  justify-content: initial;
}
.ed-faq-item > summary::after {
  font-size: 17px;
}
.ed-faq-item > .ed-faq-a {
  padding-top: 0;
}

/* "You already have a booking" notice, shown after the email is entered in
   step 2 of the booking modal. */
.ed-dup {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px 14px;
  margin-bottom: 16px;
  border: 1px solid var(--border);
  border-left-width: 4px;
  border-radius: 11px;
  font-size: 13.5px;
  line-height: 1.5;
}
.ed-dup.is-ok {
  border-left-color: var(--ok-fg);
  background: #f2fbf5;
}
.ed-dup.is-warn {
  border-left-color: var(--warn-fg);
  background: #fff9f0;
}
.ed-dup-acts {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

/* Sticky action bar — MOBILE ONLY. On a phone the ticket panel sits after the
   content (so the reader meets the event before the form), which leaves
   "Book now" ~4,300px down. The bar keeps the primary actions reachable
   without moving a 500px form above the first sentence. */
.ed-sticky-bar {
  display: none;
}
@media (max-width: 900px) {
  .ed-sticky-bar {
    display: flex;
    gap: 10px;
    align-items: stretch;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 60;
    padding: 10px var(--gutter);
    padding-bottom: calc(10px + env(safe-area-inset-bottom));
    background: color-mix(in srgb, var(--surface) 92%, transparent);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border-top: 1px solid var(--border);
    box-shadow: 0 -6px 20px rgba(22, 24, 29, 0.07);
  }
  .ed-sticky-bar .btn {
    flex: 1;
    justify-content: center;
    padding: 12px 14px;
    font-size: 14.5px;
  }
  .ed-sticky-bar .ed-btn-outline {
    flex: 0 0 auto;
    min-width: 104px;
  }
  .ed-sticky-book {
    display: flex;
    flex-direction: column;
    gap: 1px;
    line-height: 1.15;
  }
  .ed-sticky-from {
    font-size: 11.5px;
    font-weight: 500;
    opacity: 0.85;
  }
  /* The bar floats over the page end, so give the footer room to clear it. */
  body:has(.ed-sticky-bar) .footer {
    padding-bottom: 76px;
  }
}
.ed-dup-hint {
  color: var(--gray);
}

/* Mobile: the TICKET comes before "Set a password".
   The claim panel is a DOM sibling ahead of .ed-layout (which holds the ticket),
   so on a phone the attendee had to scroll past a signup form to reach the thing
   they opened the link for. Ordering is done with flex `order` rather than by
   moving the markup, because on desktop the claim panel legitimately sits above
   the two-column grid. */
@media (max-width: 900px) {
  .bk-page {
    display: flex;
    flex-direction: column;
  }
  /* Explicit orders so nothing depends on source position. */
  .bk-page > .bk-flash {
    order: 1;
  }
  .bk-page > .bk-head {
    order: 2;
  }
  .bk-page > .bk-status-row {
    order: 3;
  }
  /* The KYC card goes ABOVE the ticket: it is the reason the ticket is
     locked, so meeting it first is the shortest path to what they came for. */
  /* The KYC heads-up is context, not an alert: it belongs under the booking
     it is about, at every width. Without this it inherits .bk-flash order:1
     and jumps above the event title on a phone but not on a desktop. */
  .bk-page > .bk-kyc-heads {
    order: 4;
  }
  .bk-page > .bk-kyc {
    order: 4;
  }
  .bk-page > .ed-layout {
    order: 5;
  } /* ticket + details */
  .bk-page > .bk-claim {
    order: 6;
  } /* signup last */
  .bk-page > .bk-guest-tip {
    order: 6;
  }
  /* Direct children of a flex column do not constrain their own width. */
  .bk-page > * {
    width: 100%;
    min-width: 0;
  }
}

/* ── Event at a glance ───────────────────────────────────────────────────────
   Stat cards inside the house panel: an icon in a soft colour chip, the
   figure beside it, the label beneath. Each stat keeps its own accent so the
   row scans at a glance; the card itself stays quiet (faint wash + hairline)
   so seven of them don't shout. */
.ed-stats {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(158px, 1fr));
  gap: 10px;
}
.ed-stat {
  display: flex;
  align-items: center;
  gap: 11px;
  min-width: 0;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: linear-gradient(180deg, #fff, #fafafc);
}
.ed-stat-i {
  flex: 0 0 auto;
  width: 38px;
  height: 38px;
  border-radius: 10px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.ed-stat-i.is-blue {
  background: #eff6ff;
  color: #2563eb;
}
.ed-stat-i.is-violet {
  background: var(--tint);
  color: var(--violet);
}
.ed-stat-i.is-green {
  background: #ecfdf5;
  color: #059669;
}
.ed-stat-i.is-red {
  background: #fef2f2;
  color: #dc2626;
}
.ed-stat-i.is-orange {
  background: #fff7ed;
  color: #ea580c;
}
.ed-stat-i.is-pink {
  background: #fdf2f8;
  color: #db2777;
}
.ed-stat-i.is-teal {
  background: #f0fdfa;
  color: #0d9488;
}
.ed-stat-i.is-amber {
  background: #fefce8;
  color: #ca8a04;
}
.ed-stat-t {
  min-width: 0;
}
.ed-stat-n {
  font-size: 19px;
  font-weight: 750;
  line-height: 1.15;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ed-stat-n small {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--gray);
}
.ed-stat-l {
  font-size: 12px;
  font-weight: 600;
  color: var(--gray);
  margin-top: 1px;
}
/* Phones: compact chips — three usually fit a row (auto-fit at 96px), five
   wrap 3+2. Everything steps down together so nothing looks zoomed-in. */
@media (max-width: 560px) {
  .ed-stats {
    grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
    gap: 6px;
  }
  .ed-stat {
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
    padding: 9px 10px;
    border-radius: 10px;
  }
  .ed-stat-i {
    width: 26px;
    height: 26px;
    border-radius: 8px;
  }
  .ed-stat-i svg {
    width: 14px;
    height: 14px;
  }
  .ed-stat-n {
    font-size: 15px;
  }
  .ed-stat-n small {
    font-size: 10.5px;
  }
  .ed-stat-l {
    font-size: 10.5px;
    margin-top: 0;
  }
}

/* ── Event discussion ────────────────────────────────────────────────────────
   Reading is public; the form only renders for logged-in users. Replies are
   indented one level and no deeper — this is a discussion strip on an event
   page, not a forum. */
.ed-disc-form {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 6px;
}
.ed-disc-form textarea {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  font: inherit;
  font-size: 14px;
  resize: vertical;
  min-height: 64px;
}
.ed-disc-form textarea:focus {
  outline: none;
  border-color: var(--violet);
}
.ed-disc-form-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.ed-disc-form.is-reply {
  margin: 10px 0 2px 26px;
}
.ed-disc-login {
  margin: 0;
  font-size: 14px;
  color: var(--gray);
}
.ed-disc-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-top: 12px;
}
.ed-disc-item {
  display: flex;
  gap: 10px;
  padding: 11px 0;
  border-top: 1px solid var(--border);
}
.ed-disc-main {
  flex: 1;
  min-width: 0;
}
/* Photo when they have one; initials disc otherwise — a stock face for
   everyone without a photo would make six strangers identical. */
.ed-disc-avatar {
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  border-radius: 9px;
  object-fit: cover;
}
.ed-disc-avatar.is-initials {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--tint);
  color: var(--violet);
  font-size: 12px;
  font-weight: 750;
  letter-spacing: 0.02em;
}
.ed-disc-item.is-reply .ed-disc-avatar {
  width: 26px;
  height: 26px;
  font-size: 10.5px;
}
.ed-disc-item.is-reply {
  margin-left: 26px;
  padding-left: 12px;
  border-left: 2px solid var(--border);
  border-top: 0;
  padding-top: 6px;
}
/* Hidden = moderators only; greyed so it reads as moderated, not normal. */
.ed-disc-item.is-hidden {
  opacity: 0.55;
}
.ed-disc-head {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  font-size: 13.5px;
}
.ed-disc-head small {
  margin-left: auto;
}
.ed-disc-badge {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--tint);
  color: var(--violet);
}
.ed-disc-badge.is-warn {
  background: #fff4e5;
  color: #b25e09;
}
.ed-disc-body {
  margin: 5px 0 0;
  font-size: 14px;
  line-height: 1.55;
  color: var(--ink);
  overflow-wrap: anywhere;
}
.ed-disc-actions {
  display: flex;
  gap: 12px;
  margin-top: 5px;
}
.ed-disc-actions button {
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--violet);
}
.ed-disc-actions button.is-danger {
  color: #b21f1f;
}

/* ── Fonepay QR payment, inside the booking modal ────────────────────────────
   The attendee pays without leaving the page: the dynamic QR is rendered
   server-side by QREncoder and polled against Fonepay's signed status check. */
.ed-qr {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  text-align: center;
  padding: 4px 0;
}
.ed-qr-head {
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.ed-qr-amt {
  font-size: 28px;
  font-weight: 750;
  line-height: 1;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.ed-qr-ref {
  font-size: 12.5px;
  color: var(--gray);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
/* Fixed box so the layout does not jump when the image replaces the spinner. */
.ed-qr-frame {
  position: relative;
  display: grid;
  place-items: center;
  width: min(260px, 72vw);
  aspect-ratio: 1;
  padding: 12px;
  box-sizing: border-box;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 16px;
}
.ed-qr-frame img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}
.ed-qr-loading {
  font-size: 13px;
  color: var(--gray);
  max-width: 80%;
  line-height: 1.5;
}
.ed-qr-hint {
  margin: 0;
  font-size: 13px;
  line-height: 1.6;
  color: var(--gray);
  max-width: 44ch;
}
.ed-qr-state {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  font-weight: 600;
  padding: 7px 14px;
  border-radius: 999px;
  background: var(--tint);
  color: var(--violet);
}
.ed-qr-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
  animation: edQrPulse 1.4s ease-in-out infinite;
}
@keyframes edQrPulse {
  0%,
  100% {
    opacity: 0.35;
  }
  50% {
    opacity: 1;
  }
}
.ed-qr-state.is-paid {
  background: var(--ok-bg, #f2fbf5);
  color: var(--ok-fg);
}
.ed-qr-state.is-paid .ed-qr-dot {
  animation: none;
}
.ed-qr-state.is-expired {
  background: #fef4f4;
  color: var(--danger-fg);
}
.ed-qr-state.is-expired .ed-qr-dot {
  animation: none;
}
.ed-qr-alt {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: center;
  padding-top: 12px;
  border-top: 1px solid var(--border);
  width: 100%;
}
/* ── Pay from your banking app (Fonepay v2 intent) ───────────────────────────
   The deep-link list. On a phone this is the route that works — scanning a QR
   shown on the same screen you are holding needs a second device — so it sits
   above the QR and the QR collapses behind a toggle on narrow screens. */
.ed-qr-banks {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.ed-qr-banks-head {
  display: flex;
  flex-direction: column;
  gap: 2px;
  text-align: center;
}
.ed-qr-banks-head strong {
  font-size: 14px;
  color: var(--ink);
}
.ed-qr-banks-head small {
  font-size: 12.5px;
}
/* auto-fit rather than a fixed count: the list is 7 in sandbox and will be
   dozens in production, and it must not force the modal to scroll sideways. */
.ed-qr-bank-list {
  display: grid;
  gap: 8px;
  width: 100%;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
}
.ed-qr-bank {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: #fff;
  color: var(--ink);
  text-decoration: none;
  font-size: 13.5px;
  font-weight: 600;
  text-align: left;
  transition:
    border-color 0.15s,
    box-shadow 0.15s;
}
.ed-qr-bank:hover,
.ed-qr-bank:focus-visible {
  border-color: var(--violet);
  box-shadow: 0 0 0 3px var(--tint);
  outline: none;
}
/* Search across the bank list. Only rendered when the list is long enough to
   need it, so it never adds a field to a two-button choice. */
.ed-qr-bank-search {
  width: 100%;
  margin: 0 0 10px;
}
.ed-qr-bank-search input {
  width: 100%;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: #fff;
  color: var(--ink);
  font: inherit;
  font-size: 13.5px;
}
.ed-qr-bank-search input:focus {
  border-color: var(--violet);
  box-shadow: 0 0 0 3px var(--tint);
  outline: none;
}
.ed-qr-bank-none {
  margin: 10px 0 0;
  font-size: 13px;
  color: var(--gray);
}

/* Initials are the fallback when no absolute logo URL is available — the
   sandbox returns relative icon paths with no documented base. */
.ed-qr-bank-mark {
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  border-radius: 8px;
  display: grid;
  place-items: center;
  background: var(--tint);
  color: var(--violet);
  font-size: 11.5px;
  font-weight: 750;
  letter-spacing: 0.02em;
}
/* The real bank logo, when Fonepay gives an absolute URL for it. Same box as
   the initials it replaces, so the row height never shifts as logos decode.
   contain, not cover: these are wordmarks on white, and cropping them to fill
   a square would cut the bank's name in half. */
.ed-qr-bank-logo {
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  border-radius: 8px;
  object-fit: contain;
  background: #fff;
}
.ed-qr-bank-mark[hidden] { display: none; }
.ed-qr-bank-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ed-qr-scan {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  width: 100%;
}
.ed-qr-scan-toggle {
  background: none;
  border: 0;
  padding: 4px 2px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
  color: var(--violet);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.ed-qr-scan-toggle:focus-visible {
  outline: 2px solid var(--violet);
  outline-offset: 2px;
  border-radius: 6px;
}

/* QR and bank list side by side once there is room for both.
   auto-fit rather than two fixed columns: the bank list is [hidden] for v1 and
   whenever the roster could not be fetched, and auto-fit then gives the QR the
   whole width instead of stranding it in half with an empty column beside it.
   Below the breakpoint this stays a plain block, so the phone keeps the
   existing stacked order with the QR collapsed behind its toggle. */
/* The QR always comes FIRST — stacked above the bank list on a phone, in the
   left column on a desktop. It is the one route that works on every device, so
   it leads regardless of width; `order` does the reordering because the bank
   list must stay first in the DOM for the markup to read sensibly. */
.ed-qr-split {
  display: flex;
  flex-direction: column;
  gap: 18px;
  width: 100%;
}
.ed-qr-split > .ed-qr-scan {
  order: -1;
}
@media (min-width: 760px) {
  .ed-qr-split {
    display: grid;
    /* auto-fit, so a hidden bank list (v1, or a roster that failed to load)
       leaves the QR the full width instead of half with a gap beside it. */
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 22px;
    align-items: start;
  }
  .ed-qr-split > .ed-qr-banks {
    border-left: 1px solid var(--border);
    padding-left: 22px;
  }
  /* One visible child means one column, and the divider would be a line in
     mid-air. */
  .ed-qr-split > .ed-qr-banks:only-child {
    border-left: 0;
    padding-left: 0;
  }
  /* Two banks per row. The column is wide enough for it only because the
     dialog widens below; minmax(0,…) lets each cell shrink so the long names
     ellipsis instead of forcing the grid wider. */
  .ed-qr-split .ed-qr-bank-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* 640px fits one column; two need more. Applied only while the bank list is
   actually on screen, so every other step of the booking modal keeps its
   normal width. */
@media (min-width: 900px) {
  .ed-modal-dialog--qr-split {
    max-width: 880px;
  }
}

/* ── Card payment (GetPay by NCHL) ───────────────────────────────────────
   #checkout is NCHL bundle territory: it mounts its own form there and owns
   everything inside, so only the box is styled here. min-height keeps the
   dialog from collapsing while the script loads. */
.ed-card-pay {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  text-align: center;
  padding: 4px 0;
}
.ed-card-status {
  font-size: 13px;
  color: var(--gray);
  line-height: 1.5;
  max-width: 44ch;
}
.ed-card-mount {
  width: 100%;
  min-height: 120px;
}
.ed-card-mount:empty {
  min-height: 0;
}
@media (prefers-reduced-motion: reduce) {
  .ed-qr-dot {
    animation: none;
  }
}

/* Feature-card glyphs now hold an SVG rather than a two-letter text stub, so
   the icon needs sizing. .og-head .glyph elsewhere is still text — hence the
   :has(svg) guard rather than changing the shared rule. */
.card .glyph:has(svg) {
  line-height: 0;
}
.card .glyph svg {
  width: 20px;
  height: 20px;
  display: block;
}

/* ── Venue cards ─────────────────────────────────────────────────────────────
   Location, capacity and operator as labelled facts with icons, instead of one
   run-on grey line. Cards stretch to equal height so a row reads as a set. */
.event-card .vn-name {
  font-size: 17px;
  font-weight: 700;
  line-height: 1.3;
  color: var(--ink);
}
.vn-facts {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.vn-facts li {
  display: flex;
  align-items: flex-start;
  gap: 7px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--gray);
}
.vn-facts svg {
  flex: none;
  margin-top: 1px;
  color: var(--violet);
  opacity: 0.8;
}
.vn-facts span {
  min-width: 0;
  overflow-wrap: anywhere;
}
.vn-foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  margin-top: auto;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
/* The "View venue" link INSIDE a venue card (the card's wrapper is
   .event-card, shared with events). Scoped, because the bare .vn-cta also
   matched the venue DETAIL page's "Host your event here" panel, which is
   `class="vn-card vn-cta"` — and being later in the file this won, turning a
   stacked card into one inline-flex row. The heading, the description and both
   buttons were crushed side by side, each breaking down four lines on a
   phone. */
.event-card .vn-cta {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 13.5px;
  font-weight: 700;
  color: var(--violet);
}
.event-card .vn-cta svg {
  opacity: 0.75;
}
/* One fact line INSIDE a venue card. Scoped for the same reason as .vn-cta
   above: the bare selector also hit the venue detail page's meta row, and
   being later it replaced that row's wrapping 8px/20px flex with a tight
   4px inline-flex — so the location ran straight into the next icon
   ("…Koshi Province, Nepal" hard against the capacity glyph). */
.event-card .vn-meta {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  color: var(--gray);
  font-variant-numeric: tabular-nums;
}
.event-card .vn-meta svg {
  opacity: 0.7;
}
.event-card:hover .vn-cta {
  text-decoration: underline;
}
/* Page-header lede: one line of orientation under a page title. */
.pg-head-lede {
  margin: 10px 0 20px;
  /* The page-lede tier — see .ev-hero p. */
  font-size: clamp(15px, 1.8vw, 17px);
  line-height: 1.6;
  color: var(--gray);
  max-width: 56ch;
}
/* One or two items: keep the cards at a natural card width rather than letting
   a single event stretch the full container. */
.grid-3[style*="--cols:1"] {
  grid-template-columns: minmax(0, 380px);
}
.grid-3[style*="--cols:2"] {
  grid-template-columns: repeat(2, minmax(0, 420px));
}

/* ===========================================================================
   Organiser profile — /organizer/{slug}

   Shaped after the way a ticketing platform presents an organiser: a tinted
   hero holding the mark, the name and one line of social proof, with Follow /
   Contact / Share to its right; then the events in a single card with Upcoming
   and Past tabs, so a visitor is not scrolled past a wall of finished events to
   reach the one they can still buy.
   =========================================================================== */
.op-hero {
  position: relative;
  overflow: hidden;
  background: linear-gradient(
    180deg,
    rgba(124, 58, 237, 0.06),
    rgba(124, 58, 237, 0.02)
  );
  border-bottom: 1px solid #f0edf7;
}
.op-hero .container {
  max-width: 1360px;
  padding-block: clamp(16px, 2.6vw, 28px) clamp(20px, 3vw, 34px);
}
.op-crumbs {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
  font-size: 13px;
  color: var(--gray);
  margin-bottom: 20px;
}
.op-crumbs a {
  color: var(--gray);
}
.op-crumbs a:hover {
  color: var(--violet);
}
.op-crumb-here {
  color: var(--ink);
  font-weight: 600;
}

.op-profile-card {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 22px;
  box-shadow: 0 14px 30px rgba(17, 24, 39, 0.05);
  padding: 18px 18px 16px;
  /* Rests ON the bottom edge of the cover so the two read as ONE object
     rather than a picture with an unrelated slab under it. Full width, NOT
     inset: a narrower card leaves a sliver of cover down each side, which
     reads as a mistake. */
  position: relative;
  z-index: 1;
  margin-top: -24px;
  display: flex;
  gap: 18px;
  align-items: flex-start;
  flex-wrap: wrap;
}

/* Cover banner — the logo tile overlaps its bottom edge, so the row below
   switches to top alignment and pulls only the tile up (a white ring makes it
   read as a profile picture, the way every profile site draws it). */
.op-cover {
  width: 100%;
  aspect-ratio: 820 / 312;
  height: auto;
  /* The card covers the bottom edge, so those corners would be invisible
     anyway — squaring them keeps the seam clean at any card width. */
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
  border-radius: 16px;
  background-position: center;
  background-size: cover;
  background-color: var(--tint);
  border: 1px solid var(--border);
  box-sizing: border-box;
  margin-bottom: 0;
}
.op-ident.has-cover {
  align-items: flex-start;
  margin-top: 14px;
  padding: 0 10px;
}
@media (max-width: 640px) {
  .op-cover { aspect-ratio: 16 / 9; }
}
.op-ident.has-cover .op-logo-wrap {
  /* Breaks the card's top edge, nothing more. This was -56px from when the
     card sat flush BELOW the cover; once the card itself moved up, the two
     negative margins stacked and the avatar floated clear of it. Raised with
     the tile from 116 to 132px so the same proportion of it sits over the
     cover rather than the card swallowing the extra height. */
  margin-top: -46px;
  border: 3px solid #fff;
  box-shadow: 0 2px 12px rgba(22, 24, 29, 0.14);
}

.op-ident {
  display: flex;
  gap: 24px;
  align-items: center;
  flex-wrap: wrap;
  flex: 1 1 420px;
  min-width: 0;
}
/* A white tile of a fixed size with the artwork CONTAINED inside it. Logos here
   range from a square crest to a 1.9:1 wordmark; cover would crop the wordmark
   to its first few letters, and letting the tile follow the artwork made the
   row jump around between organisers. */
.op-logo-wrap {
  /* Bigger than it was (116px), so the avatar holds its own against a cover
     more than four times its width. A small avatar under a large cover left
     the name as the loudest thing in the hero. */
  width: 132px;
  height: 132px;
  border-radius: 24px;
  border: 1px solid rgba(124, 58, 237, 0.14);
  background: linear-gradient(135deg, #fff, #f5f3ff);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  box-sizing: border-box;
  flex: none;
  overflow: hidden;
  box-shadow: 0 10px 22px rgba(124, 58, 237, 0.08);
}
.op-logo {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  background: #f4f1ff;
}
.op-logo-ph {
  font-size: 34px;
  font-weight: 800;
  color: var(--violet);
  background: var(--tint);
  padding: 0;
}

.op-ident-body {
  flex: 1 1 340px;
  min-width: 0;
}
.op-kicker {
  margin: 0 0 4px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--violet);
}
.op-name {
  margin: 0;
  /* 32px at the top end, matching .ed-title on the event page. This ran to
     38px, which is the PAGE-TITLE tier — but this name sits inside a card,
     under a large cover and beside a 110px avatar, so at 38px it outweighed
     both and the hero read as text with a picture attached. */
  font-size: clamp(24px, 3vw, 32px);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.12;
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
.op-verified {
  font-size: 12px;
  font-weight: 700;
  color: var(--violet);
  background: #fff;
  border: 1px solid var(--violet-pale);
  border-radius: 100px;
  padding: 4px 12px;
  letter-spacing: 0;
}
.op-spec {
  margin: 8px 0 0;
  font-size: 14px;
  font-weight: 700;
  color: var(--violet);
}

/* One line of social proof, dot-separated, wrapping on narrow screens. */
.op-metrics {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 12px;
  margin: 12px 0 0;
  padding: 0;
  font-size: 14px;
  color: var(--gray);
}
.op-metrics li {
  display: flex;
  align-items: center;
  gap: 5px;
}
.op-metrics li:not(:last-child)::after {
  content: "\00B7";
  margin-left: 12px;
  color: #cbd5e1;
  font-weight: 700;
}
.op-metrics strong {
  color: var(--ink);
  font-weight: 800;
  font-size: 15px;
}
.op-metric-rating a {
  font-weight: 600;
}
.op-where {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 10px 0 0;
  font-size: 14px;
  color: var(--gray);
}
/* Hero facts (was the sidebar details panel): two columns, icon per fact. */
.op-hero-facts {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px 18px;
  margin-top: 12px;
  max-width: 760px;
}
@media (max-width: 560px) {
  .op-hero-facts {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px 10px;
  }
  .op-fact {
    font-size: 12.2px;
    line-height: 1.35;
  }
}
.op-fact {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: 13.5px;
  color: var(--gray);
  min-width: 0;
}
/* A flex child does not shrink below its content by default, so an address
   like anubhav@eventio360.com pushed straight out of its column. */
.op-fact > * {
  min-width: 0;
  overflow-wrap: anywhere;
}
/* A fact too long for half a row — the email — spans the grid instead of
   breaking mid-word down two lines. */
.op-fact.is-wide {
  grid-column: 1 / -1;
}
.op-fact svg {
  margin-top: 2px;
  color: var(--violet);
  flex: none;
}
.op-fact a {
  color: var(--violet);
  font-weight: 600;
  overflow-wrap: anywhere;
}
.op-hero-soc {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 12px;
}
.op-soc-btn {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--violet);
  transition: border-color 0.12s;
}
.op-soc-btn:hover {
  border-color: var(--violet);
}
/* Services offered: three across on desktop, as reviewed. */
.op-svc-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
}
@media (max-width: 1000px) {
  .op-svc-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (max-width: 560px) {
  .op-svc-grid {
    grid-template-columns: 1fr;
  }
}
.op-where svg {
  flex: none;
}

.op-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  align-items: center;
  margin-left: auto;
  padding-top: 8px;
}
.op-actions .btn {
  min-width: 118px;
  justify-content: center;
  border-radius: 999px;
  box-shadow: 0 6px 14px rgba(124, 58, 237, 0.08);
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.op-actions .btn.is-on {
  background: var(--violet);
  color: #fff;
}
.btn-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
.btn-icon svg {
  display: block;
}

/* Details row: two columns of facts / tap-to-act / socials, and the share
   panel in the third. On a desktop the panel is ALWAYS shown (the CSS below
   overrides its `hidden`); on a phone it drops under the details and the
   Share button toggles it. */
.op-body-row {
  /* A full row of the (flex-wrap) card, under the name and the buttons: two
     columns of details, and a third that opens for the share panel only while
     it is shown (.is-open), so a closed panel leaves no empty column. */
  flex: 1 1 100%;
  width: 100%;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 18px 28px;
  align-items: start;
  margin-top: 6px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}
.op-body-row.is-open {
  grid-template-columns: minmax(0, 2fr) minmax(360px, 1fr);
}
/* Shown only when the Share button asks for it — on every screen size. */
.op-share:not(.is-open) { display: none; }
.op-details {
  min-width: 0;
}
.op-details .op-hero-facts { margin-top: 0; }
/* Chips on the left, the QR on the right — one compact block, not a stack. */
.op-share {
  min-width: 0;
  padding: 14px 16px;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: #faf9fc;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 128px;
  grid-template-areas: "title title" "chips qr";
  gap: 10px 16px;
  align-items: start;
}
.op-share-title { grid-area: title; }
.op-share-chips { grid-area: chips; align-content: start; }
.op-share-qr {
  grid-area: qr;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 6px;
}
.op-share-title {
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gray);
}
.op-share .op-chip {
  padding: 7px 12px;
  font-size: 12.5px;
}
@media (max-width: 900px) {
  .op-body-row, .op-body-row.is-open { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .op-share { margin-top: 14px; }
}
@media (max-width: 480px) {
  .op-share { grid-template-columns: minmax(0, 1fr); grid-template-areas: "title" "chips" "qr"; }
}
.op-share-chips {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  min-width: 0;
}
.op-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  border: 1px solid var(--border);
  border-radius: 100px;
  padding: 8px 15px;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
  background: #fff;
  cursor: pointer;
  font-family: inherit;
}
.op-chip:hover {
  border-color: var(--violet-pale);
  color: var(--violet);
}
.op-share-qr {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: none;
}
.op-share-qr img {
  width: 92px;
  height: 92px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: #fff;
  padding: 5px;
  display: block;
}
.op-share-qr-cap {
  margin: 0 0 4px;
  font-size: 13px;
  font-weight: 600;
}
.op-share-qr-dl {
  font-size: 12px;
  font-weight: 700;
}

/* ------------------------------------------------------------------ body -- */
.op-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: 18px;
  align-items: start;
}
.op-main {
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-width: 0;
}
.op-side {
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-width: 0;
  position: sticky;
  top: 76px;
  /* A sticky column pins its TOP, so anything past the fold is unreachable —
     the column simply stops scrolling with the page. With About now leading
     this column it runs well past a laptop viewport, so cap it and let the
     column scroll on its own. */
  max-height: calc(100vh - 92px);
  overflow-y: auto;
  overscroll-behavior: contain;
  /* Room for the scrollbar so it never sits on top of the panel borders. */
  scrollbar-width: thin;
}
.op-panel {
  border: 1px solid var(--border);
  border-radius: 14px;
  background: #fff;
  padding: 20px 22px;
}
.op-h {
  margin: 0 0 14px;
  font-size: 17px;
  font-weight: 750;
  letter-spacing: -0.02em;
}
.op-body {
  margin: 0;
  font-size: 15px;
  line-height: 1.65;
  color: var(--gray);
}
.op-muted {
  color: var(--gray);
  font-size: 14px;
}
.op-w100 {
  width: 100%;
}

/* Tabs. Underline rather than pills: this is navigation inside a card, and
   pills would compete with the Follow button a few hundred pixels above. */
.op-tabs {
  display: flex;
  gap: 6px;
  border-bottom: 1px solid var(--border);
  margin: -4px 0 18px;
}
.op-tab {
  border: 0;
  background: none;
  cursor: pointer;
  font-family: inherit;
  font-size: 15px;
  font-weight: 700;
  color: var(--gray);
  padding: 10px 4px 12px;
  margin-right: 14px;
  border-bottom: 2px solid transparent;
  display: flex;
  align-items: center;
  gap: 8px;
}
.op-tab:hover {
  color: var(--ink);
}
.op-tab.is-on {
  color: var(--ink);
  border-bottom-color: var(--violet);
}
.op-tab-n {
  font-size: 12px;
  font-weight: 700;
  color: var(--gray);
  background: var(--tint);
  border-radius: 100px;
  padding: 2px 8px;
  min-width: 18px;
  text-align: center;
}
.op-tab.is-on .op-tab-n {
  color: var(--violet);
}
.op-tab:focus-visible {
  outline: 2px solid var(--violet);
  outline-offset: 2px;
  border-radius: 6px;
}

/* The events grid sizes itself: two across in the content column, one on a
   phone, without the page having to count the rows. */
.op-events {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 18px;
}
.op-empty {
  padding: 14px 0 4px;
}
.op-empty p {
  margin: 0 0 4px;
}

.op-dl {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.op-dl > div {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.op-dl dt {
  font-size: 12px;
  color: var(--gray);
}
.op-dl dd {
  margin: 0;
  font-size: 14px;
  font-weight: 600;
  word-break: break-word;
}
.op-links {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.op-link {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  border: 1px solid var(--border);
  border-radius: 100px;
  padding: 7px 14px;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
  background: #fff;
}
.op-link svg {
  color: var(--violet);
  flex: none;
}
.op-link:hover {
  border-color: var(--violet-pale);
  color: var(--violet);
}

.op-rating-summary {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 16px;
}
.op-rating-big {
  font-size: 40px;
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1;
}

/* Rating form. The stars are real buttons so they are keyboard reachable; the
   hover preview repaints on mouseenter and snaps back on mouseleave. */
.op-rate {
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--tint-bg);
  padding: 16px 18px;
  margin-bottom: 18px;
}
.op-rate-h {
  margin: 0;
  font-size: 15px;
  font-weight: 700;
}
.op-rate-sub {
  margin: 4px 0 10px;
  font-size: 13px;
}
.op-stars-input {
  display: flex;
  gap: 4px;
  margin-bottom: 10px;
}
.op-star {
  border: 0;
  background: none;
  cursor: pointer;
  font-size: 26px;
  line-height: 1;
  padding: 0 2px;
  color: #e5e7eb;
  font-family: inherit;
}
.op-star.is-on {
  color: #f59e0b;
}
.op-star:focus-visible {
  outline: 2px solid var(--violet);
  outline-offset: 2px;
  border-radius: 4px;
}
.op-textarea {
  width: 100%;
  box-sizing: border-box;
  border: 1px solid #e4e0ef;
  border-radius: 10px;
  padding: 10px 12px;
  font-family: inherit;
  font-size: 14px;
  color: var(--ink);
  background: #fff;
  resize: vertical;
  outline: none;
}
.op-textarea:focus {
  border-color: var(--violet-pale);
}
.op-rate-foot {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 10px;
}
.op-rate-msg {
  font-size: 13px;
  color: var(--gray);
}
.op-rate-msg.is-good {
  color: #15803d;
}
.op-rate-msg.is-bad {
  color: #b91c1c;
}
.op-rate-note {
  margin: 0 0 16px;
}

.op-reviews {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}
.op-review {
  padding: 16px 0;
  border-top: 1px solid var(--border);
}
.op-review:first-child {
  border-top: 0;
  padding-top: 0;
}
.op-review-head {
  display: flex;
  gap: 12px;
  align-items: flex-start;
}
.op-avatar {
  width: 36px;
  height: 36px;
  border-radius: 10px;
  background: var(--tint);
  color: var(--violet);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 700;
  flex: none;
}
.op-review-meta {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
  font-size: 12px;
  margin-top: 2px;
}
.op-review-text {
  margin: 10px 0 0;
  font-size: 14px;
  line-height: 1.6;
  color: var(--gray);
}

@media (max-width: 900px) {
  .op-grid {
    grid-template-columns: 1fr;
  }
  .op-side {
    position: static;
    /* One column here, so the side panels are just more page. The desktop
       height cap and its own scrollbar would trap them in a short box. */
    max-height: none;
    overflow-y: visible;
  }
  .op-profile-card {
    padding: 14px 14px 12px;
  }
  .op-actions {
    margin-left: 0;
    width: 100%;
    padding-top: 0;
  }
  .op-actions .btn {
    flex: 1 1 auto;
  }
  .op-share {
    justify-content: flex-start;
  }
}
@media (max-width: 900px) {
  .provider-card {
    grid-template-columns: 108px minmax(0, 1fr);
    gap: 12px;
  }
  .provider-banner {
    width: 108px;
    height: 108px;
  }
}
@media (max-width: 560px) {
  .provider-card {
    grid-template-columns: 92px minmax(0, 1fr);
    gap: 12px;
    padding: 10px;
  }
  .provider-banner {
    width: 92px;
    height: 92px;
    border-radius: 14px;
  }
  .provider-head {
    flex-direction: column;
    align-items: flex-start;
  }
  .provider-side {
    align-items: flex-start;
    flex-direction: row;
    flex-wrap: wrap;
  }
  .op-profile-card {
    padding: 12px;
    border-radius: 18px;
    box-shadow: 0 12px 24px rgba(17, 24, 39, 0.05);
  }
  .op-ident {
    gap: 12px;
    align-items: flex-start;
    flex-direction: row;
  }
  .op-logo-wrap {
    width: 74px;
    height: 74px;
    border-radius: 16px;
    box-shadow: 0 8px 18px rgba(124, 58, 237, 0.08);
  }
  .op-ident.has-cover {
    margin-top: 10px;
    padding: 0 4px;
  }
  .op-ident.has-cover .op-logo-wrap {
    margin-top: -38px;
  }
  .op-logo-ph {
    font-size: 22px;
  }
  .op-name {
    font-size: clamp(23px, 7vw, 30px);
    gap: 8px;
  }
  .op-metrics {
    gap: 6px 14px;
    font-size: 13px;
  }
  .op-hero-facts {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .op-actions {
    width: 100%;
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 8px;
  }
  .op-actions .btn {
    width: 100%;
    min-width: 0;
  }
  .op-share-qr {
    width: 100%;
  }
  .op-events {
    grid-template-columns: 1fr;
  }
}

/* Follow row in the event page's "Organized by" card. */
.ed-follow-row {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin: 0 0 12px;
}
.ed-follow-row .btn {
  min-width: 104px;
  justify-content: center;
}

/* ── The organiser / provider card on a phone ──────────────────────────
   It had no mobile rules, so a 56px logo sat beside a wrapping heading, the
   follow row split across two lines and the action buttons ran ragged — every
   part at its own indent. Centred stack, even button grid, one edge. */
@media (max-width: 560px) {
  .ed-org {
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 10px;
  }
  .ed-org-body {
    min-width: 0;
    width: 100%;
  }
  .ed-org-logo,
  .ed-org-ph {
    margin: 0 auto;
  }
  .ed-follow-row {
    justify-content: center;
    gap: 10px;
    margin-bottom: 14px;
  }
  .ed-follow-row .btn {
    width: 100%;
    min-width: 0;
  }
  /* The contact lines are the card's only left-aligned block on a desktop;
     centred they read as part of the same stack. */
  .ed-org-body > div[style*="flex-direction:column"] {
    align-items: center;
  }
  /* Two even columns rather than whatever fits — the row that used to wrap
     1-2-1 across three lines. */
  .ed-org .op-card-acts {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
    width: 100%;
  }
  .ed-org .op-card-act {
    width: 100%;
    justify-content: center;
  }
  .ed-org-hero .ed-share {
    justify-content: center;
  }
}

/* Share QR. Hidden until the chip is pressed, so the panel keeps its height in
   the sticky rail and the PNG is never fetched unless someone wants it. */
.ed-share-qr {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
  text-align: center;
}
.ed-share-qr img {
  width: 150px;
  height: 150px;
  display: block;
  margin: 0 auto;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: #fff;
  padding: 6px;
}
.ed-share-qr-cap {
  margin: 8px 0 4px;
  font-size: 12px;
  color: var(--gray);
}
.ed-share-qr-dl {
  font-size: 12px;
  font-weight: 700;
}
.ed-share.is-on {
  border-color: var(--violet);
  color: var(--violet);
  background: var(--tint);
}

/* Free event: the note that replaces the payment step. */
.ed-free-note {
  display: flex;
  flex-direction: column;
  gap: 3px;
  margin-bottom: 14px;
}
.ed-free-note strong {
  font-size: 14px;
  color: var(--ink);
}
.ed-free-note span {
  font-size: 13px;
  color: var(--gray);
}

/* "All my bookings" — the page a Find-my-tickets email links to. */
.bk-list {
  max-width: 720px;
  margin: 0 auto;
}
.bk-list-head {
  margin-bottom: 20px;
}
.bk-list-head h1 {
  font-size: clamp(24px, 3.4vw, 32px);
  font-weight: 800;
  letter-spacing: -0.03em;
  margin: 8px 0 6px;
}
.bk-list-head p {
  margin: 0;
  font-size: 15px;
  color: var(--gray);
}
.bk-list-items {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.bk-list-item {
  display: flex;
  align-items: center;
  gap: 16px;
  justify-content: space-between;
  flex-wrap: wrap;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: #fff;
  padding: 16px 18px;
}
.bk-list-main {
  min-width: 0;
  flex: 1 1 260px;
}
.bk-list-title {
  font-size: 16px;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.bk-list-meta {
  display: flex;
  gap: 8px 14px;
  flex-wrap: wrap;
  align-items: center;
  margin-top: 5px;
  font-size: 13px;
  color: var(--gray);
}
.bk-pill {
  font-size: 11px;
  font-weight: 700;
  border-radius: 100px;
  padding: 3px 10px;
  letter-spacing: 0.01em;
}
.bk-pill-ok {
  background: #dcfce7;
  color: #15803d;
}
.bk-pill-wait {
  background: #fef3c7;
  color: #b45309;
}
@media (max-width: 560px) {
  .bk-list-item {
    align-items: stretch;
  }
  .bk-list-item .btn {
    width: 100%;
    justify-content: center;
  }
}

/* Related events close the event page across its full width. A 320px column at
   grid-row 3 left one narrow card alone at the bottom beside an empty content
   column, which is what this replaces. */
.ed-more {
  margin: 26px 0 8px;
  padding-top: 24px;
  border-top: 1px solid var(--border);
}
.ed-more-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}
.ed-more-head h2 {
  margin: 0;
  font-size: 20px;
  font-weight: 800;
  letter-spacing: -0.02em;
}
.ed-more-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 18px;
}
@media (max-width: 560px) {
  .ed-more-grid {
    grid-template-columns: 1fr;
  }
  .ed-more-head .btn {
    width: 100%;
    justify-content: center;
  }
}

/* The organizer's name beside their logo on the portrait ticket. Deliberately
   small — it identifies who is running the event, it is not the headline — and
   it wraps to a second line instead of ellipsising, which is what an earlier
   attempt did to "Society of Surgeons of Nepal". */
.tk-org-name-sm {
  font-size: 12px;
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: 0;
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  max-width: 190px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Two-line option in the searchable select: the thing, then the detail that
   tells two similarly named things apart. Used by the ticket lookup's event
   picker, where three events can all be called "test". */
.ev-ss-item.has-sub {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 8px 9px;
}
.ev-ss-t {
  font-weight: 600;
  line-height: 1.25;
}
.ev-ss-s {
  font-size: 11.5px;
  line-height: 1.3;
  color: var(--gray);
}
.ev-ss-item:hover .ev-ss-s,
.ev-ss-item.is-cursor .ev-ss-s {
  color: var(--violet);
}
.ev-ss-list {
  max-height: 280px;
}

/* The "why might nothing arrive" line under the lookup confirmation. */
.bk-neutral-why {
  margin: 8px 0 0;
  font-size: 13px;
  line-height: 1.55;
  color: var(--gray);
}
/* Signup: the dial code sits beside the mobile box as text, not an input — it
   is derived from the country and stored in users.country_code. */
.dial-row {
  display: flex;
  align-items: stretch;
  gap: 8px;
}
.dial-row .dial-code {
  display: flex;
  align-items: center;
  padding: 0 12px;
  border: 1px solid #e4e0ef;
  border-radius: 10px;
  background: #f7f5fc;
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
  white-space: nowrap;
  min-width: 64px;
  justify-content: center;
}
.dial-row .auth-input {
  flex: 1 1 auto;
  min-width: 0;
}
.auth-hint {
  display: block;
  font-size: 12px;
  color: var(--gray);
  margin-top: 2px;
}

/* Four pricing plans: 36px card padding leaves too little room in a 1100px
   container, and four tracks are unreadable before the 900px 1-col step. */
.grid-3[style*="--cols:4"] .plan {
  padding: 28px 22px;
  gap: 18px;
}
@media (min-width: 901px) and (max-width: 1080px) {
  .grid-3[style*="--cols:4"] {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
/* The card's "when" line sits above "where" and shares its shape. */
.event-when {
  margin-bottom: 4px;
}
.event-when .event-where-lines span {
  color: var(--ink);
  font-weight: 600;
}
/* Save-the-date buttons under the booking facts. */
.bk-cal {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 12px;
}
/* Why the certificate is not here yet, said where the button would be. */
.bk-cert-note {
  align-self: center;
  font-size: 12.5px;
  color: var(--gray);
}

.op-chip svg {
  color: var(--violet);
  flex: none;
}

/* Portfolio grid on the profile — same 3-across rhythm as the services grid. */
.op-pf-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
}
@media (max-width: 1000px) {
  .op-pf-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (max-width: 560px) {
  .op-pf-grid {
    grid-template-columns: 1fr;
  }
}
.op-pf-card {
  display: block;
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
  background: #fff;
  color: inherit;
  transition:
    box-shadow 0.15s,
    transform 0.15s;
}
a.op-pf-card:hover {
  box-shadow: 0 8px 20px rgba(22, 24, 29, 0.09);
  transform: translateY(-2px);
}
.op-pf-img {
  aspect-ratio: 16/10;
  background-size: cover;
  background-position: center;
}
.op-pf-body {
  padding: 10px 12px;
}
.op-pf-title {
  font-size: 13.5px;
  font-weight: 700;
  line-height: 1.35;
}
.op-pf-client {
  font-size: 12px;
  color: var(--gray);
  margin-top: 2px;
}

/* Clients strip: a logo per tile, the name standing in when there is none.
   Logos are CONTAINED — a wordmark and a square crest sit in the same tile. */
.op-cl-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 12px;
}
.op-cl-card {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 78px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: #fff;
  color: var(--ink);
  text-decoration: none;
  transition: box-shadow 0.15s, transform 0.15s, border-color 0.15s;
}
a.op-cl-card:hover {
  border-color: var(--violet-pale);
  box-shadow: 0 8px 20px rgba(22, 24, 29, 0.09);
  transform: translateY(-2px);
}
.op-cl-logo {
  max-width: 100%;
  max-height: 48px;
  width: auto;
  height: auto;
  object-fit: contain;
  display: block;
}
.op-cl-name {
  font-size: 13.5px;
  font-weight: 700;
  text-align: center;
  line-height: 1.3;
}

/* Service-card CTA (decorative — the whole card is the link) and the service
   page's facts/steps blocks. */
.svc-cta {
  display: block;
  text-align: center;
  margin-top: 12px;
  pointer-events: none;
}
.svc-facts {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px 20px;
}
@media (max-width: 560px) {
  .svc-facts {
    grid-template-columns: 1fr;
  }
}
.svc-facts > div {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.svc-fact-l {
  font-size: 12px;
  color: var(--gray);
}
.svc-fact-v {
  font-size: 14px;
  font-weight: 600;
}
.svc-steps {
  margin: 0;
  padding-left: 20px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  font-size: 14px;
  line-height: 1.6;
  color: var(--gray);
}
.svc-steps b {
  color: var(--ink);
}

/* Service booking — online payment buttons. */
.svc-pay-methods {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.svc-pay-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  width: 100%;
  padding: 13px 18px;
  font-size: 14.5px;
}
.svc-pay-btn[disabled] {
  opacity: 0.6;
  cursor: default;
}
.svc-pay-btn img {
  display: block;
  border: 0;
}
.svc-pay-sandbox {
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  background: rgba(255, 255, 255, 0.22);
  padding: 2px 7px;
  border-radius: 100px;
}

/* ── Profile as a digital card ──────────────────────────────────────────────
   The link a creator puts in their bio is opened on a phone, so at ≤640px the
   hero becomes a centred card: cover, logo on top of it, name, facts, then the
   things a phone can act on. Desktop keeps the wide layout. */
.op-card-acts {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: center;
  margin-top: 14px;
}
/* Keeps the labelled pills and the round social icons legible as two groups
   on one line. */
.op-acts-sep {
  width: 1px;
  align-self: stretch;
  min-height: 22px;
  background: var(--border);
  margin: 0 2px;
}
/* An address like anubhav@eventio360.com is wider than half a 390px screen;
   without this it ran out of its column. */
.op-fact a,
.op-fact span {
  min-width: 0;
  overflow-wrap: anywhere;
}
.op-card-act {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 14px;
  border-radius: 100px;
  border: 1px solid var(--border);
  background: #fff;
  color: var(--ink);
  font-size: 13px;
  font-weight: 600;
  transition:
    border-color 0.12s,
    box-shadow 0.12s;
}
.op-card-act:hover {
  border-color: var(--violet);
  color: var(--violet);
}
.op-card-act-ic {
  display: inline-flex;
  color: var(--violet);
}
.op-card-act.is-primary {
  background: var(--violet);
  border-color: var(--violet);
  color: #fff;
}
.op-card-act.is-primary .op-card-act-ic {
  color: #fff;
}
.op-card-act.is-primary:hover {
  background: #8b4df7;
  color: #fff;
}

@media (max-width: 640px) {
  .op-hero .container {
    padding-bottom: 22px;
  }
  .op-cover {
    height: clamp(104px, 30vw, 150px);
    border-radius: 14px;
  }
  /* Centred card: the tile sits ON the cover, everything below is centred. */
  /* .op-ident.has-cover carries align-items for the desktop overlap, so the
     card view has to match its specificity to re-centre. */
  .op-ident,
  .op-ident.has-cover {
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 0;
  }
  .op-ident.has-cover {
    margin-top: 0;
    padding: 0;
  }
  .op-ident.has-cover .op-logo-wrap {
    margin-top: -42px;
  }
  .op-logo-wrap {
    width: 84px;
    height: 84px;
    border: 3px solid #fff;
    box-shadow: 0 4px 16px rgba(22, 24, 29, 0.16);
  }
  .op-ident-body {
    flex: 1 1 auto;
    width: 100%;
    margin-top: 10px;
  }
  .op-name {
    justify-content: center;
    font-size: 22px;
  }
  .op-kicker,
  .op-spec {
    text-align: center;
  }
  .op-spec {
    margin-left: auto;
    margin-right: auto;
    max-width: 32ch;
  }
  .op-metrics {
    justify-content: center;
  }
  /* Two columns, left-aligned: one fact per line ran the block down half the
     screen, and centred facts with icons never share an edge. This rule used
     to force a single centred column and overrode the grid set above. */
  .op-hero-facts {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px 12px;
    margin-left: 0;
    margin-right: 0;
    justify-items: stretch;
    max-width: none;
    text-align: left;
  }
  .op-fact {
    justify-content: flex-start;
    text-align: left;
    font-size: 12.2px;
    line-height: 1.35;
  }
  /* The socials share the action row on a DESKTOP, where there is room. On a
     phone that row is already three pills wide, so they take their own line.

     `order` ALONE was not enough: it puts the socials after the pills but they
     still wrap wherever they happen to fit, so on a 430px screen Facebook rode
     along at the end of the Email row and Instagram was orphaned underneath.
     The separator is turned into a zero-height, full-width flex item, which
     forces the wrap at a fixed point — every social lands on the line below,
     together. */
  .op-card-acts .op-acts-sep {
    order: 1;
    width: 100%;
    min-height: 0;
    height: 0;
    margin: 0;
    background: none;
  }
  .op-card-acts .op-soc-btn {
    order: 2;
  }
  .op-hero-soc {
    justify-content: center;
  }
  .op-card-acts {
    justify-content: center;
    gap: 7px;
  }
  .op-card-act {
    padding: 10px 14px;
  }
  /* Follow / Contact / Share: full-width taps under the card. */
  .op-actions {
    width: 100%;
    margin-top: 14px;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
  }
  .op-actions .btn {
    width: 100%;
    justify-content: center;
    text-align: center;
  }
  /* Follow and Save contact each take a row of their own: they are the two
     things a visitor came to do, and "Save contact" wraps onto two lines in a
     third-width button. Contact and Share pair up below them. */
  .op-actions .btn:nth-child(1),
  .op-actions .btn:nth-child(2) {
    grid-column: 1 / -1;
  }
  .op-share {
    margin-top: 14px;
  }
  .op-share-chips {
    justify-content: center;
  }
}
/* ── Provider directory grid ────────────────────────────────────────────────
   A provider card is horizontal (avatar beside the copy), so it needs roughly
   twice the width of an event card. Two across on a desktop, one once the
   column can no longer hold two without crushing the copy. Overrides .ev-grid,
   which stays as the portrait-card grid every other browse page uses. */
.pv-grid {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
}
@media (max-width: 1200px) {
  .pv-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 980px) {
  .pv-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 820px) {
  .pv-grid {
    grid-template-columns: 1fr;
  }
}
@media (max-width: 560px) {
  .pv-grid {
    grid-template-columns: 1fr;
    gap: 12px;
  }
}
/* The provider tile is white wherever it is placed, so it carries its own ink
   rather than inheriting the section's. It used to use `color: inherit`, which
   on the homepage's dark section resolved to white and made every provider
   name invisible against the white card. */
.provider-card {
  color: var(--ink);
}
/* The homepage shows THREE providers as a taster row, not the directory's
   paginated two-column grid, so it gets its own track count. Declared AFTER
   the .pv-grid media queries above, which would otherwise win on source order
   at every width they cover. */
.pv-grid-dark,
.pv-grid.pv-grid-dark {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
@media (max-width: 980px) {
  .pv-grid.pv-grid-dark {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 700px) {
  .pv-grid.pv-grid-dark {
    grid-template-columns: 1fr;
  }
}
/* Provider card: one reading order at every width — the pills are their own
   row under the categories, never floated beside the name. */
.provider-head {
  display: block;
}
.provider-copy {
  flex: none;
  min-width: 0;
}
.provider-side {
  justify-content: flex-start;
  margin-top: 9px;
}
/* Profile card: the metrics as a stat strip rather than a wrapping sentence. */
@media (max-width: 640px) {
  .op-metrics {
    display: grid;
    align-items: start;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 12px 4px;
    width: 100%;
    margin: 14px 0 2px;
    padding: 12px 0;
    font-size: 11.5px;
    border-top: 1px solid var(--border);
    border-bottom: 1px solid var(--border);
  }
  .op-metrics li {
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    gap: 1px;
    text-align: center;
    line-height: 1.25;
    min-width: 0;
  }
  /* The dot separators belong to the inline sentence, not to a strip. */
  .op-metrics li:not(:last-child)::after {
    content: none;
  }
  .op-metrics strong {
    font-size: 15px;
  }
  /* The rating is the third cell of the strip, shaped like the other two:
     the score on its own line, the stars and the count under it. The stars
     are five separate spans, so a full-width `strong` is what breaks the
     line — flex-direction cannot, with seven children to place. */
  .op-metrics .op-metric-rating {
    flex-flow: row wrap;
    align-items: center;
    justify-content: center;
    gap: 0 3px;
    padding-top: 0;
  }
  .op-metrics .op-metric-rating strong {
    order: -1;
    flex-basis: 100%;
    text-align: center;
  }
  .op-metrics .op-metric-rating span { font-size: 11px !important; }
  .op-metrics .op-metric-rating a { font-size: 11px; }
}
/* Service checkout — the in-page Fonepay QR. */
.svc-qr-pane {
  margin-top: 16px;
  padding: 16px;
  border: 1px solid var(--border);
  border-radius: 14px;
  text-align: center;
}
.svc-qr-cap {
  margin: 0 0 10px;
  font-size: 12.5px;
  color: var(--gray);
}
.svc-qr-pane img {
  width: 240px;
  height: 240px;
  display: block;
  margin: 0 auto;
  border-radius: 10px;
}
.svc-qr-amt {
  margin: 10px 0 0;
  font-size: 15px;
  font-weight: 800;
}
.svc-qr-banks {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  justify-content: center;
  margin-top: 10px;
}
.svc-qr-bank {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--violet);
  border: 1px solid var(--border);
  border-radius: 100px;
  padding: 6px 12px;
  background: #fff;
}
.svc-qr-status {
  margin: 12px 0 0;
  font-size: 12.5px;
  color: var(--gray);
}

/* ── Service booking confirmation ───────────────────────────────────────────
   A settled booking opens with a plain statement of what happened, then the
   details, then WHO is doing the work and how to reach them. The page used to
   show a status chip over four facts and told the customer "the provider has
   your contact details" without ever giving them the provider's. */
.svc-confirm {
  text-align: center;
  padding: 30px 22px 26px;
  background: linear-gradient(180deg, var(--tint-bg), #fff);
  border-color: var(--violet-pale);
}
.svc-confirm-mark {
  width: 52px;
  height: 52px;
  margin: 0 auto 14px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #15803D;
  background: #DCFCE7;
}
.svc-confirm-h {
  margin: 0 0 8px;
  /* The page-title tier, one step down — this is a panel head, not a page
     title competing with the site header. */
  font-size: clamp(21px, 3vw, 26px);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.2;
}
.svc-confirm-lede {
  margin: 0 auto;
  max-width: 52ch;
  font-size: 15.5px;
  line-height: 1.6;
  color: var(--ink);
}
.svc-confirm-sub {
  margin: 10px auto 0;
  max-width: 52ch;
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--gray);
}
/* What the customer typed at booking, shown back so they can check it. */
.svc-notes {
  font-size: 14px;
  line-height: 1.6;
  color: var(--ink);
  overflow-wrap: anywhere;
}
.svc-prov {
  display: flex;
  gap: 14px;
  align-items: flex-start;
}
.svc-prov-logo {
  width: 56px;
  height: 56px;
  flex: none;
  border-radius: 14px;
  /* CONTAIN — a provider logo is as often a wide wordmark as a square crest,
     and cover crops a wordmark to its middle. */
  object-fit: contain;
  background: #fff;
  border: 1px solid var(--border);
}
.svc-prov-ph {
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: "Bricolage Grotesque", sans-serif;
  font-weight: 800;
  font-size: 22px;
  color: var(--violet);
  background: var(--tint);
}
.svc-prov-body {
  min-width: 0;
  flex: 1 1 auto;
}
.svc-prov-name {
  font-weight: 800;
  font-size: 16px;
  margin-bottom: 10px;
}
.svc-prov-acts {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
/* A phone number and an address are both long; let them wrap rather than
   push the row past the panel. */
.svc-prov-acts .op-card-act {
  min-width: 0;
}
.svc-prov-acts .op-card-act span:last-child {
  overflow-wrap: anywhere;
}
@media (max-width: 560px) {
  .svc-confirm {
    padding: 24px 16px 20px;
  }
  .svc-prov {
    flex-direction: column;
  }
  /* Full-width taps on a phone, the way the profile card does it. */
  .svc-prov-acts {
    flex-direction: column;
    align-items: stretch;
  }
  .svc-prov-acts .op-card-act {
    justify-content: center;
  }
}

/* ── Quick ways into the events list ────────────────────────────────────────
   Chips under the hero search: Today, This week, Free, Online. Every one of
   these filters already existed but only inside a collapsed panel, so the page
   opened with nothing suggesting what to do next. Each carries its real count
   and is only rendered when that count is above zero, so a chip can never
   promise results it has none of. */
.ev-quick {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 14px;
}
.ev-quick-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 13px;
  border-radius: 100px;
  border: 1px solid var(--border);
  background: #fff;
  color: var(--ink);
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  transition: border-color .15s, background .15s, transform .15s;
}
.ev-quick-chip:hover {
  border-color: var(--violet);
  background: var(--tint-bg);
  transform: translateY(-1px);
}
/* The count is supporting detail, not the label — kept quiet and on its own
   tint so it reads as a quantity rather than part of the name. */
.ev-quick-n {
  font-size: 11.5px;
  font-weight: 700;
  color: var(--violet);
  background: var(--tint);
  padding: 1px 7px;
  border-radius: 100px;
  font-variant-numeric: tabular-nums;
}
@media (pointer: coarse) {
  .ev-quick-chip { padding: 10px 15px; }
}
