@import url("/styles/site-shell.css");

/* Self-hosted brand fonts — no external Google Fonts request, so the wordmark
   never flashes a fallback before Gaya loads. Preload both in each page <head>
   (see index/CategoryListingPage/venues) so the fetch starts immediately. */
@font-face {
  font-family: 'Syne Mono';
  src: url('/fonts/SyneMono-Regular.ttf') format('truetype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Gaya Trial';
  src: url('/fonts/gayatrial-regular.otf') format('opentype');
  font-weight: 400;
  font-style: normal;
  /* block (not swap): the logo waits for Gaya rather than painting a fallback
     first and visibly "correcting". Preloaded + same-origin, so the wait is
     imperceptible. Avoids the refresh glitch entirely. */
  font-display: block;
}

/* ═══════════════════════════════════════════════════════════════════
   mulch — UNIVERSAL THEME
   Edit this ONE file to change colours, fonts, and brand across the
   entire site. Every page loads it via <link href="/styles/theme.css">.

   THEMES (set on <html data-theme="…">; no attribute = Ember, the default):
     ember   — warm dark   (brand default)
     peach   — warm light
     indigo  — cool dark (blue-violet)
     mint    — cool light (green)
     plum    — dark purple
     stone   — light monochrome (off-grey)
   Each theme is just TWO colours: a background + an accent (--fg).
   Everything else (secondary text, borders, fills) is derived from those
   via alpha, so a theme stays tiny and the whole site flips for free.

   Primary action buttons use a SINGLE brand accent (--accent / --on-accent)
   that stays constant across every theme, so the main call-to-action is
   always recognisable.
   ═══════════════════════════════════════════════════════════════════ */

:root {
  /* ── Brand ─────────────────────────────────────────────── */
  --brand-name: "mulch";                 /* reference only */
  --logo-font: 'Gaya Trial', 'Gaya', 'Syne Mono', monospace;
  --body-font: 'Syne Mono', monospace;
  --font: var(--body-font);
  --logo-size: 2.50rem;
  --logo-tracking: 0.025em;
  --body-size: 1.125rem;
  --body-weight: 500;
  --body-tracking: 0.012em;
  --body-line: 1.65;
  --body-gap: 1.50rem;
  --heading-weight: 700;

  /* ── Universal CTA accent (constant across all themes) ──── */
  --accent:     #cc3a0a;                 /* primary button fill — burnt orange, stands out on light + dark themes */
  --on-accent:  #fff7f1;                 /* text on accent (AA: 4.7:1) */
  --accent-hover: #b23108;

  /* ── Fixed semantic badges/buttons (constant for legibility) ── */
  --free-blue: #275695;
  --on-free-blue: #fff7f1;
  --highlight-green: #1c7a42;
  --on-highlight-green: #fff7f1;
  --deep-purple: #5b21b6;
  --on-deep-purple: #fff7f1;
  --dark-badge: #1c1c1a;
  --on-dark-badge: #fff7f1;
  /* Door / custom listing badges (Orla, 28 July 2026: one colour per ticket
     type — green = mulch tickets, blue = free, yellow = pay on the door and
     the promoter's own badge).
     28 July, later: this is the BRAND yellow, not a generic one — it is the
     same colour as the wordmark, so it retunes with whichever theme the
     visitor picks (var(--fg) is defined per theme below). */
  --door-yellow: var(--fg);
  --on-door-yellow: var(--bg);

  /* ═════════ EMBER — warm dark (default) ═════════ */
  --bg:      #1e0503;                     /* page background */
  --bg2:     #280c08;                     /* raised surfaces */
  --bg3:     #280c08;                     /* alt surfaces */
  --card:    #180403;                     /* cards / panels */

  --fg:      #ffbb69;                     /* primary text + accent */
  --fg-rgb:  255, 187, 105;               /* accent channels for rgba(var(--fg-rgb), a) */
  --fg2:     rgba(255, 187, 105, 0.78);   /* secondary text */
  --fg3:     rgba(255, 187, 105, 0.66);   /* tertiary text — hints/placeholders only */
  --muted:   rgba(255, 187, 105, 0.82);   /* muted text — AA 4.5:1+ on every surface */

  --border:  rgba(255, 187, 105, 0.15);   /* default borders */
  --border2: rgba(255, 187, 105, 0.08);   /* subtle borders */
  --dim:     rgba(255, 187, 105, 0.08);   /* subtle fills */

  --green:   #4caf6e;
  --red:     #e05555;
  --blue:    #4977b3;
  --amber:   #ffbb69;
  --purple:  #8b5cf6;
  --ok:      #69ffb0;
  --err:     #ff6b6b;

  --pick-bg:  rgba(255, 187, 105, 0.06);
  --draft-bg: rgba(255, 187, 105, 0.025);
}

html,
body {
  font-family: var(--body-font);
  font-size: var(--body-size);
  font-weight: var(--body-weight);
  letter-spacing: var(--body-tracking);
  line-height: var(--body-line);
  /* Set the page background on the root element too, so extra space beyond the
     content (from tall/wide window ratios or overscroll) shows the theme colour
     instead of the browser default — fixes the mismatched "bar" seam. */
  background-color: var(--bg);
}

p { margin-bottom: var(--body-gap); }

h1, h2, h3, h4, h5, h6,
.page-title, .card-title, .ev-title, .event-title, .section-title {
  font-family: var(--body-font);
  font-weight: var(--heading-weight);
}

.site-header__logo,
.site-logo,
.topbar-logo,
.logo,
.wordmark,
#auth-title {
  font-family: var(--logo-font);
  font-size: var(--logo-size);
  font-weight: 400 !important;
  font-optical-sizing: auto;
  letter-spacing: var(--logo-tracking) !important;
  color: var(--fg);
  font-synthesis: none;
}

.topbar-logo sup,
.topbar-logo span,
.wordmark span {
  font-family: var(--body-font);
  font-weight: 400 !important;
  font-synthesis: none;
}

.wordmark-kerned,
.wordmark-kerned span {
  font-family: var(--logo-font) !important;
  font-weight: 400 !important;
  color: inherit !important;
  font-synthesis: none;
  letter-spacing: 0 !important;
}

.wordmark-kerned {
  display: inline-block !important;
  color: inherit;
}

.wordmark-kerned > span {
  display: inline !important;
}

.wordmark-kerned .wordmark-l {
  display: inline-block !important;
  margin-left: 0.04em;
  margin-right: -0.01em;
}

/* Consistent main-header logo size on small screens */
@media (max-width: 560px) {
  .site-header__logo, .site-logo, #auth-title { font-size: 2rem; }
}

/* ── Universal primary CTA buttons ──────────────────────────
   Any button tagged .btn-solid / .btn-submit / .btn-cta (the main filled
   call-to-action) uses the constant brand accent on every theme. */
.btn-solid,
.btn-submit,
.btn-cta {
  background: var(--accent) !important;
  color: var(--on-accent) !important;
  border-color: var(--accent) !important;
}
.btn-solid:hover:not(:disabled),
.btn-submit:hover:not(:disabled),
.btn-cta:hover:not(:disabled) {
  background: var(--accent-hover) !important;
  border-color: var(--accent-hover) !important;
}

.btn-green,
.green-btn,
.status-btn.live.active,
.sale-btn.on.active {
  background: var(--highlight-green) !important;
  color: var(--on-highlight-green) !important;
  border-color: var(--highlight-green) !important;
}

.btn-blue,
.blue-btn,
.alt-btn,
.status-btn.offline.active {
  background: var(--free-blue) !important;
  color: var(--on-free-blue) !important;
  border-color: var(--free-blue) !important;
}

.btn-purple,
.purple-btn,
.status-btn.private.active {
  background: var(--deep-purple) !important;
  color: var(--on-deep-purple) !important;
  border-color: var(--deep-purple) !important;
}

/* ── Popup multi-select (initMultiSelect) — used for "Other categories" ──
   The toggle reuses each form's own .finput look; only the popup + options
   are styled here so it matches the native-feeling primary <select>. */
.ms { position: relative; }
.ms-toggle { display: flex; align-items: center; justify-content: space-between; gap: .5rem; cursor: pointer; text-align: left; }
.category-fields {
  display: grid;
  gap: 1rem;
  margin: .35rem 0 .8rem;
  padding: 1rem;
  border: 1px solid var(--border);
  background: rgba(var(--fg-rgb), .025);
}
.category-fields .field + .field {
  padding-top: 1rem;
  border-top: 1px solid var(--border);
}
.category-field-help {
  margin: 0 0 .35rem;
  color: var(--muted);
  font-size: 0.75rem;
  line-height: 1.55;
}
.unsaved-overlay {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: grid;
  place-items: center;
  padding: 1rem;
  background: rgba(0, 0, 0, .72);
}
.unsaved-overlay[hidden] { display: none; }
.unsaved-dialog {
  width: min(100%, 460px);
  padding: 1.25rem;
  border: 1px solid var(--fg);
  background: var(--bg);
  color: var(--fg);
  box-shadow: 0 18px 60px rgba(0, 0, 0, .45);
}
.unsaved-title {
  margin: 0 0 .45rem;
  font-size: 1rem;
  font-weight: bold;
  text-transform: uppercase;
}
.unsaved-copy { margin: 0; color: var(--muted); font-size: .78rem; line-height: 1.55; }
.unsaved-actions { display: flex; gap: .65rem; flex-wrap: wrap; margin-top: 1rem; }

/* Compact operational switches shared by promoter and admin event management. */
.event-visibility-bar {
  margin: 0 0 1.25rem;
  padding: 1rem;
  border: 1px solid var(--border);
  background: rgba(var(--fg-rgb), .025);
}
.operational-label {
  margin: 0 0 .55rem;
  color: var(--muted);
  font-size: 0.75rem;
  font-weight: bold;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.segmented-control {
  display: inline-grid;
  gap: 0;
  max-width: 100%;
  padding: 3px;
  border: 1px solid var(--border);
  background: rgba(var(--fg-rgb), .035);
  border-radius: 0;
  overflow: hidden;
  transition: border-color .18s ease, background .18s ease;
}
.status-btns.segmented-control {
  display: inline-grid;
  grid-template-columns: repeat(3, max-content);
  width: max-content;
  max-width: 100%;
  gap: 0;
  margin: 0;
}
.sale-toggle.segmented-control {
  display: inline-grid;
  grid-template-columns: repeat(2, max-content);
  width: max-content;
  max-width: 100%;
  gap: 0;
  margin: 0;
}
.status-btns[data-state="live"],
.sale-toggle[data-state="on"] {
  border-color: rgba(76, 175, 110, .65);
  background: rgba(76, 175, 110, .12);
}
.status-btns[data-state="offline"] {
  border-color: rgba(73, 119, 179, .65);
  background: rgba(73, 119, 179, .12);
}
.status-btns[data-state="private"] {
  border-color: rgba(139, 92, 246, .65);
  background: rgba(139, 92, 246, .12);
}
.sale-toggle[data-state="off"] {
  border-color: rgba(224, 85, 85, .65);
  background: rgba(224, 85, 85, .12);
}
.segmented-control .status-btn,
.segmented-control .sale-btn {
  min-width: 0;
  margin: 0;
  border: 0;
  border-radius: 0;
  text-align: center;
  transition: color .18s ease, background .18s ease;
}
.segmented-control .active {
  box-shadow: none;
  transform: none;
}
.segmented-control .status-btn:not(.active):hover,
.segmented-control .status-btn:not(.active):focus-visible,
.segmented-control .sale-btn:not(.active):hover,
.segmented-control .sale-btn:not(.active):focus-visible {
  background: rgba(var(--fg-rgb), .1);
  outline: none;
}
.segmented-control .status-btn + .status-btn,
.segmented-control .sale-btn + .sale-btn {
  border-left: 1px solid rgba(var(--fg-rgb), .13);
}
@media (max-width: 420px) {
  .status-btns.segmented-control,
  .sale-toggle.segmented-control {
    width: 100%;
  }
  .status-btns.segmented-control { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .sale-toggle.segmented-control { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .segmented-control .status-btn,
  .segmented-control .sale-btn { padding-inline: .55rem; }
}
.operational-save-row {
  display: flex;
  align-items: center;
  gap: .75rem;
  flex-wrap: wrap;
  margin-top: .75rem;
}
.operational-confirmation { color: var(--green); font-size: 0.75rem; font-weight: bold; }
.ticket-sales-control { margin: 0 0 1rem; padding-bottom: 1rem; border-bottom: 1px solid var(--border); }

/* 12-hour event time picker — paired with public/event-time-picker.js. The
   native <input type="time"> stays in the DOM holding a 24-hour HH:MM value
   (everything downstream reads it); it is hidden and replaced by hour /
   minute / AM-PM controls so nobody has to guess which clock is meant. */
.event-time-picker { display: flex; align-items: stretch; gap: .4rem; width: 100%; }
.event-time-picker__native { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; margin: -1px; }
.event-time-picker__part { flex: 1 1 auto; min-width: 0; text-align: center; letter-spacing: .04em; }
/* Typed, not picked (28 July 2026) — no spinner arrows on any browser. */
.event-time-picker__part::-webkit-outer-spin-button,
.event-time-picker__part::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.event-time-picker__mer { display: grid; grid-template-columns: repeat(2, 1fr); border: 1px solid var(--border); flex: 0 0 auto; }
.event-time-picker__mer-btn { font-family: var(--body-font); font-size: .82rem; font-weight: bold; letter-spacing: .05em; padding: 0 .85rem; background: transparent; color: var(--fg2); border: none; cursor: pointer; transition: background .15s, color .15s; }
.event-time-picker__mer-btn.is-on { background: var(--fg); color: var(--bg); }

/* Branded date picker used by every promoter/admin event form. The original
   date input remains the source of truth, so existing validation and save
   logic continue to read exactly the same YYYY-MM-DD value. */
.event-date-picker { position: relative; width: 100%; }
.event-date-picker > input.finput[type="date"] {
  cursor: pointer;
  padding-right: 2.6rem;
}
.event-date-picker > input.finput[type="date"]::-webkit-calendar-picker-indicator {
  opacity: 0;
  pointer-events: none;
}
.event-date-picker__icon {
  position: absolute;
  right: .9rem;
  top: 50%;
  transform: translateY(-50%);
  color: var(--fg2);
  pointer-events: none;
  font-size: .9rem;
}
.event-date-picker__panel {
  position: absolute;
  z-index: 180;
  top: calc(100% + .35rem);
  left: 0;
  width: 19rem;
  max-width: calc(100vw - 32px);
  padding: .7rem;
  color: var(--fg);
  background: var(--bg2);
  border: 1px solid var(--border);
  box-shadow: 0 12px 32px rgba(0,0,0,.4);
}
.event-date-picker__panel[hidden] { display: none; }
.event-date-picker__head { display: flex; align-items: center; justify-content: space-between; margin-bottom: .5rem; }
.event-date-picker__title { font-size: .78rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; }
.event-date-picker__nav {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  color: var(--fg2);
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 0;
  font: inherit;
  font-size: 1.1rem;
  cursor: pointer;
}
.event-date-picker__nav:hover,
.event-date-picker__nav:focus-visible { color: var(--fg); background: var(--dim); border-color: var(--fg2); outline: none; }
.event-date-picker__dow,
.event-date-picker__grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 3px; }
.event-date-picker__dow span { padding: .2rem 0; color: var(--fg3); font-size: 0.68rem; font-weight: 700; text-align: center; text-transform: uppercase; }
.event-date-picker__day {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 2.1rem;
  aspect-ratio: 1;
  padding: 0;
  color: var(--fg2);
  background: var(--dim);
  border: 1px solid transparent;
  border-radius: 0;
  font: inherit;
  font-size: .8rem;
  cursor: pointer;
  appearance: none;
}
.event-date-picker__day:hover,
.event-date-picker__day:focus-visible { color: var(--fg); background: rgba(var(--fg-rgb), .18); outline: none; }
.event-date-picker__day.is-today { color: var(--fg); border-color: var(--border); }
.event-date-picker__day.is-selected { color: var(--bg); background: var(--fg); border-color: var(--fg); font-weight: 700; }
.event-date-picker__day.is-empty,
.event-date-picker__day.is-empty:hover { background: transparent; cursor: default; }
.event-date-picker__foot { display: flex; justify-content: flex-end; margin-top: .5rem; }
.event-date-picker__clear { padding: .35rem; color: var(--fg3); background: transparent; border: 0; font: inherit; font-size: 0.72rem; font-weight: 700; text-transform: uppercase; cursor: pointer; }
.event-date-picker__clear:hover { color: var(--fg); }
@media (max-width: 360px) {
  .event-date-picker__panel { width: calc(100vw - 24px); max-width: calc(100vw - 24px); padding: .55rem; }
  .event-date-picker__day { min-height: 1.9rem; font-size: .76rem; }
}

.ms-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ms-label.ms-placeholder { color: var(--muted); }
.ms-caret { color: var(--muted); flex: 0 0 auto; font-size: .8em; }
.ms-panel { position: absolute; left: 0; right: 0; top: calc(100% + 3px); z-index: 60; background: var(--bg); border: 1px solid var(--fg); max-height: 260px; overflow-y: auto; box-shadow: 0 8px 24px rgba(0,0,0,.35); }
.ms-opt { display: flex; align-items: center; gap: .6rem; padding: .55rem .75rem; font-size: .9rem; cursor: pointer; border-bottom: 1px solid var(--border2); }
.ms-opt:last-child { border-bottom: none; }
.ms-opt:hover { background: rgba(var(--fg-rgb), .08); }
.ms-opt input { width: 16px; height: 16px; accent-color: var(--accent); flex: 0 0 auto; }
.ms-opt.ms-disabled { opacity: .4; cursor: not-allowed; }
.ms-empty { padding: .6rem .75rem; color: var(--muted); font-size: .8rem; }

/* ═══════════════════════════════════════════════════════════════════
   THEME VARIANTS — only the variables change.
   ═══════════════════════════════════════════════════════════════════ */

/* ───────── PEACH — warm light (saturated) ───────── */
:root[data-theme="peach"] {
  --bg:      #ffc187;
  --bg2:     #ffce9f;
  --bg3:     #ffce9f;
  --card:    #ffd7af;

  --fg:      #2a0a00;
  --fg-rgb:  42, 10, 0;
  --fg2:     rgba(42, 10, 0, 0.82);
  --fg3:     rgba(42, 10, 0, 0.68);
  --muted:   rgba(42, 10, 0, 0.84);

  --border:  rgba(42, 10, 0, 0.26);
  --border2: rgba(42, 10, 0, 0.14);
  --dim:     rgba(42, 10, 0, 0.06);

  --green:   #1c7a42;
  --red:     #a82d1c;
  --blue:    #275695;
  --amber:   #8a4b00;
  --purple:  #5b21b6;
  --ok:      #1c7a42;
  --err:     #a82d1c;

  --pick-bg:  rgba(42, 10, 0, 0.07);
  --draft-bg: rgba(42, 10, 0, 0.03);
}

/* ───────── INDIGO — cool dark (blue-violet) ───────── */
:root[data-theme="indigo"] {
  --bg:      #16142e;
  --bg2:     #1f1c3f;
  --bg3:     #1f1c3f;
  --card:    #121029;

  --fg:      #b9b4ff;
  --fg-rgb:  185, 180, 255;
  --fg2:     rgba(185, 180, 255, 0.78);
  --fg3:     rgba(185, 180, 255, 0.68);
  --muted:   rgba(185, 180, 255, 0.86);

  --border:  rgba(185, 180, 255, 0.16);
  --border2: rgba(185, 180, 255, 0.08);
  --dim:     rgba(185, 180, 255, 0.08);

  --green:   #5fd99a;
  --red:     #ff7a7a;
  --blue:    #8ea2ff;
  --amber:   #ffce6b;
  --purple:  #c9b6ff;
  --ok:      #7dffc0;
  --err:     #ff8a8a;

  --pick-bg:  rgba(185, 180, 255, 0.07);
  --draft-bg: rgba(185, 180, 255, 0.03);
}

/* ───────── MINT — cool light (green) ───────── */
:root[data-theme="mint"] {
  --bg:      #b3efce;
  --bg2:     #c5f4dc;
  --bg3:     #c5f4dc;
  --card:    #d4f8e7;

  --fg:      #083022;
  --fg-rgb:  8, 48, 34;
  --fg2:     rgba(8, 48, 34, 0.82);
  --fg3:     rgba(8, 48, 34, 0.68);
  --muted:   rgba(8, 48, 34, 0.86);

  --border:  rgba(8, 48, 34, 0.24);
  --border2: rgba(8, 48, 34, 0.13);
  --dim:     rgba(8, 48, 34, 0.06);

  --green:   #0c7a45;
  --red:     #a82d1c;
  --blue:    #1f5a8f;
  --amber:   #7a5200;
  --purple:  #5b21b6;
  --ok:      #0c7a45;
  --err:     #a82d1c;

  --pick-bg:  rgba(8, 48, 34, 0.07);
  --draft-bg: rgba(8, 48, 34, 0.03);
}

/* ───────── PLUM — dark purple ───────── */
:root[data-theme="plum"] {
  --bg:      #221033;
  --bg2:     #2c1641;
  --bg3:     #2c1641;
  --card:    #1a0c28;

  --fg:      #e8b8ff;
  --fg-rgb:  232, 184, 255;
  --fg2:     rgba(232, 184, 255, 0.78);
  --fg3:     rgba(232, 184, 255, 0.68);
  --muted:   rgba(232, 184, 255, 0.82);

  --border:  rgba(232, 184, 255, 0.16);
  --border2: rgba(232, 184, 255, 0.08);
  --dim:     rgba(232, 184, 255, 0.08);

  --green:   #5fd99a;
  --red:     #ff7a9a;
  --blue:    #9aa8ff;
  --amber:   #ffce6b;
  --purple:  #e8b8ff;
  --ok:      #7dffc0;
  --err:     #ff8aa8;

  --pick-bg:  rgba(232, 184, 255, 0.07);
  --draft-bg: rgba(232, 184, 255, 0.03);
}

/* ───────── STONE — soft monochrome light (off-grey, never pure white) ───────── */
:root[data-theme="stone"] {
  --bg:      #e8e8e5;
  --bg2:     #f0f0ed;
  --bg3:     #f0f0ed;
  --card:    #f2f2ef;

  --fg:      #1c1c1a;
  --fg-rgb:  28, 28, 26;
  --fg2:     rgba(28, 28, 26, 0.82);
  --fg3:     rgba(28, 28, 26, 0.68);
  --muted:   rgba(28, 28, 26, 0.84);

  --border:  rgba(28, 28, 26, 0.22);
  --border2: rgba(28, 28, 26, 0.12);
  --dim:     rgba(28, 28, 26, 0.06);

  --green:   #1c7a42;
  --red:     #a82d1c;
  --blue:    #275695;
  --amber:   #6a5200;
  --purple:  #5b21b6;
  --ok:      #1c7a42;
  --err:     #a82d1c;

  --pick-bg:  rgba(28, 28, 26, 0.06);
  --draft-bg: rgba(28, 28, 26, 0.03);
}

/* Wordmark colour follows the theme accent on every theme. */
:root[data-theme] .site-header__logo,
:root[data-theme] .site-logo,
:root[data-theme] .topbar-logo,
:root[data-theme] .logo,
:root[data-theme] #auth-title { color: var(--fg); }

/* ═══════════════════════════════════════════════════════════════════
   THEME PICKER  (injected by /theme-toggle.js)
   - Small round swatch button, fixed bottom-right.
   - Homepage: floats over the hero, auto-dims after 10s (stays clickable).
   - All other pages: always fully visible (sits at footer bottom-right).
   ═══════════════════════════════════════════════════════════════════ */
.theme-fab {
  position: fixed;
  bottom: 1.25rem;
  right: 1.25rem;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  margin: 0;
  background: var(--card);
  color: var(--fg);
  border: 1px solid var(--border);
  cursor: pointer;
  z-index: 9999;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.25);
  transition: opacity .35s ease, transform .2s ease, background .15s, color .15s, border-color .15s;
  -webkit-tap-highlight-color: transparent;
}
.theme-fab:hover { transform: scale(1.06); border-color: var(--fg); opacity: 1 !important; }
.theme-fab:active { transform: scale(0.96); }
.theme-fab svg { width: 20px; height: 20px; display: block; }
/* Homepage auto-dim: faded + smaller, but still reachable */
.theme-fab.is-dimmed { opacity: 0.32; transform: scale(0.82); }
.theme-fab.is-dimmed:hover,
.theme-fab.is-dimmed:focus-visible { opacity: 1; transform: scale(1); }
@media print { .theme-fab { display: none; } }

@media (max-width: 600px) {
  .theme-fab { width: 38px; height: 38px; bottom: 0.85rem; right: 0.85rem; }
  .theme-fab svg { width: 17px; height: 17px; }
}

/* Backdrop + popup */
.theme-pop-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  z-index: 10000;
  opacity: 0;
  pointer-events: none;
  transition: opacity .18s ease;
}
.theme-pop-backdrop.open { opacity: 1; pointer-events: auto; }

.theme-pop {
  position: fixed;
  bottom: 4.75rem;
  right: 1.25rem;
  width: min(340px, calc(100vw - 2rem));
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 1rem;
  z-index: 10001;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.45);
  transform: translateY(8px) scale(0.98);
  opacity: 0;
  pointer-events: none;
  transition: opacity .18s ease, transform .18s ease;
}
.theme-pop.open { opacity: 1; transform: translateY(0) scale(1); pointer-events: auto; }
@media (max-width: 600px) {
  .theme-pop { bottom: 4rem; left: 0.85rem; right: 0.85rem; width: auto; }
}

.theme-pop__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.85rem;
}
.theme-pop__title {
  font-family: var(--body-font);
  font-size: 0.95rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--fg);
}
.theme-pop__close {
  background: none;
  border: 1px solid var(--border);
  color: var(--fg);
  width: 30px; height: 30px;
  border-radius: 8px;
  cursor: pointer;
  font-size: 1rem;
  line-height: 1;
  display: flex; align-items: center; justify-content: center;
  transition: border-color .15s, background .15s;
}
.theme-pop__close:hover { border-color: var(--fg); background: var(--dim); }

.theme-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.55rem;
}
.theme-swatch {
  position: relative;
  border: 1.5px solid transparent;
  border-radius: 10px;
  padding: 0.85rem 0.6rem 0.65rem;
  cursor: pointer;
  text-align: center;
  overflow: hidden;
  transition: transform .12s ease, box-shadow .12s ease;
  font-family: var(--body-font);
}
.theme-swatch:hover { transform: translateY(-1px); }
.theme-swatch__mark {
  font-family: var(--logo-font);
  font-size: 1.5rem;
  line-height: 1;
  margin-bottom: 0.3rem;
  display: block;
}
.theme-swatch__name {
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  display: block;
}
.theme-swatch.is-active { border-color: #4f7cff; box-shadow: 0 0 0 1px #4f7cff; }
.theme-swatch__dot {
  position: absolute;
  top: 6px; right: 6px;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: #4f7cff;
  display: none;
}
.theme-swatch.is-active .theme-swatch__dot { display: block; }

/* ── iOS: stop the page zooming in when you tap a field ─────────────────────
   Safari on iPhone auto-zooms whenever you focus a form control whose text is
   smaller than 16px, and it does NOT zoom back out afterwards — that is the
   "everything got slightly bigger and the margins vanished" effect. Most of
   our inputs are set around 0.8-0.9rem (13-14px), which triggers it.

   The only reliable fix is to make the text 16px on small screens. The old viewport-tag trick that
   locks the maximum zoom scale is deliberately NOT used: modern iOS ignores
   it, and it would break pinch-zoom for anyone who needs it. Checkboxes, radios and range sliders have no text so they are exempt.

   This is global on purpose — every page loads theme.css, so form controls
   behave the same everywhere. `!important` is needed (and is the one place we
   want it): the per-page styles set font-size on classes like .filter-input
   and .finput, which would otherwise outrank a plain element selector. It is
   scoped to phone widths only, so desktop styling is untouched. */
@media (max-width: 767px) {
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="hidden"]),
  select,
  textarea {
    font-size: 16px !important;
  }
}

/* ── Checkboxes: one themed style for the whole site ────────────────────────
   Previously every page rolled its own. Some were left as plain white browser
   boxes (checkout, account creation); the themed ones drew their tick with a
   text character nudged by hard-coded pixel offsets, so it landed small and
   off-centre and could spill past the border.

   This replaces all of that with a single accessible pattern:
     * the box is sized in em, so it scales with its label text;
     * `display: grid` + `place-content: center` centres the tick exactly,
       with no magic offsets to drift;
     * the tick is a clip-path shape, not a font glyph, so it is crisp at any
       size and identical in every browser and font;
     * colours come from the theme, so it follows ember/peach/indigo/etc.

   Opt out on a one-off control with class="native-check" if a page ever needs
   the browser default back. */
input[type="checkbox"]:not(.native-check) {
  appearance: none;
  -webkit-appearance: none;
  display: grid;
  place-content: center;
  flex-shrink: 0;
  width: 1.15em;
  height: 1.15em;
  margin: 0;
  padding: 0;
  border: 1px solid var(--fg);
  border-radius: 0;
  background: transparent;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}

/* The themed display must not override the HTML hidden contract. Some forms
   keep a checkbox as state behind branded On/Off buttons. */
input[type="checkbox"][hidden] {
  display: none !important;
}

input[type="checkbox"]:not(.native-check)::after {
  content: "";
  width: 0.66em;
  height: 0.66em;
  background: var(--bg);
  /* A checkmark, drawn geometrically. Sits fully inside the border. */
  clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
  transform: scale(0);
  transition: transform 0.12s ease-in-out;
}

input[type="checkbox"]:not(.native-check):checked {
  background: var(--fg);
  border-color: var(--fg);
}
input[type="checkbox"]:not(.native-check):checked::after { transform: scale(1); }

input[type="checkbox"]:not(.native-check):focus-visible {
  outline: 2px solid var(--fg2);
  outline-offset: 2px;
}
input[type="checkbox"]:not(.native-check):disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

/* ── Date and time fields: stop them overflowing the screen ────────────────
   iOS Safari gives input[type=date] and input[type=time] an intrinsic minimum
   width based on the widest date the locale can render. `width:100%` cannot
   shrink an element below its intrinsic minimum, so on a narrow phone these
   two field types pushed past the right edge of the page. The page then became
   horizontally scrollable, and focusing a field made Safari pan sideways —
   which reads as "the page zoomed and lost its margin".

   min-width:0 lets them honour their container. -webkit-appearance:none drops
   the native chrome that carries that intrinsic size, while still opening the
   normal native picker on tap. */
input[type="date"],
input[type="time"],
input[type="datetime-local"],
input[type="month"] {
  min-width: 0;
  max-width: 100%;
  -webkit-appearance: none;
  appearance: none;
}

/* Belt and braces: nothing on a form page should be able to scroll the body
   sideways. If a future field misbehaves it gets clipped rather than breaking
   the whole page layout. */
html { overflow-x: hidden; }

/* ── Collapsible form sections (see public/form-sections.js) ───────────────
   Shared by the promoter create/manage event pages and both admin ones, so
   all four look and behave the same. The engine wraps each .fsect heading and
   its fields into .fsec > .fsec-toggle + .fsec-body. */
.fsec {
  border: 1px solid var(--border);
  margin-bottom: 0.6rem;
  background: rgba(var(--fg-rgb), 0.015);
  scroll-margin-top: 6.25rem;
}
/* Brand-guide semantic colours, used only as faint navigation tints. The
   first and final panels intentionally keep the active theme's native surface. */
.fsec-tone-2 { --fsec-tone-rgb: 39, 86, 149; }   /* Free / info blue */
.fsec-tone-3 { --fsec-tone-rgb: 28, 122, 66; }   /* Mulch highlight green */
.fsec-tone-4 { --fsec-tone-rgb: 204, 58, 10; }   /* CTA burnt orange */
.fsec-tone-5 { --fsec-tone-rgb: 91, 33, 182; }   /* Deep purple */
.fsec[class*="fsec-tone-"] {
  border-color: rgba(var(--fsec-tone-rgb), 0.46);
  background: rgba(var(--fsec-tone-rgb), 0.055);
}
.fsec[class*="fsec-tone-"] .fsec-toggle {
  background: rgba(var(--fsec-tone-rgb), 0.11);
}
.fsec[class*="fsec-tone-"] .fsec-body {
  border-top-color: rgba(var(--fsec-tone-rgb), 0.34);
}
.fsec[class*="fsec-tone-"] :is(.type-card, .info-strip, .approval-opt, .approval-locked, .tier-empty) {
  background: rgba(var(--fsec-tone-rgb), 0.07);
  border-color: rgba(var(--fsec-tone-rgb), 0.34);
}

/* Subheadings within one of the six sections. `.fsect` is reserved for the
   actual accordion boundaries and must never be used for these. */
.form-subsection {
  margin: 1.5rem 0 0.75rem;
  padding-bottom: 0.55rem;
  border-bottom: 1px solid var(--border);
}
.form-subsection:first-child { margin-top: 0; }
.form-subsection-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
}
.form-subsection-title {
  margin: 0;
  color: var(--fg);
  font-size: 0.86rem;
  font-weight: bold;
  letter-spacing: 0.075em;
  line-height: 1.3;
  text-transform: uppercase;
}
.form-subsection-copy {
  display: block;
  margin-top: 0.3rem;
  color: var(--muted);
  font-size: 0.75rem;
  font-weight: normal;
  letter-spacing: 0;
  line-height: 1.5;
  text-transform: none;
}
.form-subsection-actions {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
}
.form-subsection-actions.sale-toggle { margin: 0; }
.discount-ticket-wrap { margin-top: 1.5rem; }

/* Ticket type cards are shared by promoter/admin create and manage forms.
   The selected card must read instantly, not rely on a one-pixel border. */
.fsec .type-cards {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
}
/* One option per row. A vertical list scans faster than a 2x2 grid, keeps
   every description on the same measure, and leaves room to add ticket types
   without reflowing the block. */
.fsec .type-card {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: start;
  column-gap: 0.8rem;
  row-gap: 0.2rem;
  min-width: 0;
  padding: 0.85rem 7.2rem 0.85rem 1rem;
  border: 1px solid rgba(var(--fg-rgb), 0.34);
  background: rgba(var(--fg-rgb), 0.025);
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s, box-shadow 0.15s, transform 0.15s;
}
.fsec .type-card:has(input:not(:disabled)):hover {
  border-color: rgba(var(--fg-rgb), 0.78);
  background: rgba(var(--fg-rgb), 0.1);
  transform: translateY(-1px);
}
.fsec .type-card:has(input:focus-visible) {
  outline: 2px solid var(--fg);
  outline-offset: 3px;
}
.fsec .type-card:has(input:checked) {
  border-color: var(--fg);
  background: rgba(var(--fg-rgb), 0.16);
  box-shadow: inset 0 0 0 2px var(--fg);
}
.fsec .type-card:has(input:checked)::after {
  content: "Selected ✓";
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  right: 0.7rem;
  padding: 0.18rem 0.38rem;
  color: var(--bg);
  background: var(--fg);
  font-size: 0.75rem;
  font-weight: bold;
  letter-spacing: 0.04em;
  line-height: 1.2;
  text-transform: uppercase;
}
.fsec .type-card input[type="radio"] {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
.fsec .type-card-emoji {
  grid-column: 1;
  grid-row: 1 / span 2;
  align-self: center;
  font-size: 1.25rem;
  line-height: 1;
}
.fsec .type-card-label {
  grid-column: 2;
  color: var(--fg);
  font-size: 0.86rem;
  font-weight: bold;
}
.fsec .type-card-desc {
  grid-column: 2;
  color: var(--muted);
  font-size: 0.8rem;
  line-height: 1.5;
}
.fsec .type-cards.is-readonly .type-card:not(:has(input:checked)) { opacity: 0.4; }
.fsec .type-cards.is-readonly .type-card { cursor: default; transform: none; }
.ticket-type-source {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  margin: -1px !important;
  padding: 0 !important;
  overflow: hidden !important;
  clip: rect(0 0 0 0) !important;
  clip-path: inset(50%) !important;
  border: 0 !important;
  white-space: nowrap !important;
}

.fsec-toggle {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: 100%;
  padding: 1.15rem 1rem;
  font-family: inherit;
  font-size: 0.95rem;
  font-weight: bold;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  text-align: left;
  color: var(--fg);
  background: transparent;
  border: 0;
  cursor: pointer;
  transition: background 0.15s;
}
.fsec-toggle:hover:not(:disabled) { background: rgba(var(--fg-rgb), 0.05); }
/* First and last sections can't collapse, so they must not look clickable. */
.fsec-toggle:disabled { cursor: default; opacity: 1; }
.fsec.is-locked .fsec-chev { display: none; }

.fsec-title { flex: 1; min-width: 0; }
/* The small grey explainer under some headings keeps its own look. */
.fsec-title .fsect-sub {
  display: block;
  margin-top: 0.3rem;
  font-size: 0.8rem;
  font-weight: normal;
  text-transform: none;
  letter-spacing: 0;
  line-height: 1.5;
  color: var(--muted);
}

/* x/y progress chip. Amber while there's something left, green when done —
   so a glance down the form shows exactly where the gaps are. */
.fsec-count {
  flex: 0 0 auto;
  font-size: 0.75rem;
  font-weight: bold;
  letter-spacing: 0.04em;
  padding: 0.2rem 0.45rem;
  border: 1px solid var(--border);
  color: var(--muted);
  white-space: nowrap;
}
.fsec.is-incomplete .fsec-count { color: var(--fg); border-color: rgba(var(--fg-rgb), 0.45); }
.fsec.is-complete .fsec-count {
  color: var(--on-highlight-green);
  background: var(--highlight-green);
  border-color: var(--highlight-green);
}

.fsec-chev {
  flex: 0 0 auto;
  font-size: 0.75rem;
  line-height: 1;
  transition: transform 0.2s;
}
.fsec[aria-expanded] .fsec-chev { transform: none; }
.fsec.is-open .fsec-chev { transform: rotate(180deg); }

.fsec-body {
  padding: 1.15rem 1rem 1rem;
  border-top: 1px solid var(--border);
}
.fsec:not(.is-open) .fsec-body { display: none; }

.fsec-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-top: 1.25rem;
  padding-top: 1rem;
  border-top: 1px solid var(--border);
}
.fsec-nav.has-next-only { justify-content: flex-end; }
.fsec-nav.has-back-only { justify-content: flex-start; }

/* Running total beside the submit button. */
.form-progress {
  font-size: 0.75rem;
  font-weight: bold;
  letter-spacing: 0.04em;
  color: var(--muted);
  white-space: nowrap;
}
.form-progress.is-complete { color: var(--green); }
.req-star { color: var(--fg); font-weight: bold; }
.section-progress-value {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  border: 0;
  opacity: 0;
  pointer-events: none;
}
.tier-empty {
  margin: 0;
  padding: 0.9rem 1rem;
  border: 1px solid var(--border);
  color: var(--muted);
  font-size: 0.76rem;
  line-height: 1.55;
}
/* The final decision section is important copy, not fine print. */
.fsec.is-final .fsect-sub,
.fsec.is-final .aopt-desc,
.fsec.is-final .approval-locked {
  font-size: 0.8rem;
  line-height: 1.55;
}

@media (max-width: 700px) {
  .fsec-toggle { padding: 1rem 0.8rem; font-size: 0.86rem; letter-spacing: 0.06em; gap: 0.5rem; }
  .fsec-body { padding: 1rem 0.8rem 0.9rem; }
  .form-subsection-head { flex-direction: column; gap: 0.7rem; }
  /* Narrow screens: drop the reserved badge gutter and let the badge sit at
     the top-right corner so long labels are not squeezed. */
  .fsec .type-card { padding: 0.85rem 0.85rem 0.85rem 0.8rem; }
  .fsec .type-card-label { padding-right: 5rem; }
  .fsec .type-card:has(input:checked)::after { top: 0.75rem; transform: none; }
}

/* ═══════════════════════════════════════════════════════════════════
   ACCESSIBILITY — site-wide rules (added 2026-07-28 after Luka's audit)

   These live here, in the one file every page loads, so the behaviour is
   identical on every page instead of being re-invented per page.
   ═══════════════════════════════════════════════════════════════════ */

/* ── Keyboard focus ring ────────────────────────────────────────────
   People who navigate with Tab need to see where they are. Dozens of
   page-level styles set `outline: none` on inputs and buttons (to hide the
   browser default), which left keyboard users with nothing to follow. This is
   the single focus style for the whole site, and it is deliberately
   `!important` so those older per-page rules cannot switch it back off.

   Nothing changes for mouse users: `:focus-visible` only fires when the
   browser decides a visible indicator is warranted (keyboard, not a click). */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
details:focus-visible,
label:focus-visible,
[tabindex]:focus-visible,
[role="button"]:focus-visible,
[role="tab"]:focus-visible,
[contenteditable]:focus-visible {
  /* 28 July 2026: halved from 3px — still clearly visible, far less shouty
     on a form full of fields. */
  outline: 1.5px solid var(--fg) !important;
  outline-offset: 2px !important;
}

/* Controls that sit inside a clipped container would have the ring cut off,
   so those draw it just inside their own edge instead. */
.segmented-control .status-btn:focus-visible,
.segmented-control .sale-btn:focus-visible,
.card-image-wrapper a:focus-visible {
  outline-offset: -3px !important;
}

/* ── Links: underlined on hover and keyboard focus ──────────────────
   An underline is the standard "this is a link" signal. We show it on hover
   and on keyboard focus rather than permanently, so listings stay clean but
   the link is still discoverable. */
a:hover,
a:focus-visible {
  text-decoration: underline !important;
  text-underline-offset: 0.18em;
  text-decoration-thickness: 1px;
}

/* …except anything that already reads as a button, card, chip, tab, nav item
   or the wordmark — an underline on those looks like a rendering fault. */
:is(
  a[class*="card"],
  a[class*="btn"],
  a[class*="cta"],
  a[class*="pill"],
  a[class*="badge"],
  a[class*="tag"],
  a[class*="chip"],
  a[class*="tab"],
  a[class*="logo"],
  a[class*="wordmark"],
  a[role="button"],
  a[role="menuitem"],
  .public-nav-dropdown a,
  .nav-dropdown a,
  .site-menu__links a,
  .public-site-header a,
  .theme-swatch
):is(:hover, :focus-visible) {
  text-decoration: none !important;
}

/* ── Show / hide password toggle (see public/password-reveal.js) ────────────
   The script wraps each password input in .pw-reveal and moves the input's
   vertical margins onto the wrapper, so the button centres on the box itself. */
.pw-reveal { position: relative; display: block; }
.pw-reveal-btn {
  position: absolute;
  top: 50%;
  right: 0.5rem;
  transform: translateY(-50%);
  background: transparent;
  border: 0;
  color: var(--fg2);
  font-family: inherit;
  font-size: 0.75rem;
  font-weight: bold;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 0.4rem 0.45rem;
  cursor: pointer;
  line-height: 1;
}
.pw-reveal-btn:hover { color: var(--fg); }

/* ── Shared list pager (public/paginate-list.js) ──
   Used by the account and promoter dashboards, 30 July 2026. Lives here rather
   than in either page so both stay identical and a third caller inherits it. */
.list-pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  margin: 1rem 0 .25rem;
}
.list-pager__btn {
  font-family: inherit;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--fg2);
  background: none;
  border: 1px solid var(--border);
  padding: .5rem .9rem;
  min-height: 40px;
  cursor: pointer;
}
.list-pager__btn:hover:not(:disabled) { color: var(--fg); border-color: var(--fg2); }
.list-pager__btn:disabled { opacity: .35; cursor: not-allowed; }
.list-pager__status { font-size: 0.78rem; color: var(--muted); }
