html {
  font-size: 14px;
}

@media (min-width: 768px) {
  html {
    font-size: 16px;
  }
}

.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
  box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
}

html {
  position: relative;
  min-height: 100%;
  overflow-x: clip; /* prevent horizontal scrollbar from full-bleed calc(-50vw+50%) sections; 'clip' (unlike 'hidden') does not create a scroll container, so position:sticky works correctly */
  scrollbar-gutter: stable; /* always reserve vertical scrollbar space so content width — and therefore the navbar — never shifts between scrollable and non-scrollable pages */
  --app-header-h: 72px; /* approximate header (navbar + mb-3) height; used by the sticky-footer fill calc so header + main reaches the viewport bottom independent of footer height */
  --footer-peek-h: 48px; /* sliver of the footer left visible at the bottom of short pages as a "more below" cue (SiteStickyFooterLayoutPolish-1) */
}

body {
    background: ghostwhite;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

/* Sticky footer shell (ShortPageFooterPushDownFix-2, refined by SiteStickyFooterLayout-1): body above
   is a full-height flex column. The public content wrapper is the only .container that is a direct
   child of body (the nav's and the footer's .container are nested deeper), so it is the flex item
   between header and footer. It grows to absorb leftover vertical space, and its <main> fills that
   wrapper. The footer never shrinks. No fixed/absolute positioning, no per-page spacers.

   The min-height makes the wrapper fill the viewport below the header (header + main ≈ viewport), so
   on short pages the footer is pushed to the bottom even when the footer itself is taller than the
   remaining viewport (the tall mobile marketing footer would otherwise ride up because body's 100vh
   budget was fully consumed by header + footer, leaving no free space for main to grow). On long pages
   the content exceeds this minimum and the page scrolls naturally. The 100vh line is the fallback for
   browsers without dvh; the 100dvh line wins where supported and tracks the visible mobile viewport.

   --footer-peek-h is also subtracted (SiteStickyFooterLayoutPolish-1) so a small sliver of the footer
   stays visible at the bottom of short pages as a "more content below" cue, instead of the footer
   sitting exactly at/just below the fold. */
body > .container {
  flex: 1 0 auto;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: calc(100vh - var(--app-header-h) - var(--footer-peek-h));
  min-height: calc(100dvh - var(--app-header-h) - var(--footer-peek-h));
}

body > .container > main {
  flex: 1 0 auto;
}

.site-footer {
  flex-shrink: 0;
}

/* PublicLogoCss-1 — public CSS text wordmark that replaces the raster header/footer logo. Mirrors the
   admin app-shell lockup technique (name + a ".92em" ".net" suffix rendered as one token) but with
   public-page colors: royal-blue name on the white header, white name on the dark footer, and the brand
   orange ".net" in both. Vector-crisp at any DPI. The .png asset is retained on disk (e.g. og:image). */
.site-brand {
  font-weight: 700;
  font-size: 1.6rem;
  line-height: 1;
  letter-spacing: .03em;
  white-space: nowrap;
  text-decoration: none;
}
.site-brand .site-brand-tld {
  color: #f97316;
  font-weight: 600;
  font-size: .92em;
}
/* White header: the established public brand blue. */
.navbar .site-brand .site-brand-name { color: #1965bd; }
/* Dark footer (#282A35): white name for contrast; a touch smaller than the header. */
.site-footer .site-brand { font-size: 1.35rem; }
.site-footer .site-brand .site-brand-name { color: #fff; }

.header-avatar {
  width: 38px;
  height: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #f97316;
  color: #fff;
  border: none;
  border-radius: 50%;
  font-size: .9375rem;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  margin-left: .25rem;
  transition: background .15s;
}

.header-avatar:hover {
  background: #ea580c;
  color: #fff;
}

.header-avatar:focus-visible {
  outline: 2px solid #0d6efd;
  outline-offset: 2px;
}

/* ── Public header — collapsed (mobile/tablet) menu ─────────────────────
   PWS-3 moved the header's collapse boundary from sm to lg: with the two solution doors added to the
   nav (Plan §4), the inline list only fits on one line at ≥992px. These rules — and the desktop-hover
   rules below — follow that boundary, so the collapsed menu is styled everywhere it is collapsed. */

@media (max-width: 991.98px) {
  .navbar-collapse .navbar-nav {
    align-items: stretch !important;
  }

  .navbar-collapse .navbar-nav + .navbar-nav {
    border-top: 1px solid #dee2e6;
    padding-top: .375rem;
    margin-top: .375rem;
  }

  .navbar-collapse .nav-link {
    padding-top: .625rem;
    padding-bottom: .625rem;
  }
}

/* Active public nav item — a slightly heavier weight only, in keeping with EventsLog's restrained
   style. No underline, no tab indicator. The weight change flows naturally into the mobile menu. */
.navbar-light .navbar-nav .nav-link.active {
  font-weight: 600;
}

/* Desktop nav hover — lightweight SaaS-style affordance: a very light blue pill on hover/focus with
   a small radius and a smooth transition. Desktop only (≥992px since PWS-3, where the bar is
   horizontal); the collapsed menu is left untouched. Scoped to .nav-link, so the Request Access
   button keeps its own hover. */
@media (min-width: 992px) {
  .navbar-light .navbar-nav .nav-link {
    border-radius: .375rem;
    transition: background-color .15s ease;
  }

  .navbar-light .navbar-nav .nav-link:hover,
  .navbar-light .navbar-nav .nav-link:focus-visible {
    background-color: #eff4fb;
  }
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
  color: var(--bs-secondary-color);
  text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
  text-align: start;
}

/* ── Skip-to-content link ────────────────────────────────────────────── */

.skip-to-main:focus {
  position: fixed !important;
  top: 0;
  left: 0;
  width: auto !important;
  height: auto !important;
  padding: .5rem 1.125rem !important;
  background: #fff;
  color: #212529;
  font-weight: 600;
  font-size: .9375rem;
  z-index: 9999;
  margin: 0 !important;
  border: 2px solid #0d6efd !important;
  border-radius: 0 0 .375rem 0;
  clip: auto !important;
  white-space: normal !important;
  text-decoration: none;
  box-shadow: 0 2px 8px rgba(0,0,0,.15);
}

/* ── Public Organizer Page (.op-*) ──────────────────────────────────────── */

.op-page {
  padding-bottom: 2.5rem;
}

/* Full-width banner (fills Bootstrap container, outside .op-page 760px constraint) */

.op-banner-full {
  width: 100%;
  height: 220px;
  overflow: hidden;
  background-color: #e9ecef;
  display: block;
}

@media (min-width: 576px) {
  .op-banner-full {
    height: 320px;
  }
}

.op-banner-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* op-page stacks after the banner; identity-group card handles the logo overlap */

.op-page.op-has-banner {
  position: relative;
  z-index: 1;
}

/* Centered inner content wrapper — used inside full-width section bands */

.op-inner {
  max-width: 1320px;
  margin-left: auto;
  margin-right: auto;
}

/* Identity group: centered card with max-width; white panel when banner present */

.op-identity-group {
  max-width: 1320px;
  margin-left: auto;
  margin-right: auto;
  margin-bottom: 1.75rem;
}

.op-has-banner .op-identity-group {
  background: #fff;
  border-radius: .5rem;
  padding: 0 1.25rem 1.25rem;
  box-shadow: 0 1px 6px rgba(0, 0, 0, .09);
  margin-bottom: 1.5rem;
}

/* No-banner fallback: full-width soft hero band */

.op-page:not(.op-has-banner) .op-identity-group {
  max-width: none;
  margin-left: 0;
  margin-right: 0;
  background: #f8f9fa;
  padding: 3rem 0 2rem;
  border-bottom: 1px solid #e9ecef;
  margin-bottom: 2rem;
}

.op-page:not(.op-has-banner) .op-identity {
  max-width: 1320px;
  margin-left: auto;
  margin-right: auto;
  padding-left: 1rem;
  padding-right: 1rem;
  padding-top: 0;
}

.op-page:not(.op-has-banner) .op-actions {
  max-width: 1320px;
  margin-left: auto;
  margin-right: auto;
  padding-left: 1rem;
  padding-right: 1rem;
  margin-top: 1.25rem;
  margin-bottom: 0;
}

/* Identity: logo + heading + tagline */

.op-identity {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  padding-top: 1.5rem;
  padding-bottom: 0;
}

.op-has-banner .op-identity {
  flex-direction: column;
  gap: .75rem;
  padding-top: 0;
  padding-bottom: 0;
}

@media (min-width: 576px) {
  .op-has-banner .op-identity {
    flex-direction: row;
    align-items: flex-start;
    gap: 1.25rem;
    padding-top: 0;
  }
}

.op-logo-wrap {
  flex-shrink: 0;
}

.op-has-banner .op-logo-wrap {
  margin-top: -36px;
  margin-bottom: .5rem;
}

@media (min-width: 576px) {
  .op-has-banner .op-logo-wrap {
    margin-top: -48px;
    margin-bottom: 0;
  }
}

.op-logo {
  width: 88px;
  height: 88px;
  object-fit: cover;
  border-radius: 50%;
  background-color: #f8f9fa;
  display: block;
}

.op-has-banner .op-logo {
  width: 80px;
  height: 80px;
  border: 3px solid #fff;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .18);
}

@media (min-width: 576px) {
  .op-has-banner .op-logo {
    width: 96px;
    height: 96px;
  }
}

.op-identity-text {
  flex: 1;
  min-width: 0;
  padding-top: .25rem;
}

.op-has-banner .op-identity-text {
  padding-top: 0;
}

@media (min-width: 576px) {
  .op-has-banner .op-identity-text {
    padding-top: .5rem;
  }
}

.op-heading {
  font-size: 1.75rem;
  font-weight: 700;
  line-height: 1.2;
  margin-bottom: .25rem;
  word-break: break-word;
}

@media (min-width: 576px) {
  .op-heading {
    font-size: 2.25rem;
  }
}

.op-tagline {
  font-size: 1rem;
  color: #6c757d;
  margin-bottom: 0;
  line-height: 1.5;
}

/* Link / CTA buttons */

.op-actions {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  margin-bottom: 2rem;
}

.op-has-banner .op-actions {
  margin-bottom: 0;
  margin-top: .25rem;
}

@media (min-width: 576px) {
  .op-actions {
    flex-direction: row;
    flex-wrap: wrap;
  }
}

.op-link-btn {
  display: block;
  padding: .5rem 1.375rem;
  border: 1.5px solid #343a40;
  border-radius: 2rem;
  color: #212529;
  background-color: transparent;
  font-size: .9375rem;
  font-weight: 500;
  text-align: center;
  text-decoration: none;
  line-height: 1.4;
  transition: background-color .15s, color .15s;
}

.op-link-btn:hover {
  background-color: #212529;
  color: #fff;
  text-decoration: none;
}

.op-link-btn:focus-visible {
  outline: 3px solid #258cfb;
  outline-offset: 2px;
}

/* Content sections */

.op-sections {
  margin-bottom: 1.5rem;
}

.op-section {
  margin-left: calc(-50vw + 50%);
  margin-right: calc(-50vw + 50%);
  padding-left: calc(50vw - 50%);
  padding-right: calc(50vw - 50%);
}

.op-section .op-inner {
  padding-top: 2rem;
  padding-bottom: 2rem;
}

.op-section-title {
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.3;
  margin-bottom: .625rem;
}

.op-section-body {
  line-height: 1.75;
  margin-bottom: 0;
}

/* Section variant bands — horizontal page blocks */

.op-section--light {
  background: #ffffff;
}

.op-section--accent {
  background: #dbeafe;
}

.op-section--dark {
  background: #212529;
  color: #fff;
}

.op-section--dark .op-section-title {
  color: #fff;
}

.op-section--dark .op-section-body {
  color: #dee2e6;
}

.op-section--soft-blue {
  background: #eff6ff;
}

.op-section--soft-warm {
  background: #fffbeb;
}

.op-section--soft-green {
  background: #f0fdf4;
}

/* Upcoming events */

.op-events {
  max-width: 1320px;
  margin-left: auto;
  margin-right: auto;
  /* No top divider before the events group — the uppercase section heading provides the separation
     (OrganizerEventListSpacingPolish-1). padding-top keeps space above the heading; the larger
     margin-bottom adds breathing room after the last event before the next section. */
  padding-top: 1.5rem;
  margin-bottom: 2.5rem;
}

.op-events-label {
  font-size: .75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: #6c757d;
  margin-bottom: .875rem;
}

.op-event-card {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  padding: .875rem 0;
  border-bottom: 1px solid #e9ecef;
  margin-bottom: 0;
}

.op-event-card:last-child {
  border-bottom: none;
  padding-bottom: 0;
}

.op-event-date-badge {
  flex: 0 0 48px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 52px;
  background: #f1f3f5;
  border-radius: .375rem;
  text-align: center;
  padding: .375rem .25rem;
  line-height: 1;
}

.op-event-date-month {
  display: block;
  font-size: .625rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: #6c757d;
  margin-bottom: .1875rem;
}

.op-event-date-day {
  display: block;
  font-size: 1.375rem;
  font-weight: 700;
  color: #212529;
  line-height: 1;
}

/* Third badge line (organizer page): the year, matching the small muted month line above the day.
   Only rendered where an .op-event-date-year span exists, so the /events badge is unaffected. */
.op-event-date-year {
  display: block;
  font-size: .625rem;
  font-weight: 600;
  color: #6c757d;
  margin-top: .1875rem;
  line-height: 1;
}

/* Public event date badge — calm navy/gray hierarchy on a modestly larger, more legible badge
   (OrganizerPublicPagePolish-4; extended to the /events list in PublicEventsListStyleConsistency-1).
   Applies to both the organizer page (.op-events) and the /events listing (.hp-event-list) so the
   two badges match. Readability comes from size/weight, not bright color. */
.op-events .op-event-date-badge,
.hp-event-list .op-event-date-badge {
  flex: 0 0 58px;          /* ~20% larger than the base 48px */
  min-height: 62px;        /* ~20% larger than the base 52px */
  padding: .5rem .25rem;
}

.op-events .op-event-date-month,
.hp-event-list .op-event-date-month {
  font-size: .75rem;       /* slightly larger */
  color: #1e3a5f;          /* muted navy */
}

.op-events .op-event-date-day,
.hp-event-list .op-event-date-day {
  font-size: 1.625rem;     /* dominant — largest/boldest */
  color: #1e293b;          /* strong near-black navy */
}

.op-events .op-event-date-year,
.hp-event-list .op-event-date-year {
  font-size: .6875rem;     /* slightly larger, still secondary */
  color: #495057;          /* muted gray, readable (AA) */
  font-weight: 600;
}

.op-event-content {
  flex: 1;
  min-width: 0;
  padding-top: .375rem;
}

.op-event-title {
  display: block;
  font-size: .9375rem;
  font-weight: 600;
  color: #2c7ac7;
  text-decoration: none;
  line-height: 1.3;
  margin-bottom: .375rem;
}

.op-event-title:hover,
.op-event-title:focus-visible {
  color: #1f5e9e;
  text-decoration: underline;
}

.op-event-title:focus-visible {
  outline: 3px solid #258cfb;
  outline-offset: 2px;
  border-radius: 2px;
}

.op-event-meta {
  font-size: .8125rem;
  color: #6c757d;
  margin-bottom: 0;
  line-height: 1.4;
}

/* Contact */

.op-contact {
  max-width: 1320px;
  margin-left: auto;
  margin-right: auto;
  border-top: 1px solid #dee2e6;
  padding-top: 1.5rem;
  margin-bottom: 1.5rem;
}

.op-contact-label {
  font-size: .75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: #6c757d;
  margin-bottom: .875rem;
}

.op-contact address {
  font-style: normal;
}

.op-contact-line {
  margin-bottom: .375rem;
  line-height: 1.5;
}

.op-contact-line:last-child {
  margin-bottom: 0;
}

.op-contact-link {
  color: #212529;
  text-decoration: none;
}

.op-contact-link:hover {
  text-decoration: underline;
}

.op-contact-link:focus-visible {
  outline: 3px solid #258cfb;
  outline-offset: 2px;
  border-radius: 2px;
}

/* Labeled contact rows (OrganizerPublicPagePolish-1): a visible field label above each value, with
   a decorative leading icon (envelope / phone / map marker). */
/* Contact rows (OrganizerPublicPagePolish-4): icon is a fixed left gutter aligned to the label
   line; the label and value share the right column, so the value aligns under the label text — not
   under the icon. Same pattern for Email, Phone, and Address. */
.op-contact-row {
  display: flex;
  align-items: flex-start;
  gap: .5rem;
  margin-bottom: 1rem;
}

.op-contact-row:last-child {
  margin-bottom: 0;
}

.op-contact-icon {
  flex: 0 0 1.1rem;
  text-align: center;
  font-size: .8125rem;
  /* Match the .75rem uppercase label's line box so the icon centers on the label text rather than
     floating above it (OrganizerContactConnectOrderPolish-1; fine-tuned in
     OrganizerContactIconAlignmentFineTune-1). */
  line-height: 1.125rem;
  margin-top: .1875rem;
  color: #6c757d;
}

.op-contact-row-body {
  min-width: 0;
}

.op-contact-row-label {
  display: block;
  font-size: .75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: #6c757d;
  margin-bottom: .25rem;
  line-height: 1.5;
}

.op-contact-row-value {
  margin-bottom: 0;
  line-height: 1.5;
}

/* Footer note */

.op-footer {
  max-width: 1320px;
  margin-left: auto;
  margin-right: auto;
  margin-top: 2rem;
  border-top: 1px solid #dee2e6;
  padding-top: 1.5rem;
}

.op-footer-note {
  font-size: .8125rem;
  color: #6c757d;
  line-height: 1.6;
  margin-bottom: 0;
}
/* ── Admin image preview ─────────────────────────────────────── */
.admin-preview-logo {
  width: 80px;
  height: 80px;
  object-fit: cover;
  border-radius: 50%;
  border: 1px solid #dee2e6;
  display: block;
}

.admin-preview-banner {
  width: 100%;
  max-height: 120px;
  object-fit: cover;
  border-radius: .375rem;
  border: 1px solid #dee2e6;
  display: block;
  margin-top: .25rem;
}
/* ── Focal point preview frame ───────────────────────────────────── */
.media-focal-frame {
  position: relative;
  overflow: hidden;
  border-radius: .375rem;
  border: 1px solid #dee2e6;
  background: #f8f9fa;
  cursor: crosshair;
  display: block;
  margin-bottom: .5rem;
}

.media-focal-frame--banner {
  aspect-ratio: 16 / 5;
  width: 100%;
}

.media-focal-frame--logo {
  aspect-ratio: 1 / 1;
  width: 120px;
  border-radius: 50%;
}

.media-focal-frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  pointer-events: none;
  user-select: none;
}

.media-focal-marker {
  position: absolute;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: transparent;
  border: 2px solid rgba(255, 255, 255, 0.95);
  box-shadow: 0 0 0 1.5px rgba(0, 0, 0, 0.55), 0 1px 6px rgba(0, 0, 0, 0.35);
  transform: translate(-50%, -50%);
  pointer-events: none;
  transition: left 0.07s ease, top 0.07s ease;
}

.media-focal-marker::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background:
    linear-gradient(rgba(255, 255, 255, 0.75), rgba(255, 255, 255, 0.75)) 50% 50% / 60% 1.5px no-repeat,
    linear-gradient(rgba(255, 255, 255, 0.75), rgba(255, 255, 255, 0.75)) 50% 50% / 1.5px 60% no-repeat;
}

.media-focal-marker::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.95);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.45);
  transform: translate(-50%, -50%);
}

@keyframes focalPulse {
  0%   { transform: translate(-50%, -50%) scale(1); }
  40%  { transform: translate(-50%, -50%) scale(1.3); }
  100% { transform: translate(-50%, -50%) scale(1); }
}

.media-focal-marker--pulse {
  animation: focalPulse 0.22s ease-out;
}

/* ── Public Event Page (.ep-*) ──────────────────────────────────────── */

.ep-page {
  padding-bottom: 2.5rem;
}

.ep-page.ep-has-banner {
  position: relative;
  z-index: 1;
}

/* Full-width banner */

.ep-banner-full {
  width: 100%;
  height: 220px;
  overflow: hidden;
  background-color: #e9ecef;
  display: block;
}

@media (min-width: 576px) {
  .ep-banner-full {
    height: 320px;
  }
}

.ep-banner-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Header group: white card when banner present; full-width hero when no banner */

.ep-header-group {
  max-width: 1320px;
  margin-left: auto;
  margin-right: auto;
  padding-left: 1rem;
  padding-right: 1rem;
  margin-bottom: 1.75rem;
}

.ep-has-banner .ep-header-group {
  background: #fff;
  border-radius: .5rem;
  padding: 0 1.25rem 1.25rem;
  box-shadow: 0 1px 6px rgba(0, 0, 0, .09);
  margin-bottom: 1.5rem;
}

/* No-banner: contained gradient hero card */

.ep-page:not(.ep-has-banner) .ep-header-group {
  background: linear-gradient(135deg, #f3f6fa 0%, #eef3f8 100%);
  border: 1px solid #d9e2ec;
  border-radius: .75rem;
  margin-top: 1rem;
  padding: 2rem 1.5rem 1.75rem;
  margin-bottom: 2rem;
}

.ep-page:not(.ep-has-banner) .ep-identity {
  padding-top: 0;
}

.ep-page:not(.ep-has-banner) .ep-actions {
  margin-top: 1.25rem;
}

/* No-banner hero: the soft gradient background (#f3f6fa→#eef3f8) drops the countdown green and
   muted #6c757d text below WCAG AA (4.5:1) — measured 4.06:1 and 4.20:1 worst case. Darken these
   text colors in the no-banner scope only; banner events keep their colors on the white card,
   where they already pass. WCAG 2.1 SC 1.4.3 (PublicEventNoBannerContrastFix-1). */
.ep-page:not(.ep-has-banner) .ep-meta-countdown {
  color: #157347;
}

.ep-page:not(.ep-has-banner) .ep-organizer,
.ep-page:not(.ep-has-banner) .ep-meta-secondary,
.ep-page:not(.ep-has-banner) .ep-status-msg,
.ep-page:not(.ep-has-banner) .ep-action-note {
  color: #5c636a;
}

/* Identity: logo + title + organizer byline */

.ep-identity {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  padding-top: 1.5rem;
  padding-bottom: 0;
}

.ep-has-banner .ep-identity {
  flex-direction: column;
  gap: .75rem;
  padding-top: 0;
  padding-bottom: 0;
}

@media (min-width: 576px) {
  .ep-has-banner .ep-identity {
    flex-direction: row;
    align-items: flex-start;
    gap: 1.25rem;
    padding-top: 0;
  }
}

/* Organizer logo */

.ep-logo-wrap {
  flex-shrink: 0;
}

.ep-has-banner .ep-logo-wrap {
  margin-top: -36px;
  margin-bottom: .5rem;
}

@media (min-width: 576px) {
  .ep-has-banner .ep-logo-wrap {
    margin-top: -48px;
    margin-bottom: 0;
  }
}

.ep-logo {
  width: 88px;
  height: 88px;
  object-fit: cover;
  border-radius: 50%;
  background-color: #f8f9fa;
  display: block;
}

.ep-has-banner .ep-logo {
  width: 80px;
  height: 80px;
  border: 3px solid #fff;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .18);
}

@media (min-width: 576px) {
  .ep-has-banner .ep-logo {
    width: 96px;
    height: 96px;
  }
}

/* Header text: title + byline */

.ep-header-text {
  flex: 1;
  min-width: 0;
  padding-top: .25rem;
}

.ep-has-banner .ep-header-text {
  padding-top: 0;
}

@media (min-width: 576px) {
  .ep-has-banner .ep-header-text {
    padding-top: .5rem;
  }
}

.ep-status-badge {
  display: inline-block;
  margin-bottom: .375rem;
}

.ep-title {
  font-size: 1.75rem;
  font-weight: 700;
  line-height: 1.2;
  margin-bottom: .25rem;
  word-break: break-word;
}

@media (min-width: 576px) {
  .ep-title {
    font-size: 2.25rem;
  }
}

.ep-organizer {
  font-size: .9375rem;
  color: #6c757d;
  margin-bottom: 0;
  line-height: 1.5;
}

.ep-organizer-link {
  color: #2c7ac7;
  font-weight: 500;
  text-decoration: none;
}

.ep-organizer-link:hover,
.ep-organizer-link:focus-visible {
  color: #1f5e9e;
  text-decoration: underline;
}

.ep-organizer-link:focus-visible {
  outline: 3px solid #258cfb;
  outline-offset: 2px;
  border-radius: 2px;
}

/* PerformanceSubordination-1 (S9): "Part of «Show»" eyebrow above the performance title, linking up to the
   Show /s page. Presentation only — the performance page keeps its own identity/tickets. */
.ep-part-of {
  font-size: .8rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  font-weight: 600;
  color: #6c757d;
  margin: 0 0 .2rem;
}

.ep-part-of-link {
  color: #2c7ac7;
  text-decoration: none;
}

.ep-part-of-link:hover,
.ep-part-of-link:focus-visible {
  color: #1f5e9e;
  text-decoration: underline;
}

/* Meta rows: date/time prominent; timezone, location, type muted below */

.ep-meta {
  display: flex;
  flex-direction: column;
  gap: .25rem;
  margin-top: .875rem;
  margin-bottom: .875rem;
}

.ep-meta-primary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .15rem .4rem;
  font-size: .9375rem;
  font-weight: 600;
  color: #212529;
  line-height: 1.5;
}

.ep-meta-secondary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .15rem .4rem;
  font-size: .875rem;
  color: #6c757d;
  line-height: 1.5;
}

.ep-meta-sep {
  color: #adb5bd;
  user-select: none;
}

.ep-meta-type {
  font-style: italic;
}

/* Upcoming-event countdown line: between the date row and the location/category row.
   Bootstrap success green (#198754) — more visible than the muted secondary row, a
   positive upcoming-event signal. Semibold (600) to match the date row's emphasis.
   Informational only — not a status/badge. */
.ep-meta-countdown {
  font-size: .9375rem;
  font-weight: 600;
  color: #198754;
  line-height: 1.5;
}

/* Action buttons */

.ep-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
  margin-top: .75rem;
}

.ep-status-msg {
  width: 100%;
  font-size: .9375rem;
  color: #6c757d;
  margin-bottom: .25rem;
}

/* Explanatory note shown in the action area when a Register/Donate button is hidden because its
   time window is not open. Small muted line — neutral, not an alert; secondary to lifecycle notices. */
.ep-action-note {
  width: 100%;
  font-size: .875rem;
  color: #6c757d;
  margin-top: .25rem;
  margin-bottom: 0;
}

/* Completed-event informational notice — replaces the muted .ep-status-msg for Status=Completed.
   Soft-yellow band draws attention more than the prior soft-blue; blue text and icon keep the
   notice reading as informational, not as an error or validation warning. */
.ep-completed-notice {
  width: 100%;
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .875rem 1rem;
  margin-bottom: .75rem;
  background-color: #fff8db;
  border: 1px solid #f3d36b;
  border-radius: .5rem;
  color: #0d3b8f;
}

.ep-completed-notice-icon {
  font-size: 1.25rem;
  color: #2563eb;
  flex-shrink: 0;
  line-height: 1;
}

.ep-completed-notice-text {
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.4;
  color: #0d3b8f;
}

.ep-actions .btn {
  padding: .625rem 1.25rem;
  font-size: 1rem;
}

/* Content body */

.ep-body {
  max-width: 1320px;
  margin-left: auto;
  margin-right: auto;
  padding-left: 1rem;
  padding-right: 1rem;
}

/* Public note — organizer-controlled short visitor message rendered near the top of the body.
   Calm neutral informational container: soft light-blue tint + border, no status colors, no icon,
   no title. Visible but intentionally secondary to the hero's Completed/Cancelled lifecycle notices.
   Negative side margins cancel .ep-body's 1rem inset so the card background aligns with the hero
   card edge; the 1.25rem horizontal padding matches the hero header-group's left padding so the
   text starts on the same column as the hero title/meta. */
.ep-public-note {
  margin-top: 1.25rem;
  margin-left: -1rem;
  margin-right: -1rem;
  padding: 1rem 1.25rem;
  background-color: #f4f8fc;
  border: 1px solid #d6e3f0;
  border-radius: .5rem;
}

.ep-public-note-text {
  margin-bottom: 0;
  font-size: .9375rem;
  line-height: 1.6;
  color: #344054;
  white-space: pre-line;
  overflow-wrap: anywhere;
}

/* VX-10 (S-J): "About {venue name}" — the linked venue's live public info on the public event page.
   A labeled narrative list; field values preserve author line breaks (pre-line). */
.ep-venue-info {
  margin-top: 1.5rem;
}
.ep-venue-info-list {
  margin-bottom: 0;
}
.ep-venue-info-list dt {
  font-weight: 600;
  color: #344054;
  margin-top: .75rem;
}
.ep-venue-info-list dd {
  margin-left: 0;
  margin-bottom: 0;
  color: #344054;
  overflow-wrap: anywhere;   /* VX-12: long website URLs wrap instead of overflowing */
}
.ep-venue-info-text {
  white-space: pre-line;
  overflow-wrap: anywhere;
}

/* VX-12 (§11 UX sweep): gentle wrap utility for long display values (e.g. venue website URLs) — breaks only
   when needed, unlike the aggressive .el-break-all. */
.text-wrap-anywhere {
  overflow-wrap: anywhere;
}

/* Facts section — groups the core event facts (short description, About, and the schedule/location/
   capacity details). Rendered as a full-width band using the same full-bleed technique and Soft Blue
   background (#eff6ff) as the page-builder ".ep-section--soft-blue" option, rather than another white
   card — this reduces card repetition (hero/notice/organizer) and gives the schedule/where-when more
   presence as a section of the page. Class name retained from FactsCardImplementation-1. */
.ep-facts-card {
  margin-top: 1.5rem;
  margin-bottom: 1.5rem;
  margin-left: calc(-50vw + 50%);
  margin-right: calc(-50vw + 50%);
  padding-top: 3rem;
  padding-bottom: 3rem;
  padding-left: calc(50vw - 50%);
  padding-right: calc(50vw - 50%);
  background: #eff6ff;
}

/* Card owns the outer top/bottom padding — drop the leading/trailing subsection padding so it does
   not double against the card edge. First child may be short description, About, or the details
   section (all conditional except details, which is always last). Inter-subsection rhythm and the
   .ep-short-desc/.ep-about dividers are unchanged. */
.ep-facts-card > :first-child {
  padding-top: 0;
}

.ep-facts-card > :last-child {
  padding-bottom: 0;
}

/* About / description */

.ep-about {
  padding-top: 1.25rem;
  padding-bottom: 1.25rem;
  border-bottom: 1px solid #dee2e6;
}

.ep-section-heading {
  font-size: .6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: #6c757d;
  margin-bottom: .625rem;
}

.ep-section-body {
  line-height: 1.75;
  margin-bottom: 0;
}

/* Details grid: schedule, location, capacity */

.ep-details-section {
  padding-top: 1.25rem;
  padding-bottom: 1.5rem;
}

.ep-details-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.75rem 2.5rem;
}

@media (min-width: 576px) {
  .ep-details-grid {
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  }
}

.ep-details-label {
  display: flex;
  align-items: center;
  gap: .3rem;
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.3;
  text-transform: none;
  letter-spacing: 0;
  color: #212529;
  margin-bottom: .625rem;
}

.ep-address {
  font-style: normal;
  line-height: 1.65;
  color: #495057;
}

/* Outbound map/directions links in the Location block (EventLocationDirections-1).
   Lightweight — one subtle primary link + a secondary text link; not a heavy button group,
   so it never competes with the Register/Donate CTAs. */
.ep-directions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .35rem 1rem;
  margin-top: .6rem;
}

/* Both links use the standard EventsLog contextual link style (matches .ep-organizer-link):
   same size and weight, normal-weight contextual link color — not buttons/CTAs. */
.ep-directions-primary,
.ep-directions-secondary {
  font-size: .9375rem;
  font-weight: 500;
  color: #2c7ac7;
  text-decoration: none;
}

.ep-directions-primary:hover,
.ep-directions-primary:focus-visible,
.ep-directions-secondary:hover,
.ep-directions-secondary:focus-visible {
  color: #1f5e9e;
  text-decoration: underline;
}

.ep-directions-primary i,
.ep-directions-secondary i {
  margin-right: .35rem;
}

/* Icons stay slightly muted/secondary so the text remains the primary element — they match the
   other event-detail fact icons (#212529 @ .7) rather than the link color. */
.ep-directions i,
.ep-directions .fa-solid {
  color: #212529;
  opacity: .7;
}

.ep-directions-secondary:hover {
  text-decoration: underline;
}

/* Schedule block — improved hierarchy and scannability */

.ep-schedule-heading {
  display: flex;
  align-items: center;
  gap: .3rem;
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.3;
  text-transform: none;
  letter-spacing: 0;
  color: #212529;
  margin-bottom: .625rem;
}

.ep-details-icon {
  font-size: .875rem;
  flex-shrink: 0;
  opacity: .7;
}

.ep-schedule-day-group + .ep-schedule-day-group {
  margin-top: .875rem;
  padding-top: .875rem;
  border-top: 1px solid #e9ecef;
}

.ep-schedule-date {
  font-size: 1rem;
  font-weight: 700;
  color: #343a40;
  margin-bottom: .375rem;
  line-height: 1.4;
}

.ep-schedule-sessions {
  list-style: none;
  padding: 0;
  margin: 0;
}

.ep-schedule-session {
  display: flex;
  flex-direction: column;
  padding-top: .25rem;
  padding-bottom: .25rem;
}

.ep-schedule-session + .ep-schedule-session {
  border-top: 1px solid #f1f3f5;
}

.ep-session-title {
  font-size: 1rem;
  font-weight: 600;
  color: #212529;
  line-height: 1.4;
}

.ep-session-time {
  font-size: .9375rem;
  color: #5c6672;
  line-height: 1.4;
  margin-bottom: 0;
}

.ep-schedule-tz {
  display: flex;
  align-items: center;
  gap: .375rem;
  font-size: .8125rem;
  color: #6c757d;
  margin-top: .75rem;
  padding-top: .625rem;
  border-top: 1px solid #e9ecef;
  margin-bottom: 0;
}

.ep-schedule-tz .fa-clock {
  color: #adb5bd;
  font-size: .75rem;
  flex-shrink: 0;
}

/* Add to calendar (EM2-12 · FR-12.1) — the shared _AddToCalendar block. Deliberately surface-neutral: the
   same markup renders inside the /e schedule block and on the registration confirmation, so it wraps rather
   than assuming either page's column width, and it carries no page-specific prefix. */

.atc {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .375rem .625rem;
  font-size: .8125rem;
  margin-top: .75rem;
}

.atc-label {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  color: #6c757d;
}

.atc-icon {
  color: #adb5bd;
  font-size: .75rem;
  flex-shrink: 0;
}

.atc-links {
  display: inline-flex;
  flex-wrap: wrap;
  gap: .625rem;
}

/* Short description: intro copy above About */

.ep-short-desc {
  padding-top: 1.25rem;
  padding-bottom: 1.25rem;
  border-bottom: 1px solid #dee2e6;
}

/* Event page content sections */

.ep-sections {
  margin-bottom: 1.5rem;
}

.ep-section {
  margin-left: calc(-50vw + 50%);
  margin-right: calc(-50vw + 50%);
  padding-left: calc(50vw - 50%);
  padding-right: calc(50vw - 50%);
}

.ep-section .ep-inner {
  padding-top: 3.5rem;
  padding-bottom: 3.5rem;
}

.ep-section-title {
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.3;
  margin-bottom: .625rem;
}

.ep-section--default {
  /* white background; border from .ep-section */
}

.ep-section--light {
  background: #f8f9fa;
  border-bottom-color: #e3e6ea;
}

.ep-section--accent {
  background: #eef4fb;
  border-bottom: none;
}


.ep-section--dark {
  background: #212529;
  color: #fff;
  border-bottom: none;
}

.ep-section--dark .ep-inner {
  padding-top: 4rem;
  padding-bottom: 4rem;
}

.ep-section--dark .ep-section-title {
  color: #fff;
}

.ep-section--dark .ep-section-body {
  color: #dee2e6;
}

.ep-section--soft-blue {
  background: #eff6ff;
}

.ep-section--soft-warm {
  background: #fffbeb;
}

.ep-section--soft-green {
  background: #f0fdf4;
}

/* Footer note */

.ep-footer {
  margin-top: 2rem;
  border-top: 1px solid #dee2e6;
  padding-top: 1.5rem;
  margin-bottom: 1rem;
}

.ep-footer-note {
  font-size: .8125rem;
  color: #6c757d;
  line-height: 1.6;
  margin-bottom: 0;
}

/* ── Event detail share buttons ─────────────────────────────────────── */

.ep-share-actions {
  display: flex;
  justify-content: flex-end;
  gap: .375rem;
  flex-wrap: wrap;
  margin-top: 1.25rem;
}

.ep-share-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 1.5px solid #adb5bd;
  color: #6c757d;
  background: transparent;
  text-decoration: none;
  font-size: .875rem;
  line-height: 1;
  cursor: pointer;
  padding: 0;
  transition: border-color .15s, color .15s, background-color .15s;
}

.ep-share-button:hover {
  border-color: #343a40;
  color: #212529;
  background: #f8f9fa;
  text-decoration: none;
}

.ep-share-button:focus-visible {
  outline: 3px solid #258cfb;
  outline-offset: 2px;
}

/* ── Event detail organizer card ─────────────────────────────────────── */

/* Negative side margins cancel .ep-body's 1rem inset so the card background aligns with the hero
   card edge; the 1.25rem horizontal padding matches the hero header-group's left padding so the
   organizer label/content starts on the same column as the hero title/meta. */
.ep-organizer-section {
  margin-top: 2.5rem;
  margin-left: -1rem;
  margin-right: -1rem;
  padding: 1.25rem;
  background: #fff;
  border: 1px solid #dbe5f1;
  border-radius: .75rem;
}

.ep-organizer-section-label {
  font-size: .75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: #6c757d;
  margin-bottom: .625rem;
}

.ep-organizer-section-link {
  display: inline-flex;
  align-items: center;
  gap: .625rem;
  font-size: .9375rem;
  font-weight: 600;
  color: #2c7ac7;
  text-decoration: none;
}

.ep-organizer-section-link:hover,
.ep-organizer-section-link:focus-visible {
  color: #1f5e9e;
}

/* Underline only the organizer name on hover/focus — not the logo image or the arrow. */
.ep-organizer-section-link:hover span:not(.ep-organizer-section-arrow),
.ep-organizer-section-link:focus-visible span:not(.ep-organizer-section-arrow) {
  text-decoration: underline;
}

.ep-organizer-section-link:focus-visible {
  outline: 3px solid #258cfb;
  outline-offset: 2px;
  border-radius: 2px;
}

.ep-organizer-section-logo {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid #dee2e6;
  flex-shrink: 0;
}

.ep-organizer-section-arrow {
  flex-shrink: 0;
  font-size: .75rem;
  color: #adb5bd;
}

/* Action page (register / donate) event/organizer context line */

.action-page-context {
  font-size: 1.0625rem;
  color: #495057;
  margin-bottom: 1.5rem;
}

/* ── Public banner family ─────────────────────────────────────────── */

.public-banner {
  width: 100%;
  overflow: hidden;
  background-color: #e9ecef;
  display: block;
}

.public-banner > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.public-banner--hero {
  height: 220px;
}

@media (min-width: 576px) {
  .public-banner--hero {
    height: 320px;
  }
}

.public-banner--action {
  height: 140px;
  margin-bottom: 1.25rem;
}

@media (min-width: 576px) {
  .public-banner--action {
    height: 200px;
  }
}

/* Action page (register / donate) compact organizer banner */

.action-page-banner {
  display: block;
  width: 100%;
  height: 160px;
  object-fit: cover;
  border-radius: .375rem;
  margin-bottom: 1.25rem;
}

/* ── Homepage (.hp-*) ─────────────────────────────────────────────── */

.hp-hero {
  margin-left: calc(-50vw + 50%);
  margin-right: calc(-50vw + 50%);
  /* Remove the ghostwhite strip under the header: the navbar's mb-3 leaves a 1rem gap that exposes the
     body background. Pull every marketing hero up by that amount so it begins directly beneath the white
     nav (Home gets this via .mk-hero-stage; /event-management & /class-management need it on the base). */
  margin-top: -1rem;
  padding-top: 3rem;
  padding-bottom: 2.5rem;
  padding-left: calc(50vw - 50%);
  padding-right: calc(50vw - 50%);
  background: linear-gradient(135deg, #f8fbff 0%, #82b3eb 100%);
  /* No bottom border or margin: the hairline border read as a hard "section box" divider that
     isolated the hero, and the full-bleed gradient hero's bottom margin exposed a strip of the
     ghostwhite page background. Dropping both lets the soft gradient edge meet the next white
     band directly, so the transition reads as one continuous, intentional flow. The following
     section's own top padding supplies the breathing room. */
  margin-bottom: 0;
}

.hp-hero-title {
  font-size: 2rem;
  font-weight: 700;
  line-height: 1.2;
  margin-bottom: .5rem;
}

@media (min-width: 576px) {
  .hp-hero-title {
    font-size: 2.75rem;
  }
}

.hp-hero-lead {
  font-size: 1.0625rem;
  color: #6c757d;
  margin-bottom: 0;
  max-width: 52ch;
}

.hp-section-label {
  font-size: .75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: #6c757d;
  margin-bottom: 0;
}

.hp-event-list {
  /* No top divider before the first event (PublicEventsListSpacingAndCssDeployCheck-1) — the page's
     "Upcoming Events" hero heading and the section's top padding provide the separation. The bottom
     margin adds breathing room after the last event before the footer. Row separators between events
     come from .op-event-card's border-bottom (unchanged). */
  margin-bottom: 2.5rem;

  /* PWD-5 (§6.5 (a)): the element became a real <ul> so the directory announces as a list of N cards.
     These three declarations are the ENTIRE cost of that change — the browser's default bullets, indent
     and top margin are removed so the rendering is byte-for-byte what the <div> produced. */
  list-style: none;
  padding-left: 0;
  margin-top: 0;
}

/* PWD-5 (§6.5 (a)): each /events card opens with a heading carrying its own title. The heading element is
   structural only — the type scale, colour, weight and spacing all stay on .op-event-title (the anchor
   inside it), so demoting or promoting the level changes the outline and nothing visual. */
.op-event-heading {
  font-size: inherit;
  font-weight: inherit;
  line-height: inherit;
  margin: 0;
}

.hp-org-cta {
  margin-left: calc(-50vw + 50%);
  margin-right: calc(-50vw + 50%);
  padding-top: 2rem;
  padding-bottom: 2rem;
  padding-left: calc(50vw - 50%);
  padding-right: calc(50vw - 50%);
  background: #f8fbff;
  border-top: 1px solid #dbe5f1;
  margin-top: 2.5rem;
}

/* ── Public page full-bleed section system ─────────────────────────────── */

/* Breaks out of the Bootstrap container so section backgrounds reach the
   viewport edges, while content re-aligns with the container via the
   inverse calc. 50% refers to the containing block (<main>) width, not
   the element's own width, so the math works at every breakpoint. */
.public-page-intro {
  margin-left: calc(-50vw + 50%);
  margin-right: calc(-50vw + 50%);
  padding-top: 2.5rem;
  padding-bottom: 2rem;
  padding-left: calc(50vw - 50%);
  padding-right: calc(50vw - 50%);
  background: linear-gradient(135deg, #f8fbff 0%, #eef4fb 100%);
  border-bottom: 1px solid #dbe5f1;
  margin-bottom: 0;
}

.public-page-intro h1 {
  font-size: 1.75rem;
  font-weight: 700;
  margin-bottom: .5rem;
  color: #212529;
}

@media (min-width: 576px) {
  .public-page-intro h1 {
    font-size: 2.25rem;
  }
}

.public-page-intro p {
  color: #6c757d;
  font-size: 1rem;
  margin-bottom: 0;
  max-width: 60ch;
}

.public-page-content {
  padding-top: 2rem;
}

/* Public static/content-page contextual links (PublicStaticPageLinkStyle-1): one consistent
   EventsLog blue for in-content links on About / Terms / Refunds (and reusable for future static
   content). No underline at rest; underline + visible focus on hover/keyboard. Scoped to this
   class only — NOT a global anchor change, and intentionally not auto-applied to all content. */
.public-content-link {
  color: #2c7ac7;
  text-decoration: none;
}

.public-content-link:hover,
.public-content-link:focus-visible {
  color: #1f5e9e;
  text-decoration: underline;
}

.public-content-link:focus-visible {
  outline: 2px solid #258cfb;
  outline-offset: 2px;
  border-radius: 2px;
}

/* .public-form-card is defined with the shared public form-card family above
   (ContactPage-VisualPolish-Implement-1) — it carries the tint plus the stronger
   input border, matching the registration/enrollment forms. */

/* ── Marketing homepage (MarketingHomeOrganizerPivot-1 / MarketingHomeVisualRefinement-1) ──
   Organizer-acquisition homepage. Reuses .hp-hero / .hp-org-cta full-width bands and
   .public-page-content; this block adds the section/card/tag/chip vocabulary plus a warm,
   scoped CTA accent (#b45309). The .btn-mk-* classes are scoped — they do NOT override
   Bootstrap's global .btn-primary, so other pages are unaffected. */

/* Scoped marketing CTA. Softer, welcoming primary: light-blue fill, navy border, near-black text
   (dark text on #cbe0fb ≈ 12:1, passes WCAG AA). Hover/focus fills navy with white text (~11:1).
   Scoped to .btn-mk-primary — does NOT touch Bootstrap's global .btn-primary. */
.btn-mk-primary {
  background-color: #cbe0fb;
  border-color: #1e3a5f;
  color: #111827;
}

/* Filled "active" look on focus (e.g. right after a tap) for both marketing buttons. The :hover variant is
   guarded by @media (hover: hover) below so touch devices never apply hover — that removes the mobile
   "first tap only shows the hover state, then a second tap follows the link" double-tap (MarketingButtonTap-1). */
.btn-mk-primary:focus {
  background-color: #1e3a5f;
  border-color: #1e3a5f;
  color: #fff;
}

.btn-mk-outline {
  background-color: transparent;
  border-color: #1e3a5f;
  color: #1e3a5f;
}

.btn-mk-outline:focus {
  background-color: #1e3a5f;
  border-color: #1e3a5f;
  color: #fff;
}

@media (hover: hover) {
  .btn-mk-primary:hover {
    background-color: #1e3a5f;
    border-color: #1e3a5f;
    color: #fff;
  }
  .btn-mk-outline:hover {
    background-color: #1e3a5f;
    border-color: #1e3a5f;
    color: #fff;
  }
}

.btn-mk-primary:focus-visible,
.btn-mk-outline:focus-visible,
.btn-mk-learn:focus-visible {
  outline: 3px solid #258cfb;
  outline-offset: 2px;
}

/* Two-ways card "Learn about …" CTAs (TwoWaysLearnButton-1). Brand-blue outline button:
   2px #0662bb border + matching text on a transparent fill, with a light-blue hover wash and a
   subtle drop shadow. Hover is guarded by @media (hover: hover) like the other marketing buttons
   so touch devices don't get the double-tap; :focus mirrors the hover for keyboard/tap feedback. */
.btn-mk-learn {
  background-color: transparent;
  border: 2px solid #0662bb;
  color: #0662bb;
  transition: background-color .15s ease, box-shadow .15s ease, color .15s ease;
}

.btn-mk-learn:focus {
  background-color: #cbe0fb;
  border-color: #0662bb;
  color: #0662bb;
  box-shadow: 0 4px 10px rgba(6, 98, 187, .25);
}

@media (hover: hover) {
  .btn-mk-learn:hover {
    background-color: #cbe0fb;
    border-color: #0662bb;
    color: #0662bb;
    box-shadow: 0 4px 10px rgba(6, 98, 187, .25);
  }
}

/* ── PWS-0: marketing CTA visual hierarchy ─────────────────────────────────────────────────────────
   The Home review found the hero's two buttons read at near-identical weight. This establishes one
   unambiguous solid primary and a distinctly quieter secondary, so a page's main action is obvious at a
   glance. These are ADDITIVE, scoped .btn-mk-* classes — the existing .btn-mk-primary / .btn-mk-outline /
   .btn-mk-learn are untouched, so no live page changes until its own slice (PWS-1/PWS-2) adopts these. */

/* Solid primary: filled brand navy, white text (~10:1 on #fff). The heaviest button on the page. */
.btn-mk-solid {
  background-color: #1e3a5f;
  border: 1px solid #1e3a5f;
  color: #fff;
  transition: background-color .15s ease, border-color .15s ease, box-shadow .15s ease;
}
.btn-mk-solid:focus {
  background-color: #16304d;
  border-color: #16304d;
  color: #fff;
}

/* Quieter secondary: transparent fill, hairline border, navy text — clearly subordinate to the solid. */
.btn-mk-quiet {
  background-color: transparent;
  border: 1px solid #c3ccd8;
  color: #1e3a5f;
  transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}
.btn-mk-quiet:focus {
  background-color: #eef2f7;
  border-color: #1e3a5f;
  color: #1e3a5f;
}

/* Hover guarded like the other marketing buttons so touch devices don't get the double-tap. */
@media (hover: hover) {
  .btn-mk-solid:hover {
    background-color: #16304d;
    border-color: #16304d;
    color: #fff;
    box-shadow: 0 4px 10px rgba(30, 58, 95, .25);
  }
  .btn-mk-quiet:hover {
    background-color: #eef2f7;
    border-color: #1e3a5f;
    color: #1e3a5f;
  }
}

.btn-mk-solid:focus-visible,
.btn-mk-quiet:focus-visible {
  outline: 3px solid #258cfb;
  outline-offset: 2px;
}

/* ── PWS-0: one-platform statement (_OnePlatformStatement.cshtml, Plan §1) ──────────────────────────
   A calm, single-line mandatory statement carried by every page that presents multiple use cases or
   capabilities. Muted, centered, with a small leading icon; not a card or a CTA. */
.mk-one-platform {
  display: flex;
  align-items: flex-start;
  gap: .5rem;
  justify-content: center;
  text-align: center;
  color: #4b5563;
  max-width: 46rem;
  margin: 1.5rem auto 0;
}
.mk-one-platform-icon {
  color: #1e3a5f;
  margin-top: .2rem;
  flex: 0 0 auto;
}

/* Full-width section bands — the background defines chapter separation. Each band breaks out to
   the full viewport using the same calc technique as .hp-hero / .ep-section, then re-pads so its
   content aligns to the same centered container content edge as the hero. Bands sit flush;
   alternating tint/white surfaces mark each chapter (no rounded section cards). */
.mk-fullband {
  margin-left: calc(-50vw + 50%);
  margin-right: calc(-50vw + 50%);
  padding-left: calc(50vw - 50%);
  padding-right: calc(50vw - 50%);
  padding-top: 3.5rem;
  padding-bottom: 3.5rem;
  background: #f3f3f3;
}

.mk-fullband--tint {
  background: #f5f8fc;
}

/* Section heading: near-black content anchor + a short warm accent rule (the one orange touch). */
.mk-section-title {
  font-size: 1.5rem;
  font-weight: 700;
  color: #111827;
  line-height: 1.25;
  margin-bottom: .875rem;
}

.mk-section-title::after {
  content: "";
  display: block;
  width: 2.5rem;
  height: 3px;
  margin-top: .5rem;
  background: #f97316;
  border-radius: 2px;
}

/* Hero heading + reserved (CSS-only) visual panel */
.mk-hero-title {
  color: #111827;
}

.mk-hero-visual {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 16rem;
  padding: 2.25rem;
  border-radius: 1rem;
  background: linear-gradient(135deg, #1e3a5f 0%, #2c5282 100%);
  box-shadow: 0 1px 10px rgba(30, 58, 95, .15);
}

/* HeroCardIdentityPolish-1: give the three hero cards distinct-but-sibling identities by shifting ONLY
   the card's background undertone — nothing else (dimensions, shape, radius, padding, shadow, typography,
   icon rings, connector, timeline, and spacing all stay identical to the canonical card above).
   Home keeps the canonical navy and is the reference. Event leans a hair warmer (indigo / warm-blue);
   Class leans a hair cooler (blue-teal). The shifts are deliberately small (~10° hue, same lightness)
   so each page feels subtly its own without reading as a different brand. Scoped via the existing,
   per-page hero `aria-labelledby` ids, so no page markup changes are required. */
.hp-hero[aria-labelledby="em-hero-title"] .mk-hero-visual {
  background: linear-gradient(135deg, #233862 0%, #345086 100%); /* Event — subtle warm/indigo */
}

.hp-hero[aria-labelledby="cm-hero-title"] .mk-hero-visual {
  background: linear-gradient(135deg, #183c5d 0%, #265684 100%); /* Class — subtle cool/blue-teal */
}

/* Compact 3-stage lifecycle teaser inside the hero panel — vertical, icon-led, short labels,
   no numbers/paragraphs. Differs from the horizontal numbered "How it works" cards below.
   The node is a wrapper <span> (not the Font Awesome <i>), so flex centering is not overridden
   by Font Awesome's `.fa-solid { display: inline-block }`. */
.mk-lifecycle {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  /* HeroTimelineAlignment-1: fix the timeline to a consistent width so the icon column and connector
     sit on the SAME x-axis across the Home/Event/Class hero cards regardless of label length. Without
     this the block is shrink-to-fit and horizontally centered in the card (justify-content: center on
     .mk-hero-visual), so a longer label widens the block and pushes the centered icon column sideways.
     Width is sized to the longest label; max-width keeps it from overflowing the card at the narrow lg
     breakpoint. Labels still vary in length and wrap-free; only the icon column is pinned. */
  width: 17.5rem;
  max-width: 100%;
}

.mk-lifecycle-step {
  display: flex;
  align-items: center;
  gap: .85rem;
}

.mk-lifecycle-node {
  position: relative;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  background: rgba(255, 255, 255, .12);
  border: 1px solid rgba(255, 255, 255, .28);
  color: #fff;
}

.mk-lifecycle-node i {
  font-size: 1.1rem;
  line-height: 1;
}

/* Connector line linking each node to the next (fills the flex gap). */
.mk-lifecycle-step:not(:last-child) .mk-lifecycle-node::after {
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  width: 2px;
  height: 1.5rem;
  background: rgba(255, 255, 255, .25);
}

.mk-lifecycle-label {
  color: rgba(255, 255, 255, .92);
  font-weight: 600;
  font-size: 1rem;
}

.mk-section-intro {
  max-width: 60ch;
  margin-bottom: 1.5rem;
}

.mk-attendee-onramp {
  font-size: .9375rem;
}

/* ── Home hero stage (HomeHeroEditorialType-1, retained by PWS-1) ─────────────
   The Home hero's softly lit environment: two layers apply across the WHOLE hero band — Gallery
   Light (soft directional light + depth) and an extremely faint horizontal baseline rhythm.
   Scoped to .mk-hero-stage so the Event/Class management heroes — which keep the .mk-hero-visual
   lifecycle card — are untouched. PWS-1 replaced the editorial word panel this stage was built
   around (.mk-cap-*, removed with its entrance animation) with the .hp-hero-shots screenshot
   composition; the lit stage itself is unchanged and carries no motion of its own. */
.mk-hero-stage {
  position: relative;
  overflow: hidden;
  /* (1) Remove the ghostwhite strip under the header: the navbar's mb-3 leaves a 1rem gap that exposes
     the body background. Pull the hero up by that amount so it begins directly beneath the white nav. */
  margin-top: -1rem;
  /* (5) A little more breathing room before the Journey section so the hero finishes first. */
  padding-bottom: 4.5rem;
}
.mk-hero-stage > .row { position: relative; z-index: 1; }

/* (3) Paragraph readability — slightly looser leading only (size/width/copy unchanged). */
.mk-hero-stage .hp-hero-lead { line-height: 1.7; }

/* (2) Optical alignment (desktop only): the right-hand panel is taller than the left column, so under
   align-items-center its top sits a little above the left content. Raise the whole left column ~16px
   to line its top up with the panel top. Typography/buttons unchanged. */
@media (min-width: 992px) {
  .mk-hero-stage > .row > .col-lg-7 { margin-top: -1rem; }
}

/* (HeroMobileAlign-1) Mobile-only headline alignment across the three marketing heroes (Home,
   /event-management, /class-management). The Home hero (.mk-hero-stage) sat much higher than the other
   two because its lit "stage" couples flush to the nav; push its content column down so the nav→headline
   gap matches the others. The Event/Class heroes (.hp-hero without the stage) come up ~4px. Mobile only —
   desktop is untouched (the desktop optical raise lives in the min-width:992px rule). */
@media (max-width: 991.98px) {
  .mk-hero-stage > .row > .col-lg-7 { margin-top: 2.25rem; }
  .hp-hero:not(.mk-hero-stage) { padding-top: 2.75rem; }
}

/* Gallery Light across the entire hero — soft key light (upper-left), gentle depth
   (lower-right), faint edge falloff. Matte, low-saturation; no glow, no hotspot. */
.mk-hero-stage::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    /* (HomeHeroFinalAtmosphere-1): a whisper top-wash — slightly richer existing-navy directly
       beneath the white nav, eased to nothing by ~170px. No new color, no stop, no band; it simply gives
       the hero a "lid" so the white navigation reads as a separate plane (felt mostly on mobile, where the
       white key-light below bleaches the top). Topmost layer so it tints the very top edge. */
    linear-gradient(to bottom, rgba(30, 58, 95, .055), rgba(30, 58, 95, 0) 170px),
    radial-gradient(120% 115% at 16% 10%, rgba(255, 255, 255, .55), rgba(255, 255, 255, 0) 52%),
    radial-gradient(125% 120% at 90% 94%, rgba(30, 58, 95, .05), rgba(30, 58, 95, 0) 58%),
    radial-gradient(150% 130% at 50% 42%, rgba(30, 58, 95, 0) 62%, rgba(30, 58, 95, .028) 100%);
}

/* Extremely subtle horizontal baseline rhythm across the entire hero (no vertical guide).
   ~3% navy, edges masked so it reads as structure, not a wireframe. */
.mk-hero-stage::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: repeating-linear-gradient(to bottom,
    rgba(30, 58, 95, .026) 0, rgba(30, 58, 95, .026) 1px, transparent 1px, transparent 40px);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 14%, #000 86%, transparent 100%);
          mask-image: linear-gradient(to bottom, transparent 0, #000 14%, #000 86%, transparent 100%);
}

/* ── PWS-1: Home hero product-screenshot composition ─────────────────────────────────────────────────
   Replaces the retired editorial word panel (.mk-cap-*, HomeHeroEditorialType-1), whose content only
   assembled through a CSS entrance animation — the hero's "can render empty" defect. This composition is
   plain markup: two curated 16:10 screenshots, the lead shot in front and a supporting shot offset behind
   it for depth. Nothing here depends on script or animation, so the hero is complete on first paint.
   Both images carry intrinsic width/height and a fixed aspect ratio, so the boxes are reserved before the
   bytes arrive (no layout shift, and the lead shot is a stable LCP element). */
.hp-hero-shots {
  position: relative;
  /* Reserve the composition's height (front shot + the back shot's visible offset) so the hero does not
     reflow as the images decode. */
  padding: 0 0 3.25rem 3.5rem;
}

.hp-hero-shot {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  border-radius: .85rem;
  border: 1px solid rgba(30, 58, 95, .1);
  background: #f5f8fc;
}

.hp-hero-shot--front {
  position: relative;
  z-index: 1;
  box-shadow: 0 18px 40px -18px rgba(30, 45, 64, .5);
}

/* The supporting shot sits behind and below-left, cropped by the composition box — a hint of a second
   surface, never a competing image. Decorative only (aria-hidden, empty alt in the markup). */
.hp-hero-shot--back {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 62%;
  z-index: 0;
  opacity: .92;
  box-shadow: 0 12px 28px -16px rgba(30, 45, 64, .45);
}

/* Below lg the hero stacks; the composition keeps the same shape but tightens its offsets so it stays
   comfortably inside a 360px viewport. */
@media (max-width: 991.98px) {
  .hp-hero-shots {
    margin-top: 2rem;
    padding: 0 0 2rem 1.5rem;
  }
}

/* Early-access reassurance under the hero buttons — quiet, factual, never a badge or a banner. */
.hp-hero-note {
  margin: 1.25rem 0 0;
  font-size: .9375rem;
  color: #4b5563;
}

.hp-hero-note i {
  color: #1e3a5f;
  margin-right: .4rem;
}

/* ── Organizer journey (OrganizerJourneySection-1) ───────────────────────
   A calm, connected path — one thin line threads the milestone icons. NOT
   feature cards, NO step numbers, NO arrowheads (so it reads as a journey,
   not a flowchart). Icons carry an opaque fill so they sit on top of the line.
   Desktop: horizontal path. Mobile: vertical path. Palette reuses the hero
   band (#eef4fb / #dbe5f1) for cohesion. The journey sits inside a soft grouping
   panel (.oj-panel) so the wide row reads as one cohesive unit with the heading
   rather than icons floating wider than the heading block. */
.oj-panel {
  margin-top: 2rem;
  padding: 2.25rem 1.75rem;
  background: #e4edf9;
  border: 1px solid #e9eef5;
  border-radius: 1rem;
}

.oj-journey {
  list-style: none;
  margin: 0;
  padding: 0;
  position: relative;
  display: flex;
  gap: 1.5rem;
}

/* the connecting path, behind the icons (desktop, horizontal) */
.oj-journey::before {
  content: "";
  position: absolute;
  top: 1.75rem;           /* vertical centre of the 3.5rem icon */
  left: 10%;
  right: 10%;
  height: 2px;
  background: #dbe5f1;
  z-index: 0;
}

.oj-stage {
  flex: 1 1 0;
  min-width: 0;
  text-align: center;
  position: relative;
}

.oj-icon {
  position: relative;
  z-index: 1;             /* above the connecting line; opaque fill masks it */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 50%;
  background: #fff;
  /* PrototypeJourneyIconAccent-1: warm coral guidance accent (secondary brand color) replaces the
     blue glyph so the journey icons soften the page and guide the eye without competing with the
     navy typography. Glyph color only — circular white background, hairline border, and size unchanged. */
  color: #e78e72;
  border: 1px solid #dbe5f1;
  margin-bottom: 1rem;
}

.oj-icon i {
  font-size: 1.3rem;
  line-height: 1;
}

.oj-label {
  font-size: 1.0625rem;
  font-weight: 600;
  color: #111827;
  margin-bottom: .35rem;
}

.oj-caption {
  font-size: .9375rem;
  color: #6c757d;
  margin: 0 auto;
  max-width: 24ch;
}

@media (max-width: 767.98px) {
  .oj-panel {
    padding: 1.75rem 1.25rem;
  }
  .oj-journey {
    flex-direction: column;
    gap: 0;
    max-width: 24rem;
    margin-left: auto;
    margin-right: auto;
  }
  /* hide the horizontal line; the path becomes vertical, segment per stage */
  .oj-journey::before {
    display: none;
  }
  .oj-stage {
    text-align: left;
    display: grid;
    grid-template-columns: 3.5rem 1fr;
    column-gap: 1rem;
    align-items: start;
    padding-bottom: 1.75rem;
  }
  .oj-stage:last-child {
    padding-bottom: 0;
  }
  .oj-icon {
    margin-bottom: 0;
    grid-row: span 2;
  }
  /* vertical connector from each icon down to the next (in the gap region) */
  .oj-stage:not(:last-child)::after {
    content: "";
    position: absolute;
    left: 1.75rem;        /* icon centre */
    top: 3.5rem;          /* below this icon */
    bottom: 0;            /* to the next icon's top edge */
    width: 2px;
    background: #dbe5f1;
    transform: translateX(-50%);
    z-index: 0;
  }
  .oj-label {
    margin-bottom: .15rem;
  }
  .oj-caption {
    max-width: none;
    margin: 0;
  }
}

/* ── PWS-1: Home use-case doors (.hd-*) ───────────────────────────────────
   Replaces the retired "Two ways" panels (.tw-*, TwoWaysSection-1) and their choice framing. Two on-ramps
   into ONE platform, each led by a real product screenshot so the door shows what it routes to. The CTA is
   pinned to the card bottom so both cards balance at equal height. Marketing palette (#eef4fb / #dbe5f1). */
.hd-card {
  background: #fff;
  border: 1px solid #e2e8f0;
  border-radius: .85rem;
  box-shadow: 0 1px 8px rgba(30, 58, 95, .06);
  display: flex;
  flex-direction: column;
  overflow: hidden;   /* the shot bleeds to the card edge and is clipped by the card's radius */
}

/* Screenshot thumbnail: same 16:10 frame and intrinsic sizing as the journey-page shots, so the box is
   reserved before the lazy image arrives. Not click-to-zoom — the whole card routes to the door. */
.hd-card-shot {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  object-position: top center;
  background: #f5f8fc;
  border-bottom: 1px solid #e2e8f0;
}

.hd-card-body {
  padding: 1.75rem;
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
}

.hd-card-title {
  font-size: 1.25rem;
  font-weight: 700;
  color: #111827;
  margin: 0 0 .85rem;
}

.hd-card-for {
  color: #374151;
  margin-bottom: .65rem;
}

.hd-card-caps {
  color: #6c757d;
  font-size: .9375rem;
  margin-bottom: 1.25rem;
}

.hd-card-cta {
  margin-top: auto;        /* pin to the bottom so both cards balance at equal height */
  display: flex;
  align-items: center;
  gap: .75rem;
  flex-wrap: wrap;
}

/* ── PWS-1: Home live-proof strip (.hp-proof-*) ───────────────────────────
   Real upcoming events/classes as linked cards. The whole card is the link (one target, no nested
   interactive elements), so every line inside is a <span> and the card carries the focus ring. */
.hp-proof-card {
  display: flex;
  flex-direction: column;
  gap: .35rem;
  height: 100%;
  padding: 1.25rem 1.35rem;
  background: #fff;
  border: 1px solid #e2e8f0;
  border-radius: .85rem;
  box-shadow: 0 1px 8px rgba(30, 58, 95, .06);
  text-decoration: none;
  color: inherit;
  transition: box-shadow .15s ease, border-color .15s ease;
}

.hp-proof-date {
  font-size: .8125rem;
  font-weight: 600;
  letter-spacing: .02em;
  color: #1e3a5f;
}

/* "Next" marker on a recurring offering's card — its next meeting, not a one-off date. */
.hp-proof-next {
  color: #6c757d;
  font-weight: 500;
  margin-right: .35rem;
}

.hp-proof-title {
  font-size: 1.0625rem;
  font-weight: 700;
  color: #111827;
  line-height: 1.3;
}

.hp-proof-meta {
  font-size: .875rem;
  color: #6c757d;
}

@media (hover: hover) {
  .hp-proof-card:hover {
    border-color: #c3d5ea;
    box-shadow: 0 6px 18px -8px rgba(30, 58, 95, .28);
  }
  .hp-proof-card:hover .hp-proof-title {
    text-decoration: underline;
  }
}

.hp-proof-card:focus-visible {
  outline: 3px solid #258cfb;
  outline-offset: 2px;
}

/* ── Event Management journey page (EventManagementFoundation-1) ──────────
   Scoped (.em-*) styles for /event-management. Reuses the marketing shell
   (.hp-hero, .mk-fullband, .mk-section-title) and palette (#eef4fb / #dbe5f1,
   navy #1d4ed8) for cohesion with Home. This slice styles the page foundation:
   the event-type pills and the workflow-chapter scaffold (placeholder media
   frames). Screenshots/narratives are slotted in later slices. */

/* Event types: calm text pills — an "is this for me?" band, deliberately NOT a
   dense icon grid. White pills sit on the tinted band. */
.em-type-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: .625rem;
}

.em-type-pill {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  padding: .5rem .9rem;
  background: #fff;
  border: 1px solid #dbe5f1;
  border-radius: 999px;
  font-size: .9375rem;
  color: #1f2937;
}

.em-type-pill i {
  font-size: .85rem;
  color: #1d4ed8;
}

/* Workflow chapters: a vertical, chronological scaffold. Each chapter carries a
   small step eyebrow, an icon + milestone title, and a placeholder media frame
   that later holds the stage's screenshot. */
.em-chapters {
  list-style: none;
  margin: 2.5rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}

.em-chapter {
  padding: 1.75rem;
  background: #fff;
  border: 1px solid #e9eef5;
  border-radius: 1rem;
}

.em-chapter-eyebrow {
  font-size: .75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: #6c757d;
  margin: 0 0 .5rem;
}

.em-chapter-head {
  display: flex;
  align-items: center;
  gap: .85rem;
  margin-bottom: 1.25rem;
}

.em-chapter-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3rem;
  height: 3rem;
  flex-shrink: 0;
  border-radius: 50%;
  background: #eef4fb;
  color: #1d4ed8;
  border: 1px solid #dbe5f1;
}

.em-chapter-icon i {
  font-size: 1.25rem;
  line-height: 1;
}

.em-chapter-title {
  font-size: 1.25rem;
  font-weight: 600;
  color: #111827;
  margin: 0;
}

/* Placeholder media frame — a calm dashed area that reads as "screenshot goes
   here" so the scaffold is honest while content is pending. Replaced by a real
   figure in the per-chapter slices. */
.em-chapter-media {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  min-height: 11rem;
  border: 1px dashed #c8d6e8;
  border-radius: .75rem;
  background: #f8fbff;
  color: #94a3b8;
}

.em-chapter-media i {
  font-size: 1.6rem;
}

.em-chapter-media span {
  font-size: .875rem;
  font-weight: 500;
}

/* Story chapter (EventManagementPublish-1): a built chapter is a calm two-column layout —
   organizer-voice copy beside a reserved screenshot location. The reserved frame (.em-shot--reserved)
   is intentionally empty (no placeholder artwork) and sized to a typical screenshot aspect, so the
   real image drops in later without a redesign. Applies only to chapters built out as stories;
   not-yet-built chapters keep the foundation placeholder (.em-chapter-media). */
.em-chapter-body {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 2rem;
  /* Top-align the two columns (MarketingChapterCopyTopAlign-1): the screenshot is taller than the copy, so
     center-alignment pushed the paragraphs to the row's middle — too far below the heading. Start-aligning
     keeps the copy directly under the heading with normal spacing. */
  align-items: start;
}

.em-chapter-copy p {
  color: #4b5563;
  font-size: 1rem;
  line-height: 1.65;
  margin-bottom: 1rem;
  max-width: 46ch;
}

.em-chapter-next {
  margin-top: 1.25rem;
}

.em-chapter-next a {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .45rem .95rem;
  border-radius: 999px;
  font-weight: 600;
  font-size: .9375rem;
  color: #1d4ed8;
  background: #e4edf9;
  text-decoration: none;
  transition: background-color .15s ease, color .15s ease, box-shadow .15s ease;
}

/* Keyboard focus always gets the deepened pill (no hover dependency). */
.em-chapter-next a:focus-visible {
  background: #cbe0fb;
  color: #163e9e;
  text-decoration: none;
}

/* Hover effects guarded to real pointers so touch devices don't get a
   sticky-hover/first-tap-swallow on the pill. */
@media (hover: hover) {
  .em-chapter-next a:hover {
    background: #cbe0fb;
    color: #163e9e;
    box-shadow: 0 2px 8px -2px rgba(25, 101, 189, .35);
    text-decoration: none;
  }
}

.em-chapter-next i {
  font-size: .8rem;
}

/* Screenshot mat (MarketingScreenshotMat-1): the curated marketing screenshots are light/near-white, so on
   the white chapter card their edges disappear. Sit each shot on a soft blue mat (coordinated with the hero)
   with a little padding + a lift shadow on the image, so the white screenshot clearly reads as a framed
   image. Shared by /event-management and /class-management (both use .em-chapter-shot / .em-shot--real). */
.em-chapter-shot {
  padding: .85rem;
  border-radius: 1.1rem;
  background: linear-gradient(135deg, #e8eef8 0%, #9cc0ec 100%);
}

.em-shot {
  border-radius: .75rem;
  overflow: hidden;
}

/* Empty reserved screenshot frame — calm tint + hairline so it reads as intentional reserved space,
   not missing media. Replaced by a real <figure>/<img> when the screenshot library lands. */
.em-shot--reserved {
  aspect-ratio: 16 / 10;
  background: #f5f8fc;
  border: 1px solid #e2e8f0;
}

/* Real screenshot (MarketingScreenshotIntegration-1): drops into the same 16:10 frame as the reserved
   placeholder — same radius (via .em-shot) and hairline border. Scales responsively (width:100%) with no
   distortion (source is 16:10) and no layout shift (intrinsic width/height + fixed aspect-ratio reserve
   the box before the lazy image loads). */
.em-shot--real {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  background: #f5f8fc;
  border: 1px solid #e2e8f0;
  box-shadow: 0 12px 30px -10px rgba(30, 45, 64, .45);
  cursor: zoom-in;
}

/* Click-to-zoom lightbox (MarketingScreenshotLightbox-1): full-screen view of a workflow screenshot,
   reusing the same blue mat frame as the inline shot. Toggled by adding/removing .is-open in site.js
   (no inline styles — CSP-safe). Hidden via display:none so it leaves the a11y tree when closed. */
.shot-lightbox {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 1080;
  padding: 2rem;
  align-items: center;
  justify-content: center;
  background: rgba(15, 23, 42, .82);
}
.shot-lightbox.is-open { display: flex; }

.shot-lightbox-frame {
  width: min(1100px, 94vw);
  max-height: 92vh;
  padding: .85rem;
  border-radius: 1.1rem;
  background: linear-gradient(135deg, #e8eef8 0%, #9cc0ec 100%);
  box-shadow: 0 24px 60px -20px rgba(0, 0, 0, .6);
}

.shot-lightbox-img {
  display: block;
  width: 100%;
  height: auto;
  max-height: calc(92vh - 1.7rem);
  object-fit: contain;
  border-radius: .75rem;
  border: 1px solid #e2e8f0;
  box-shadow: 0 12px 30px -10px rgba(30, 45, 64, .45);
}

.shot-lightbox-close {
  position: absolute;
  top: 1rem;
  right: 1.25rem;
  width: 2.5rem;
  height: 2.5rem;
  border: none;
  border-radius: 50%;
  background: rgba(255, 255, 255, .9);
  color: #1e2d40;
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
}
.shot-lightbox-close:hover,
.shot-lightbox-close:focus-visible {
  background: #fff;
  outline: 2px solid #82b3eb;
  outline-offset: 2px;
}

/* On phones a landscape screenshot can't grow past the viewport width, so go nearly full-bleed and tuck
   the close button into the corner. */
@media (max-width: 575.98px) {
  .shot-lightbox { padding: .75rem; }
  .shot-lightbox-frame { width: 97vw; padding: .5rem; }
  .shot-lightbox-close { top: .5rem; right: .5rem; }
}

/* Lock background scroll while the lightbox is open (class on <html>, not an inline style). */
.shot-lightbox-open { overflow: hidden; }

@media (max-width: 767.98px) {
  .em-chapter-body {
    grid-template-columns: 1fr;
    gap: 1.5rem;
  }
  .em-chapter-copy p {
    max-width: none;
  }
}

/* Desktop rebalance (EventManagementChapterBalance-1): on lg+ the chapter shifts from a 50/50 split
   to ~5:7 text/media with a tighter gap, and the copy fills a bounded ~27rem text column (≈50ch)
   instead of sitting capped at 46ch inside a half-width column. That closes the wide empty "river"
   between the story copy and the reserved screenshot frame so they read as one connected unit. The
   text column stays a fixed, readable measure while the media column grows on very wide screens. md
   (768–991px) keeps the 50/50 split so the frame doesn't get cramped; mobile is unchanged. */
@media (min-width: 992px) {
  .em-chapter-body {
    grid-template-columns: minmax(0, 27rem) minmax(0, 1fr);
    gap: 1.5rem;
  }
  .em-chapter-copy p {
    max-width: none;
  }
}

@media (max-width: 575.98px) {
  .em-chapter {
    padding: 1.25rem;
  }
  .em-chapter-media {
    min-height: 8rem;
  }
}

/* Everything stays connected (EventManagementCloseout-1): the "ones" read as one connected thing —
   the repetition of "one" is the message — a calm inline row, NOT a feature-card grid. */
.em-connected-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: .75rem 1.5rem;
}

.em-connected-item {
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  font-weight: 600;
  font-size: 1rem;
  color: #1f2937;
}

.em-connected-item i {
  width: 1.25rem;
  text-align: center;
  color: #1d4ed8;
  font-size: 1rem;
}

.em-connected-closer {
  margin-top: 1.5rem;
  margin-bottom: 0;
  max-width: 60ch;
}

/* Class Management cross-reference (EventManagementCloseout-1): an understated strip placed after the
   CTA — a calm contained panel (icon + text + inactive pointer) that transitions toward the future
   Class Management page without competing with the Request Access conversion above it. The heading is
   intentionally smaller than .mk-section-title so the strip stays quiet. */
.em-classref {
  margin-top: 2.5rem;
  margin-bottom: 2.5rem;
}

.em-classref-inner {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  padding: 1.5rem 1.75rem;
  background: #fff;
  border: 1px solid #e9eef5;
  border-radius: 1rem;
}

.em-classref-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3rem;
  height: 3rem;
  flex-shrink: 0;
  border-radius: 50%;
  background: #eef4fb;
  color: #1d4ed8;
  border: 1px solid #dbe5f1;
}

.em-classref-icon i {
  font-size: 1.25rem;
}

.em-classref-body {
  flex: 1 1 auto;
}

.em-classref-title {
  font-size: 1.125rem;
  font-weight: 700;
  color: #111827;
  margin: 0 0 .35rem;
}

.em-classref-text {
  color: #6c757d;
  font-size: .9375rem;
  margin: 0;
  max-width: 70ch;
}

.em-classref-cta {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .4rem;
}

@media (max-width: 767.98px) {
  .em-classref-inner {
    flex-direction: column;
    align-items: flex-start;
    gap: 1rem;
  }
}

/* Audience categories as compact organization-type tiles (not filter chips). */
.mk-audience-tile {
  display: flex;
  align-items: center;
  gap: .65rem;
  height: 100%;
  background: #fff;
  border: 1px solid #e6edf4;
  border-radius: .625rem;
  padding: .8rem .9rem;
  font-size: .9375rem;
  line-height: 1.3;
  color: #344054;
}

.mk-audience-tile i {
  flex-shrink: 0;
  width: 1.25rem;
  text-align: center;
  color: #1e3a5f;
  font-size: 1rem;
}

.mk-step {
  height: 100%;
}

.mk-step-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  background: #e9eff7;
  color: #1e3a5f;
  font-weight: 700;
  font-size: 1.0625rem;
  margin-bottom: .875rem;
}

.mk-step-title {
  font-size: 1.0625rem;
  font-weight: 600;
  color: #212529;
  margin-bottom: .25rem;
}

.mk-step-text {
  font-size: .9375rem;
  color: #6c757d;
  line-height: 1.6;
  margin-bottom: 0;
}

.mk-card {
  height: 100%;
  background: #fff;
  border: 1px solid #e6edf4;
  border-radius: .75rem;
  padding: 1.5rem;
}

.mk-card--soon {
  background: #fbfcfe;
}

.mk-card-head {
  display: flex;
  align-items: center;
  gap: .6rem;
  margin: .625rem 0 .375rem;
}

/* Element+class selector (i.mk-card-icon) raises specificity above Font Awesome's
   `.fa-solid { display: inline-block }`, which loads after site.css and would otherwise win at
   equal specificity and disable the flex centering. line-height:1 prevents vertical glyph drift. */
i.mk-card-icon {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  background: #eef2f7;
  color: #1e3a5f;
  font-size: 1rem;
  line-height: 1;
  text-align: center;
}

.mk-card--soon .mk-card-icon {
  background: #f1f3f5;
  color: #9aa4b2;
}

.mk-card-title {
  font-size: 1.0625rem;
  font-weight: 600;
  color: #212529;
  margin: 0;
}

.mk-card-text {
  font-size: .9375rem;
  color: #495057;
  line-height: 1.6;
  margin-bottom: 0;
}

.mk-final-title {
  font-size: 1.5rem;
  font-weight: 700;
  color: #111827;
  margin-bottom: .5rem;
}

/* Final CTA: a calm light band (inherits .hp-org-cta's light background + top border) with extra
   padding for separation. Navy primary + navy-outline secondary keep button styling consistent
   with nav and hero. */
.mk-final-cta {
  margin-top: 1.5rem;
  padding-top: 3rem;
  padding-bottom: 3rem;
}

.mk-final-text {
  color: #6c757d;
  max-width: 60ch;
}

/* PublicFooterPolish-3: text-focused closing CTA — a left-aligned, width-constrained content block
   anchored to the container's left edge (no icon). Reads as product copy rather than a centered
   marketing banner. Button classes (.btn-mk-primary / .btn-mk-outline) are unchanged. */
.mk-final-inner {
  max-width: 640px;
}

.mk-tag {
  display: inline-block;
  font-size: .6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .05em;
  padding: .15rem .5rem;
  border-radius: 999px;
}

.mk-tag--now {
  background: #e7f5ec;
  color: #157347;
}

.mk-tag--early {
  background: #fff4e0;
  color: #9a6700;
}

.mk-tag--soon {
  background: #eef1f5;
  color: #5c636a;
}

/* ── Org page share buttons ──────────────────────────────────────────── */

.op-share-actions {
  display: flex;
  justify-content: flex-end;
  gap: .375rem;
  flex-wrap: wrap;
  margin-top: .75rem;
  padding-bottom: .25rem;
}

.op-page:not(.op-has-banner) .op-share-actions {
  max-width: 1320px;
  margin-left: auto;
  margin-right: auto;
  padding-left: 1rem;
  padding-right: 1rem;
}

.op-share-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 1.5px solid #adb5bd;
  color: #6c757d;
  background: transparent;
  text-decoration: none;
  font-size: .875rem;
  line-height: 1;
  cursor: pointer;
  padding: 0;
  transition: border-color .15s, color .15s, background-color .15s;
}

.op-share-button:hover {
  border-color: #343a40;
  color: #212529;
  background: #f8f9fa;
  text-decoration: none;
}

.op-share-button:focus-visible {
  outline: 3px solid #258cfb;
  outline-offset: 2px;
}

/* ── Org page profile links (Connect section) ────────────────────────── */

.op-profile-links {
  max-width: 1320px;
  margin-left: auto;
  margin-right: auto;
  margin-top: 2.5rem;
  margin-bottom: 2.5rem;
  padding: 1.5rem;
  background: #fff;
  border: 1px solid #dbe5f1;
  border-radius: .75rem;
}

.op-profile-links-label {
  font-size: .75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: #6c757d;
  margin-bottom: .875rem;
}

.op-profile-links-list {
  display: flex;
  flex-direction: column;
  gap: .5rem;
}

@media (min-width: 576px) {
  .op-profile-links-list {
    flex-direction: row;
    flex-wrap: wrap;
  }
}

.op-profile-link {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  padding: .5rem 1.375rem;
  border: 1.5px solid #343a40;
  border-radius: 2rem;
  color: #212529;
  background-color: transparent;
  font-size: .9375rem;
  font-weight: 500;
  text-decoration: none;
  line-height: 1.4;
  transition: background-color .15s, color .15s;
}

.op-profile-link:hover {
  background-color: #212529;
  color: #fff;
  text-decoration: none;
}

.op-profile-link:focus-visible {
  outline: 3px solid #258cfb;
  outline-offset: 2px;
}

.op-profile-link-icon {
  flex-shrink: 0;
  width: 1.125rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Org page editor — sticky jump nav on desktop */

@media (min-width: 992px) {
  .org-page-editor-nav-sticky {
    position: sticky;
    top: 1rem;
  }
}

/* Org page editor — nav link default + active state */

.org-page-editor-nav a {
  color: #6c757d;
  transition: color 0.15s;
}

.org-page-editor-nav a.ope-nav-active {
  color: #212529;
  font-weight: 600;
}

@media (min-width: 992px) {
  .org-page-editor-nav a {
    padding-left: 0.5rem;
    border-left: 2px solid transparent;
    transition: color 0.15s, border-color 0.15s;
  }
  .org-page-editor-nav a.ope-nav-active {
    border-left-color: #0d6efd;
  }
}

/* Org page editor — floating back to top button */

.org-page-editor-backtop {
  position: fixed;
  bottom: 1.5rem;
  right: 1.5rem;
  width: 2.5rem;
  height: 2.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #6c757d;
  color: #fff;
  border-radius: 50%;
  text-decoration: none;
  font-size: 1rem;
  z-index: 1030;
  box-shadow: 0 2px 6px rgba(0, 0, 0, .2);
  opacity: 0.75;
  transition: opacity 0.15s;
}

.org-page-editor-backtop:hover {
  opacity: 1;
  color: #fff;
}

/* ── OrgDesk Event Edit — horizontal section nav ────────────────────── */

.event-edit-section-nav {
  display: flex;
  flex-wrap: nowrap;
  gap: .125rem;
  overflow-x: auto;
  scrollbar-width: thin;
  -webkit-overflow-scrolling: touch;
  background: #fff;
  border-bottom: 1px solid #dee2e6;
  padding-bottom: .375rem;
  margin-bottom: 1.25rem;
  position: sticky;
  top: 0;
  z-index: 10;
}

.event-edit-section-nav a {
  flex-shrink: 0;
  padding: .3125rem .75rem;
  font-size: .875rem;
  color: #6c757d;
  text-decoration: none;
  border-radius: .25rem;
  white-space: nowrap;
  transition: color .15s, background-color .15s;
}

.event-edit-section-nav a:hover {
  color: #212529;
  background-color: #f1f3f5;
}

.event-edit-section-nav a:focus-visible {
  outline: 2px solid #0d6efd;
  outline-offset: -2px;
}

.event-edit-section-nav a.event-edit-nav-active {
  color: #212529;
  font-weight: 600;
  background-color: #e8f0fe;
}

/* Push anchor targets below the sticky section nav */
#panel-publish,
#panel-event-details,
#panel-schedule,
#panel-location,
#panel-registration,
#panel-donations,
#panel-checkin,
#panel-internal,
/* Organizer capabilities jump-link targets (OrganizerCapabilitiesAlignment-1) reuse the
   same sticky-nav offset so anchored sections clear the sticky section nav. */
#cap-donation,
#cap-fee-payments,
#cap-ticketing,
#cap-attendance,
#cap-audience-messaging,
#cap-direct-create {
  scroll-margin-top: 2.5rem;
}

/* OrgDesk Event Edit — floating back-to-top button */

.event-edit-back-to-top {
  position: fixed;
  bottom: 1.5rem;
  right: 1.5rem;
  width: 2.5rem;
  height: 2.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #6c757d;
  color: #fff;
  border-radius: 50%;
  text-decoration: none;
  font-size: 1rem;
  z-index: 1030;
  box-shadow: 0 2px 6px rgba(0, 0, 0, .2);
  opacity: 0.75;
  transition: opacity 0.15s;
}

.event-edit-back-to-top:hover {
  opacity: 1;
  color: #fff;
}

/* OrgDesk Event Edit — publish card subtle tint */

.event-edit-publish-card {
  background-color: var(--bs-tertiary-bg, #f8f9fa);
}

/* ── Operational search control ──────────────────────────────────────── */

.operational-search {
  max-width: 720px;
}

/* ── Front Desk mobile polish ────────────────────────────────────────── */

.fd-card-registered {
  background-color: #f3f7f4;
}

.fd-selected {
  background-color: #dbeafe;
  color: #1e40af;
  border-color: #93c5fd;
}

.fd-selected:hover {
  background-color: #bfdbfe;
  color: #1e3a8a;
  border-color: #60a5fa;
}

.fd-page-dot {
  display: inline-block;
  width: .625rem;
  height: .625rem;
  border-radius: 50%;
  background-color: #198754;
  flex-shrink: 0;
}

.fd-page-dot-closed {
  background-color: #6c757d;
}

.fd-actor-line {
  font-size: 0.75rem;
}

.fd-visitor-badge {
  background-color: #dbeafe;
  color: #1e40af;
  border: 1px solid #bfdbfe;
}

/* FrontDeskRedesign-1: the search input is the page's primary action, so the field stays large for
   touch — but the placeholder should read as a quiet hint, not compete with a typed value. Dial its
   size and weight back down from the input-group-lg default. */
.fd-search-input::placeholder {
  font-size: 1.1rem;
  font-weight: 400;
  opacity: 1;
  color: #9aa0a6;
}

/* FrontDeskPolish-1: attendee search is the primary operator action — give the field and Search button a
   taller touch target and more visual weight. The control's weight (not added whitespace) is what
   separates the search area from the summary below. */
.fd-search-group .form-control,
.fd-search-group .btn {
  min-height: 3.5rem;
  padding-top: 0.6rem;
  padding-bottom: 0.6rem;
}

/* FrontDeskRedesign-1: informational empty-state — a calm, centred block with breathing room rather
   than a line of muted text crammed under the search box. */
.fd-empty-icon {
  font-size: 2rem;
  opacity: 0.45;
  display: block;
}

@media (max-width: 767.98px) {
  .fd-event-card-row {
    flex-direction: column;
  }
  .fd-event-controls {
    align-items: flex-start !important;
    width: 100%;
    border-top: 1px solid #dee2e6;
    padding-top: 0.75rem;
    margin-top: 0.5rem;
  }
  /* FrontDeskRedesign-1: keep the day-selector buttons inside the compact session card comfortable to
     tap during live door check-in without changing the wrap-based layout. */
  .fd-day-selector .btn {
    min-height: var(--el-touch-min);
    display: inline-flex;
    align-items: center;
  }
  .fd-primary-btn {
    font-size: 1rem;
    padding: 0.5rem 1rem;
  }
  /* MobileCheckInErgonomics-1 — wire the 44px touch token (--el-touch-min) to the per-attendee check-in
     action row so every action (Check In/Out, Leave/Join Session, Undo, Add Donation) is a comfortable
     touch target during live door check-in. A slightly wider gap separates the primary action from the
     adjacent Undo to reduce accidental taps. Primary actions also dropped btn-sm (per the Front Desk design
     doc). No layout, workflow, or business-logic change. */
  .fd-attendee-actions {
    gap: 0.75rem !important;
  }
  .fd-attendee-actions .btn {
    min-height: var(--el-touch-min);
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  /* EM2-18 (§6.18 FR-18.3) — ONE rule for the whole event-day tap surface, rather than a growing list of
     exceptions. `el-eventday` marks the content column of the surfaces an operator works from at a door —
     Front Desk, Front Door, Scanner, Scan, Walk-in, Attendees and Add donation — and on a phone EVERY
     action on them clears 44px.

     The roster is not a judgement about which pages "feel like" check-in; it is exactly the set that renders
     `_EventOperatorBottomNav`, and a test derives it rather than listing it. The EM2-18 review's finding R1
     is why: the first roster was picked by purpose, and the two pages the bottom nav LINKS TO — Attendees
     and Add donation — kept the 29.2px nav the slice had just called the most-tapped thing on the event-day
     path.

     Read against what the phone-grain pass actually measured, that is what "touch targets ≥ 44px on
     check-in/scan actions" has to mean: on these screens the acts and the ways between them are
     interleaved, so the phone-only bottom nav (29px), the gear that opens and closes check-in (27×29),
     the Front Door camera toggle (29px), the way OUT of the scanner and the link ACROSS to the desk were
     all under the minimum, and an operator mid-queue does not experience them as a different class of
     thing from the Check In button beside them.

     `btn-sm` keeps its type scale — only the tap box grows — so no row reflows and no label wraps. The
     `min-width` is for the icon-only gear, which was 27px wide. Deliberately NOT extended to the app-wide
     navbar toggle: that is site chrome shared with every public page, and it is recorded as a P2 in the
     sheets rather than changed from an event-day slice. */
  .el-eventday .btn {
    min-height: var(--el-touch-min);
    min-width: var(--el-touch-min);
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
  .event-operator-bottom-nav .d-flex {
    gap: 0.5rem !important;
  }
}

/* ── Admin layout footer ─────────────────────────────────────────────── */

.admin-footer {
  /* OrganizerShellPolish-1: a step deeper than the context strip (#f8f9fa) so the footer
     stops reading as the strip's twin, with muted-navy text that faintly echoes the header
     — a quiet bookend, deliberately not a second dark slab. */
  background-color: var(--el-footer-bg);
  border-top: 1px solid #dde2e8;
  color: rgba(30, 45, 64, .65);
  padding: 1.75rem 0;
  font-size: .875rem;
}

/* ── Admin layout — back to top button ───────────────────────────────── */

.admin-back-to-top {
  position: fixed;
  bottom: 1.5rem;
  right: 1.5rem;
  width: 2.75rem;
  height: 2.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #1e2d40;
  color: #fff;
  border: none;
  border-radius: 50%;
  font-size: 1.125rem;
  line-height: 1;
  z-index: 1035;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .3);
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transition: opacity .2s, background .15s;
}

.admin-back-to-top.is-visible {
  opacity: 1;
  pointer-events: auto;
}

.admin-back-to-top:hover {
  background: #111e2b;
  color: #fff;
}

/* ── Public/client layout — back to top button ───────────────────────────
   Same behavior as the admin button (.admin-back-to-top), but in the EventsLog
   orange theme used by the header avatar (#f97316). Public layout only. */
.public-back-to-top {
  position: fixed;
  bottom: 1.5rem;
  right: 1.5rem;
  width: 2.75rem;
  height: 2.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #f97316;
  color: #fff;
  border: none;
  border-radius: 50%;
  font-size: 1.125rem;
  line-height: 1;
  z-index: 1035;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .3);
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transition: opacity .2s, background .15s;
}

.public-back-to-top.is-visible {
  opacity: 1;
  pointer-events: auto;
}

.public-back-to-top:hover {
  background: #ea580c;
  color: #fff;
}

.public-back-to-top:focus-visible {
  outline: 2px solid #0d6efd;
  outline-offset: 2px;
}

/* ── Public site footer ───────────────────────────────────────────────── */

.site-footer {
  background-color: #282A35;
  color: #f8f9fa;
}

.site-footer-muted {
  color: rgba(255, 255, 255, .75);
  font-size: .9rem;
}

.site-footer-link {
  color: rgba(255, 255, 255, .85);
  text-decoration: none;
}

.site-footer-link:hover {
  color: #fff;
  text-decoration: underline;
}

.site-footer-link:focus-visible {
  outline: 2px solid #9ec5fe;
  outline-offset: 2px;
  border-radius: 2px;
}

/* Footer brand column (PublicFooterPolish-1; logo now a CSS wordmark — see .site-brand) */
.site-footer-brand-text {
  color: rgba(255, 255, 255, .70);
  font-size: .9rem;
  max-width: 34ch;
  margin-top: .75rem;
  margin-bottom: 0;
}

/* Footer column headings + link lists. Headings carry the column separation (PublicFooterPolish-2,
   Option B): brighter, heavier, and a touch more letter-spacing rather than vertical divider lines. */
.site-footer-heading {
  color: #fff;
  font-size: .8125rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  margin-bottom: 1rem;
  /* PWD-5 (review RC1): the five footer group labels moved from <h2> to <p> so they stop inflating every
     public page's heading outline. Bootstrap's reboot gives h1-h6 line-height 1.2 while a <p> inherits the
     body's 1.5, so the swap made each label ~3.9px taller and the slice's "rendered appearance is unchanged"
     claim was ~4px per label short of true. Restated here, the rule now carries the line-height itself and
     the claim holds for whichever element the class is on. */
  line-height: 1.2;
}

/* Decorative footer inline icon (e.g. envelope) — inherits the muted footer tone, sits before its
   link with a small gap. aria-hidden in markup keeps it out of the accessibility tree. */
.site-footer-icon {
  color: rgba(255, 255, 255, .55);
  margin-right: .4rem;
}

.site-footer-links {
  list-style: none;
  padding-left: 0;
  margin-bottom: 0;
}

.site-footer-links li + li {
  margin-top: .5rem;
}

/* Bottom bar divider */
.site-footer-bottom {
  border-top: 1px solid rgba(255, 255, 255, .12);
}

/* ── Event context sidebar navigation ────────────────────────────────── */

.event-sidebar {
  padding: .75rem 0;
}

@media (min-width: 768px) {
  .event-sidebar {
    position: sticky;
    top: 1rem;
    /* OnboardingPolish-1 follow-up: the manager rail gained the Messages item (~36px taller), pushing it
       just past the old `100vh - 5rem` cap so a prominent scrollbar showed at common desktop heights
       (~viewport 798–834px) where the content only barely overflowed. Reclaiming the over-reserved space
       (5rem → 2rem) drops the overflow threshold below the pre-Messages baseline, so the rail fits without
       a bar at normal heights; on genuinely short viewports it still scrolls, now with an unobtrusive thin
       scrollbar instead of the default heavy one. CSS-only; no items removed, no order/behavior change. */
    max-height: calc(100vh - 2rem);
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: rgba(33, 37, 41, .28) transparent;
  }
}

.event-sidebar-group-label {
  font-size: .8125rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: #495057;
  padding: 0 .75rem;
  margin-top: 0;
  margin-bottom: .375rem;
}

.event-sidebar-group + .event-sidebar-group {
  margin-top: 1.25rem;
  border-top: 1px solid #e9ecef;
  padding-top: .5rem;
}

.event-sidebar-nav li {
  list-style: none;
}

.event-sidebar-nav a,
.event-sidebar-nav .event-sidebar-item--disabled {
  display: block;
  padding: .4375rem .75rem;
  font-size: .875rem;
  color: #495057;
  text-decoration: none;
  /* RailComfort-1: right-rounded selected bar. Left corners stay modest (4px) so the
     blue left border reads anchored to the rail; the right edge softens (8px). The 4px
     transparent left border is reserved on every item, so activating a row adds no shift. */
  border-radius: .25rem .5rem .5rem .25rem;
  border-left: 4px solid transparent;
  transition: color .15s, background-color .15s;
}

.event-sidebar-nav a:hover {
  color: #212529;
  background-color: #f1f3f5;
  text-decoration: none;
}

.event-sidebar-nav a:focus-visible {
  outline: 2px solid #0d6efd;
  outline-offset: -2px;
  border-radius: .25rem .5rem .5rem .25rem;
}

.event-sidebar-nav a[aria-current="page"] {
  color: #212529;
  font-weight: 600;
  background-color: #e8f0fe;
  border-left-color: #0d6efd;
}

.event-sidebar-item--disabled {
  color: #adb5bd;
  cursor: default;
}

.event-sidebar-item--disabled-reason {
  display: block;
  font-size: .7rem;
  color: #adb5bd;
  padding: 0 .75rem .3125rem 1rem;
  line-height: 1.3;
}

.event-sidebar-sub-item a,
.event-sidebar-sub-item .event-sidebar-item--disabled {
  padding-left: 1.75rem;
  /* RailComfort-1: keep nested rows compact so the longest (admin event) rail stays
     usable — only top-level rows get the roomier vertical padding. */
  padding-top: .3125rem;
  padding-bottom: .3125rem;
  font-size: .8125rem;
}

.event-sidebar-escape {
  padding: .5rem .75rem;
  border-top: 1px solid #e9ecef;
  margin-top: .75rem;
}

.event-sidebar-escape a {
  font-size: .8125rem;
  color: #6c757d;
  text-decoration: none;
}

.event-sidebar-escape a:hover {
  color: #212529;
  text-decoration: underline;
}

/* Mobile typography and tap density polish */
@media (max-width: 767.98px) {
  .event-sidebar-nav a,
  .event-sidebar-nav .event-sidebar-item--disabled {
    padding-top: .8125rem;
    padding-bottom: .8125rem;
    font-size: 1rem;
    font-weight: 500;
  }

  .event-sidebar-nav a {
    color: #2f343b;
  }

  .event-sidebar-sub-item a,
  .event-sidebar-sub-item .event-sidebar-item--disabled {
    font-size: .9rem;
  }

  .event-sidebar-group-label {
    font-size: .875rem;
  }
}

/* Event Menu trigger button — mobile only (d-md-none keeps it off desktop).
   EM2-18 (§6.18 FR-18.3): measured at 39.5px. It is phone-only by construction and it is how an operator
   reaches every other event surface from a check-in page, so it takes the same 44px minimum as the bottom
   nav it pairs with. */
.event-menu-trigger {
  --bs-btn-color: #343a40;
  --bs-btn-border-color: #6c757d;
  padding-top: .5rem;
  padding-bottom: .5rem;
  font-weight: 500;
  min-height: var(--el-touch-min);
}

/* Responsive column separator — md+: right border */
.event-sidebar-col {
  padding-bottom: 0;
  margin-bottom: 0;
}

@media (min-width: 768px) {
  .event-sidebar-col {
    border-right: 1px solid #dee2e6;
  }
}

/* ── Mobile identity-card tightening — event detail + organizer ──────── */

@media (max-width: 575.98px) {
  .ep-has-banner .ep-header-group {
    padding: 0 1rem 1rem;
  }

  .ep-has-banner .ep-logo-wrap {
    margin-top: -28px;
    margin-bottom: .25rem;
  }

  .ep-has-banner .ep-logo {
    width: 64px;
    height: 64px;
  }

  .ep-has-banner .ep-identity {
    gap: .5rem;
  }

  .ep-title {
    font-size: 1.5rem;
  }

  .ep-meta {
    margin-top: .625rem;
    margin-bottom: .625rem;
  }

  .ep-share-actions {
    margin-top: 1rem;
    gap: .375rem;
    justify-content: flex-end;
  }

  .op-has-banner .op-identity-group {
    padding: 0 1rem 1rem;
  }

  .op-has-banner .op-logo-wrap {
    margin-top: -28px;
    margin-bottom: .25rem;
  }

  .op-has-banner .op-logo {
    width: 64px;
    height: 64px;
  }

  .op-has-banner .op-identity {
    gap: .5rem;
  }

  .op-heading {
    font-size: 1.5rem;
  }

  .op-share-actions {
    margin-top: .5rem;
    gap: .375rem;
    justify-content: flex-end;
  }
}

.event-operator-bottom-nav {
  margin-top: 4.5rem;
  padding-top: 1.25rem;
  border-top: 1px dashed #ccc;
}

.event-operator-bottom-nav .btn {
  min-width: 4.5rem;
}

/* ============================================================================
   Recurring schedule page (/s/{slug}-{id}) — RecurringEvents-PublicUX-SchedulePage-1
   Scoped s-* classes only. Recurring-only page; no bleed into op-*/ep-*/one-off
   pages. Reuses .op-share-* (share buttons) and .hp-event-list/.op-event-card
   (upcoming cards) read-only, without modifying them.
   ============================================================================ */

/* Banner — fills the Bootstrap container width (matches the organizer hero banner) */
.s-banner {
  width: 100%;
  height: 200px;
  overflow: hidden;
  background-color: #e9ecef;
  border-radius: .5rem;
  display: block;
}

.s-banner > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

@media (min-width: 576px) {
  .s-banner {
    height: 300px;
  }
}

/* Hero / identity */
.s-hero {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  /* Tight gap so the Next Session block reads as a continuation of the hero. */
  margin-bottom: 1.25rem;
}

/* No banner: a soft hero band so the page still looks intentional */
.s-hero--plain {
  background: #f8f9fa;
  border: 1px solid #e9ecef;
  border-radius: .5rem;
  padding: 1.75rem 1.5rem;
  margin-top: .25rem;
}

/* With banner: white card that overlaps the banner slightly */
.s-hero--has-banner {
  background: #fff;
  border-radius: .5rem;
  box-shadow: 0 1px 6px rgba(0, 0, 0, .09);
  padding: 1.25rem 1.5rem;
  margin-top: -2.5rem;
  position: relative;
  z-index: 1;
}

.s-hero-main {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  min-width: 0;
  flex: 1 1 auto;
}

.s-logo-wrap {
  flex-shrink: 0;
}

.s-logo {
  width: 72px;
  height: 72px;
  object-fit: cover;
  border-radius: 50%;
  background-color: #f8f9fa;
  display: block;
}

.s-hero--has-banner .s-logo {
  border: 3px solid #fff;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .18);
}

@media (min-width: 576px) {
  .s-logo {
    width: 88px;
    height: 88px;
  }
}

.s-hero-text {
  min-width: 0;
}

.s-eyebrow {
  text-transform: uppercase;
  letter-spacing: .04em;
  font-size: .75rem;
  font-weight: 600;
  color: var(--bs-secondary-color, #6c757d);
  margin: 0 0 .25rem;
}

.s-title {
  font-size: 1.6rem;
  line-height: 1.2;
  margin: 0 0 .35rem;
}

@media (min-width: 576px) {
  .s-title {
    font-size: 2rem;
  }
}

.s-org {
  margin: 0;
  color: var(--bs-secondary-color, #6c757d);
}

/* WIR-8: one-line workflow promise under the title ("Something you join" / "Pick a date, get your
   seats" / "Come along, here's the rhythm"). States identity before behaviour; subordinate to the title. */
.s-promise {
  font-size: 1.0625rem;
  line-height: 1.4;
  color: var(--bs-body-color, #212529);
  margin: 0 0 .35rem;
}

/* RO2-2 (a): the Recurring Event's rhythm line — the offering's identity stated in the hero ("Every
   Sunday & Friday · 10:00 AM · Plant Street Market"). Same register as the Class facts line below: one
   quiet legible line that never competes with the title. */
.s-rhythm {
  font-size: 1rem;
  line-height: 1.4;
  color: #343a40;
  margin: 0 0 .35rem;
}

/* RO-15 (VXM §13.2): the Class's advertised facts — "Term: Sep 1 – Dec 17, 2026 · $180 · Enrollment closes …".
   One quiet line under the promise: it carries the numbers a visitor decides on, so it is legible and plain
   rather than decorated, and it must never compete with the title above it. */
.s-class-facts {
  font-size: 1rem;
  line-height: 1.4;
  color: #343a40;
  margin: 0 0 .35rem;
}

/* The closing boundary beside the Enroll button. Secondary to the action, never a warning colour. */
.s-enroll-window {
  margin-top: .5rem;
  font-size: .9375rem;
  color: var(--bs-secondary-color, #6c757d);
}

.s-hero-actions {
  flex-shrink: 0;
}

/* Content — spans the full container width so every section (Next session, When it
   meets, Upcoming dates, Hosted by) shares the same left/right rhythm as the hero/banner
   instead of floating in a narrower column. */
.s-content {
  width: 100%;
}

.s-section {
  margin-bottom: 2.25rem;
}

.s-section-title {
  font-size: 1.15rem;
  font-weight: 600;
  margin: 0 0 .9rem;
  display: flex;
  align-items: center;
  gap: .5rem;
}

.s-section-icon {
  /* Charcoal, not link-blue — supports the heading without drawing attention. */
  color: #495057;
  font-size: 1rem;
}

.s-section-lead {
  color: var(--bs-secondary-color, #6c757d);
  font-size: .9375rem;
  margin: 0 0 1rem;
}

/* Date-context acknowledgment (RO-6) — shown when a visitor arrives from a link that pointed at ONE
   date. It sits directly under the hero, above everything else, because it answers the question the
   visitor arrives with ("I clicked a specific date — where is it?"). A quiet note, not an alert: the
   common case is a perfectly ordinary upcoming date, and only the terminal states earn a warmer tint. */
.s-date-context {
  border: 1px solid #e9ecef;
  border-left: 3px solid #adb5bd;
  border-radius: .5rem;
  background: #f8f9fa;
  padding: .85rem 1rem;
  margin: 0 0 1.5rem;
}

.s-date-context-headline {
  font-weight: 600;
  color: #212529;
  margin: 0;
}

.s-date-context-detail {
  color: #495057;
  font-size: .9375rem;
  margin: .2rem 0 0;
}

/* RO-10 (PD §5): the date's own description, when it holds a description exception. Body-weight text, set apart
   from the acknowledgment's factual detail line above it — it is the organizer's words, not a fact about state. */
.s-date-context-description {
  color: #212529;
  font-size: .9375rem;
  margin: .55rem 0 0;
  white-space: pre-wrap;
}

.s-date-context-jump {
  font-size: .9375rem;
  color: var(--bs-secondary-color, #6c757d);
  margin: .35rem 0 0;
}

/* VR-4: a cancelled date, in its place in the sequence. The strike + muted tone are decoration only — the badge
   carries the word, so the row states its condition rather than relying on a visual that a screen reader cannot
   announce. The row is a <div>, not an <a>: nothing to go to, nothing to do. Its note (VR-3) keeps the ordinary
   note styling below, because the explanation is the point. */
.s-upcoming-cancelled {
  color: var(--bs-secondary-color, #6c757d);
  cursor: default;
}

/* Struck AND de-linked in appearance. The date normally carries the contextual link colour because it normally
   IS a link; on a cancelled row it is not, and leaving it blue would keep inviting the click the row exists to
   prevent. Everything in the row takes the muted tone. */
.s-upcoming-cancelled .s-upcoming-date,
.s-upcoming-cancelled .s-upcoming-time,
.s-upcoming-cancelled .s-upcoming-loc {
  text-decoration: line-through;
  color: inherit;
}

.s-upcoming-cancelled-badge {
  display: inline-block;
  font-size: .8125rem;
  font-weight: 600;
  line-height: 1.2;
  padding: .1rem .45rem;
  border-radius: .25rem;
  color: #b02a37;
  background: #f8d7da;
  border: 1px solid #f1aeb5;
  text-decoration: none;
}

/* EM2-11 (§6.12 FR-11.3) — the postponed row badge. Same geometry as its cancelled sibling above so the two
   sit consistently in a mixed list, and a distinct warm palette so they are never mistaken for one another.
   The row itself stays a link and is NOT struck through: the date is still expected to happen. */
.s-upcoming-postponed-badge {
  display: inline-block;
  font-size: .8125rem;
  font-weight: 600;
  line-height: 1.2;
  padding: .1rem .45rem;
  border-radius: .25rem;
  color: #664d03;
  background: #fff3cd;
  border: 1px solid #ffe69c;
  text-decoration: none;
}

/* VR-3: one shared look for the per-date public note wherever it appears (acknowledgment, upcoming row, Show
   funnel). The ⓘ marks it as an aside about this date rather than part of the date's own facts; `pre-line`
   preserves the organizer's line breaks exactly as the /e body does, without admitting markup. */
.s-note-icon {
  color: var(--bs-secondary-color, #6c757d);
  margin-right: .4rem;
}

.s-date-context-note,
.s-upcoming-note {
  font-size: .9375rem;
  color: #212529;
  white-space: pre-line;
  margin: .55rem 0 0;
}

/* The row's own link carries .6rem/.9rem padding, so the note only needs to close the gap under it and align
   its text with the date above rather than restate the whole inset. */
.s-upcoming-note {
  margin-top: -.15rem;
  padding: 0 .9rem .6rem;
}

.s-showtime-notes {
  list-style: none;
  padding: 0;
  margin: .6rem 0 0;
}

/* `pre-line` belongs on the TEXT span, never on this row: the row holds several elements written on separate
   source lines, and preserving those newlines would break one sentence across three lines. */
.s-showtime-note {
  font-size: .9375rem;
  color: #212529;
  margin-top: .25rem;
}

.s-showtime-note-text {
  white-space: pre-line;
}

.s-showtime-note-time {
  font-weight: 600;
}

.s-showtime-note-sep {
  margin: 0 .3rem;
  color: var(--bs-secondary-color, #6c757d);
}

/* VR-2: the followed date's own public actions (Register / Donate), inside the acknowledgment. Buttons wrap on
   narrow screens rather than overflowing the aside; the block collapses to nothing when no action is offered. */
.s-date-context-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  margin: .7rem 0 0;
}

.s-date-context--upcoming { border-left-color: #0d6efd; }
.s-date-context--soldout  { border-left-color: #fd7e14; }
.s-date-context--ended    { border-left-color: #adb5bd; }
.s-date-context--cancelled {
  border-left-color: #dc3545;
  background: #fff5f5;
}

/* EM2-11 (§6.12 FR-11.3) — postponed is its OWN treatment, warm rather than red. A postponed date is still
   expected to happen; borrowing the cancelled palette would contradict the sentence inside the card. */
.s-date-context--postponed {
  border-left-color: #ffc107;
  background: #fff9e6;
}

/* EM2-11 — the "Rescheduled from …" line, in the date context and on an upcoming row. Quiet secondary text:
   it is orientation for someone holding the old date, not a headline. */
.s-date-context-rescheduled,
.s-upcoming-rescheduled {
  margin: .35rem 0 0;
  font-size: .875rem;
  color: var(--bs-secondary-color, #6c757d);
}

/* The referenced date, marked in place so the acknowledgment's "jump" link lands somewhere visibly
   distinct rather than on an identical-looking row. */
.s-upcoming-row--referenced {
  background: #eef5ff;
  box-shadow: inset 3px 0 0 #0d6efd;
}

.s-showtime-chip--referenced .s-chip {
  outline: 2px solid #0d6efd;
  outline-offset: 2px;
}

/* Activity summary (Phase 1.5) — a calm lead paragraph directly under the hero. */
.s-summary {
  font-size: 1.0625rem;
  line-height: 1.55;
  color: #343a40;
  margin: 0 0 1.75rem;
}

/* About body (Phase 1.5) — plain text; preserve author line breaks without raw HTML. Slightly
   larger type + more open line-height so longer descriptions read comfortably (no cards/panels). */
.s-about-body {
  white-space: pre-line;
  font-size: 1.0625rem;
  line-height: 1.7;
  color: #343a40;
}

/* Calendar (.ics) download link (Phase 1.5) — secondary action tied to the schedule list: sits
   between the upcoming-dates lead and the first month group, right-aligned on desktop. Stays a link
   (existing contextual text color via .public-content-link), never a button. */
.s-ics-download {
  text-align: right;
  font-size: .9375rem;
  margin: 0 0 1.1rem;
}

.s-ics-download a {
  font-weight: 600;
}

/* Neutral icon treatment matching the section-heading icons (.s-section-icon) so the calendar glyph
   reads as part of the site icon system; only the link text carries the contextual link color. */
.s-ics-icon {
  color: #495057;
}

/* Next session spotlight — the strongest informational block on the page, but a calm
   neutral surface (no accent border / tint) so it reads as a continuation of the hero,
   not a selected/alert card. */
.s-next-session {
  display: flex;
  align-items: stretch;
  gap: 1.1rem;
  /* Soft blue so the panel and the date badge share a matching cool treatment. */
  border: 1px solid #c7dceb;
  border-radius: .6rem;
  background: #eff6ff;
  padding: 1.25rem 1.4rem;
  margin-bottom: 2rem;
}

.s-next-badge {
  flex-shrink: 0;
  width: 76px;
  border-radius: .5rem;
  /* Soft blue accent matching the outer panel — readable dark-blue text,
     not a dark "stat widget" tile. */
  background: #c2e7ff;
  border: 1px solid #9cdbf1;
  color: #08008f;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: .5rem 0;
  line-height: 1.1;
}

.s-next-badge-month {
  text-transform: uppercase;
  font-size: .8125rem;
  font-weight: 600;
  letter-spacing: .03em;
}

.s-next-badge-day {
  font-size: 1.6rem;
  font-weight: 700;
}

.s-next-badge-year {
  font-size: .75rem;
  opacity: .85;
}

.s-next-body {
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
}

.s-next-eyebrow {
  text-transform: uppercase;
  letter-spacing: .04em;
  font-size: .75rem;
  font-weight: 700;
  color: #495057;
  margin: 0 0 .15rem;
}

.s-next-title {
  font-size: 1.2rem;
  font-weight: 600;
  text-decoration: none;
  color: var(--bs-body-color, #212529);
}

.s-next-title:hover {
  text-decoration: underline;
}

.s-next-meta {
  color: var(--bs-secondary-color, #6c757d);
  font-size: .9375rem;
  margin: .2rem 0 .4rem;
}

/* Relative-time line ("Starts in N days") — informational, warm to match the badge. */
.s-next-starts {
  font-weight: 600;
  color: #8f4700;
  margin: 0 0 .85rem;
}

.s-next-cta {
  align-self: flex-start;
}

/* VR-2: the next date's own actions in the spotlight. The card is a column flexbox, so the action row needs to
   be its own flex line to keep the buttons side by side and wrapping together. */
.s-next-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  align-self: flex-start;
  margin: .7rem 0 0;
}

.s-next-actions .s-next-cta {
  align-self: auto;
}

/* Recurrence-derived "Next scheduled meeting" fallback (no generated Event). Reuses the
   .s-next-session card; these two lines replace the linked title + "View this session" action. */
.s-next-meeting-date {
  font-size: 1.2rem;
  font-weight: 600;
  color: var(--bs-body-color, #212529);
  margin: 0 0 .2rem;
}

.s-next-meeting-note {
  color: var(--bs-secondary-color, #6c757d);
  font-size: .85rem;
  margin: .15rem 0 0;
}

/* Hosted-by — compact organizer trust block */
.s-organizer {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .85rem;
  border: 1px solid #e9ecef;
  border-radius: .5rem;
  background: #fff;
  padding: .85rem 1rem;
  margin-bottom: 2.25rem;
}

.s-organizer-logo {
  width: 44px;
  height: 44px;
  flex-shrink: 0;
  object-fit: cover;
  border-radius: 50%;
  background-color: #f8f9fa;
}

.s-organizer-text {
  min-width: 0;
  flex: 1 1 auto;
}

.s-organizer-eyebrow {
  text-transform: uppercase;
  letter-spacing: .04em;
  font-size: .7rem;
  font-weight: 600;
  color: var(--bs-secondary-color, #6c757d);
  margin: 0;
}

.s-organizer-name {
  font-weight: 600;
  font-size: 1.05rem;
  text-decoration: none;
  color: var(--bs-body-color, #212529);
}

a.s-organizer-name:hover {
  text-decoration: underline;
}

/* Led by — instructor/presenter cards (PublicProfiles-PublicRendering-1). Presentation only. */
/* ── Shared public form-card family ──────────────────────────────────────────
   One definition for the public bordered/tinted form panels so registration,
   class enrollment, and the contact page share a single look instead of drifting
   (ContactPage-VisualPolish-Implement-1; promoted in PublicEnrollment-VisualPolish-Implement-1).
   `.public-form-card` is the generic name; `.reg-card` is the original registration alias —
   both resolve here. Pair with Bootstrap's `border rounded p-3 mb-3` utilities in markup.
   Used by /e/.../register, /s/.../join, and /contact. */
.reg-card,
.public-form-card {
  background-color: #fbfcfe;
}

.reg-card .form-control,
.public-form-card .form-control {
  border-color: #adb5bd;
}

.s-led-by-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
}

@media (min-width: 576px) {
  .s-led-by-grid {
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  }
}

.s-led-by-card {
  /* flow-root establishes a block-formatting context so the floated avatar is fully
     contained — short cards (little/no bio) keep their height and the photo never spills
     past the bottom border. Content (role/name/bio) flows from the card's left edge so it
     aligns with the rest of the page, and the bio reclaims width beneath the photo. */
  display: flow-root;
  border: 1px solid #e9ecef;
  border-radius: .6rem;
  background: #fff;
  padding: 1rem 1.1rem;
}

.s-led-by-avatar {
  /* Small avatar anchored at the top-right; text wraps to its left and beneath it. */
  float: right;
  width: 64px;
  height: 64px;
  margin: 0 0 .5rem .9rem;
  object-fit: cover;
  border-radius: 50%;
  background-color: #f8f9fa;
}

/* Neutral placeholder when there is no active photo */
.s-led-by-placeholder {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #adb5bd;
  font-size: 1.6rem;
  border: 1px solid #e9ecef;
}

.s-led-by-body {
  min-width: 0;
}

.s-led-by-role {
  text-transform: uppercase;
  letter-spacing: .04em;
  font-size: .72rem;
  font-weight: 700;
  color: var(--bs-secondary-color, #6c757d);
  margin: 0 0 .1rem;
}

.s-led-by-name {
  font-weight: 600;
  font-size: 1.1rem;
  color: var(--bs-body-color, #212529);
  margin: 0 0 .35rem;
}

.s-led-by-bio {
  color: var(--bs-secondary-color, #6c757d);
  font-size: .9375rem;
  margin: 0;
}

/* When it meets — pattern presented as schedule cards */
.s-pattern-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: .85rem;
}

@media (min-width: 576px) {
  .s-pattern-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 992px) {
  .s-pattern-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

.s-pattern-card {
  border: 1px solid #e9ecef;
  border-radius: .5rem;
  background: #fff;
  padding: 1rem 1.1rem;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .05);
}

.s-pattern-card-cadence {
  font-weight: 600;
  font-size: 1.05rem;
  margin-bottom: .25rem;
}

.s-pattern-card-time {
  font-weight: 500;
  color: var(--bs-body-color, #212529);
}

.s-pattern-card-duration {
  color: var(--bs-secondary-color, #6c757d);
  font-weight: 400;
  margin-left: .15rem;
}

.s-pattern-card-location {
  color: var(--bs-secondary-color, #6c757d);
  font-size: .9375rem;
  margin-top: .4rem;
}

.s-pattern-card-pin {
  color: var(--bs-secondary-color, #adb5bd);
  margin-right: .35rem;
}

.s-tz-note {
  color: var(--bs-secondary-color, #6c757d);
  font-size: .8125rem;
  margin: .65rem 0 0;
}

/* Empty state */
.s-empty {
  border: 1px dashed #d6d9dd;
  border-radius: .5rem;
  background: #f8f9fa;
  padding: 2rem 1.25rem;
  text-align: center;
}

.s-empty-icon {
  font-size: 1.75rem;
  color: var(--bs-secondary-color, #adb5bd);
  margin-bottom: .5rem;
}

.s-empty-title {
  font-weight: 600;
  margin: 0 0 .25rem;
}

.s-empty-text {
  color: var(--bs-secondary-color, #6c757d);
  font-size: .9375rem;
  margin: 0;
}

/* ============================================================================
   Organizer page (/o) — recurring event card treatment
   RecurringEvents-PublicUX-OrganizerCards-1
   Additive op-recurring-* classes + a card modifier. Applied only to recurring
   cards (EventSeriesId.HasValue). Base .op-event-card / one-time cards are NOT
   modified and must stay visually identical.
   ============================================================================ */

/* Recurring modifier carries no border accent — the card must not read as
   selected/active. The amber status badge alone signals "recurring schedule". */
.op-event-card--recurring {
  /* intentionally no border/background change to the base card */
}

/* Status marker, deliberately NOT link-blue: soft amber pill with dark text so
   it reads as a status, distinct from the blue title link. */
.op-recurring-badge {
  display: inline-block;
  font-size: .75rem;
  font-weight: 600;
  letter-spacing: .02em;
  color: #8a5a00;
  background: #fff3cd;
  border: 1px solid #ffe69c;
  border-radius: 999px;
  padding: .18rem .7rem;
  margin-bottom: .35rem;
}

/* Card-level location, shown once when every pattern rule shares the same concise location
   (CardPolish-1). Secondary weight so it doesn't compete with the title. */
.op-recurring-cardloc {
  font-size: .8125rem;
  font-weight: 500;
  color: #6c757d;
  margin: 0 0 .4rem;
}

/* Pattern rules — cadence-first hierarchy (CardPolish-1). Each rule stacks a lead cadence token
   over a secondary time/duration/location detail line, so multi-rule cards scan down a clean
   left edge and wrap cleanly on mobile (no mid-segment breaks, no orphaned separators). */
.op-recurring-patterns {
  display: flex;
  flex-direction: column;
  gap: .4rem;
  margin: 0 0 .4rem;
}

.op-recurring-cadence {
  display: block;
  font-size: .9375rem;
  font-weight: 600;
  color: var(--bs-body-color, #212529);
  line-height: 1.3;
}

.op-recurring-detail {
  display: block;
  font-size: .8125rem;
  color: #6c757d;
  line-height: 1.35;
}

.op-recurring-next-label {
  font-weight: 600;
  color: var(--bs-secondary-color, #6c757d);
  margin-right: .2rem;
}

.op-recurring-relative {
  color: var(--bs-secondary-color, #6c757d);
}

/* "View full schedule" link on a Regular activities block (OrganizerPage-RegularActivities-1).
   Lightweight contextual link; the activity title is also a link to /s. */
.op-recurring-viewlink {
  display: inline-block;
  margin-top: .35rem;
  font-size: .9375rem;
  font-weight: 500;
}

/* ============================================================================
   Featured Recurring Schedule card (OrganizerPage-FeaturedRecurringSchedule-1).
   Shown when the organizer has only 1–2 recurring schedules in list mode, so a
   single offering reads as a primary offering, not a thin list row. A calm white
   panel (same surface tokens as .op-schedule / .op-profile-links) whose extra size
   is earned by real content: title, cadence, locations, next 3 dates, CTA.
   ============================================================================ */
.op-featured-activity {
  background: #fff;
  border: 1px solid #dbe5f1;
  border-radius: .75rem;
  padding: 1.5rem 1.75rem;
  margin-bottom: 1rem;
}

.op-featured-title {
  display: block;
  font-size: 1.5rem;
  font-weight: 700;
  color: #1e293b;
  text-decoration: none;
  line-height: 1.25;
  margin: .4rem 0 .25rem;
}

.op-featured-title:hover,
.op-featured-title:focus-visible {
  color: #2c7ac7;
  text-decoration: underline;
}

.op-featured-cardloc {
  font-size: .9375rem;
  font-weight: 500;
  color: #6c757d;
  margin: 0 0 .75rem;
}

.op-featured-patterns {
  display: flex;
  flex-direction: column;
  gap: .9rem;            /* modest breathing room between distinct recurrence-rule groups */
  margin: .5rem 0 1rem;
}

.op-featured-cadence {
  display: block;
  font-size: 1rem;
  font-weight: 600;
  color: var(--bs-body-color, #212529);
  line-height: 1.3;
}

.op-featured-detail {
  display: block;
  font-size: .875rem;
  color: #6c757d;
  line-height: 1.4;
}

/* Upcoming next-3 preview — the content that earns the card's extra height and
   proves the schedule is live, without duplicating the /s timetable. */
.op-featured-upcoming {
  border-top: 1px solid #e3e8ef;
  padding-top: 1rem;
  margin-bottom: 1.1rem;
}

.op-featured-upcoming-label {
  font-size: .75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: #6c757d;
  margin: 0 0 .5rem;
}

.op-featured-upcoming-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: .3rem;
}

.op-featured-upcoming-list li {
  font-size: .9375rem;
  color: #212529;
  font-variant-numeric: tabular-nums;
}

.op-featured-occ-loc {
  color: #6c757d;
}

.op-featured-cta {
  display: inline-block;
  font-size: .9375rem;
  font-weight: 600;
  text-decoration: none;
}

.op-featured-cta:hover,
.op-featured-cta:focus-visible {
  text-decoration: underline;
}

@media (max-width: 575.98px) {
  .op-featured-activity {
    padding: 1.25rem 1.25rem;
  }
  .op-featured-title {
    font-size: 1.3125rem;
  }
}

/* ============================================================================
   Activity Schedule (OrganizerPage-ActivitySchedule-1) — day-grouped rendering of
   weekly recurring rules on /o. Compact, lean rows; no grid/table; same layout on
   desktop and mobile. Additive op-schedule-* classes only.
   ============================================================================ */

/* Single light panel around the schedule body — matches the /o card surface
   (white, soft blue-grey border, rounded, comfortable padding, no heavy shadow). */
.op-schedule {
  background: #fff;
  border: 1px solid #dbe5f1;
  border-radius: .75rem;
  padding: 1.25rem 1.5rem;
}

/* Shared location shown once under the heading (single-location schedules). */
.op-schedule-location {
  color: var(--bs-secondary-color, #6c757d);
  font-size: .9375rem;
  margin: -.25rem 0 1.1rem;
}

/* Day section header — simple but clear: weight + a definite divider, generous top space. */
.op-schedule-day {
  font-size: 1rem;
  font-weight: 700;
  margin: 1.5rem 0 .25rem;
  padding-bottom: .4rem;
  border-bottom: 1px solid #e3e8ef;
}

/* First day sits flush with the panel top (or the shared-location line). */
.op-schedule-location + .op-schedule-day,
.op-events-label + .op-schedule-day {
  margin-top: 0;
}

.op-schedule-rows {
  display: flex;
  flex-direction: column;
}

/* Aligned two columns: time | activity. Grid (not a table) so times and titles
   line up across all rows of a day. */
.op-schedule-row {
  display: grid;
  grid-template-columns: 11rem 1fr;
  align-items: baseline;
  gap: .15rem 1rem;
  padding: .55rem 0;
}

.op-schedule-row + .op-schedule-row {
  border-top: 1px solid #f1f4f8;
}

.op-schedule-time {
  color: #495057;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.op-schedule-activity {
  min-width: 0;
}

.op-schedule-title {
  font-weight: 500;
  /* EventsLog contextual link color (matches .public-content-link and the recurring schedule
     links), not the brighter Bootstrap default link blue. */
  color: #2c7ac7;
  text-decoration: none;
}

.op-schedule-title:hover,
.op-schedule-title:focus-visible {
  color: #1f5e9e;
  text-decoration: underline;
}

/* Mixed-location: muted, smaller, on its own line beneath the title. */
.op-schedule-loc {
  display: block;
  color: var(--bs-secondary-color, #6c757d);
  font-size: .875rem;
  margin-top: .1rem;
}

@media (max-width: 575.98px) {
  .op-schedule {
    padding: 1rem 1.1rem;
  }

  /* Mobile: stack time above the activity (same conceptual day → entries layout). */
  .op-schedule-row {
    grid-template-columns: 1fr;
    gap: .1rem;
  }
}

/* ============================================================================
   Event detail page (/e) — recurring "More dates in this schedule" block
   RecurringEvents-PublicUX-OccurrenceAffordance-1 (placement: -OccurrenceAffordancePlacement-1)
   Additive ep-recurring-* classes. Rendered only for recurring occurrences whose
   schedule page is publicly reachable, low in the page (after Schedule/Location,
   before the Organizer card). Supportive — deliberately lighter than the hero.
   One-time event pages render none of this and base .ep-* styles are not modified.
   ============================================================================ */

/* Neutral, low-emphasis supporting card — no accent color, soft border. */
.ep-recurring-more {
  background: #f8f9fa;
  border: 1px solid #eceef0;
  border-radius: .5rem;
  padding: 1rem 1.1rem;
  margin: 1.5rem 0;
}

.ep-recurring-more-title {
  font-size: 1rem;
  font-weight: 600;
  margin: 0 0 .5rem;
}

.ep-recurring-more-note {
  color: var(--bs-secondary-color, #6c757d);
  font-size: .9375rem;
  margin: 0;
}

.ep-recurring-more-link {
  font-weight: 500;
  font-size: .9375rem;
  /* Same EventsLog contextual link styling as the sibling date links above. */
  color: #2c7ac7;
  text-decoration: none;
}

.ep-recurring-more-link:hover,
.ep-recurring-more-link:focus-visible {
  color: #1f5e9e;
  text-decoration: underline;
}

.ep-recurring-siblings {
  list-style: none;
  padding: 0;
  margin: 0 0 .65rem;
}

.ep-recurring-sibling + .ep-recurring-sibling {
  border-top: 1px solid #eef0f2;
}

.ep-recurring-sibling-link {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .1rem .6rem;
  text-decoration: none;
  /* EventsLog contextual link color (matches .public-content-link and the recurring schedule
     links), not the brighter Bootstrap default link blue. */
  color: #2c7ac7;
  padding: .4rem 0;
}

.ep-recurring-sibling-link:hover {
  color: #1f5e9e;
}

.ep-recurring-sibling-link:hover time {
  text-decoration: underline;
}

.ep-recurring-sibling-loc {
  color: var(--bs-secondary-color, #6c757d);
  font-size: .9rem;
}

/* ============================================================================
   Schedule page (/s) — Upcoming dates, grouped by month
   RecurringEvents-PublicUX-ScheduleUpcomingDates-1
   Scoped s-upcoming-* classes. Date-focused rows (the title repeats across a
   recurring schedule, so it is intentionally omitted here). Reuses no shared
   op-event-card styles.
   ============================================================================ */

/* Subtle warm divider marking the transition from the schedule summary ("When it meets")
   to individual occurrence browsing. Thin light-warm line with generous spacing — no heavy hr. */
.s-upcoming {
  border-top: 1px solid #e7e2d6;
  padding-top: 2.25rem;
  margin-top: .5rem;
}

.s-upcoming-count {
  color: var(--bs-secondary-color, #6c757d);
}

/* RO2-2 (b): the single-venue statement above the rows — the venue said once, so the rows don't repeat
   the same address twenty-five times (VXM §9). */
.s-upcoming-venue {
  color: var(--bs-secondary-color, #6c757d);
  font-size: .9375rem;
  margin: -0.5rem 0 1rem;
}

.s-upcoming-month + .s-upcoming-month {
  margin-top: 1.25rem;
}

.s-upcoming-month-label {
  font-size: .8rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  font-weight: 600;
  color: var(--bs-secondary-color, #6c757d);
  margin: 0 0 .4rem;
}

.s-upcoming-list {
  list-style: none;
  padding: 0;
  margin: 0;
  border: 1px solid #e9ecef;
  border-radius: .5rem;
  overflow: hidden;
  background: #fff;
}

.s-upcoming-row + .s-upcoming-row {
  border-top: 1px solid #f0f1f3;
}

.s-upcoming-link {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .15rem .55rem;
  padding: .6rem .9rem;
  text-decoration: none;
  color: var(--bs-body-color, #212529);
}

.s-upcoming-link:hover {
  background: #f8f9fa;
}

.s-upcoming-link:hover .s-upcoming-date {
  color: #1f5e9e;
  text-decoration: underline;
}

.s-upcoming-date {
  font-weight: 600;
  /* EventsLog contextual link color (matches .public-content-link and the organizer/events
     pages), not the brighter Bootstrap default link blue. */
  color: #2c7ac7;
}

.s-upcoming-time {
  color: var(--bs-body-color, #212529);
}

.s-upcoming-sep {
  color: var(--bs-secondary-color, #adb5bd);
}

.s-upcoming-loc {
  color: var(--bs-secondary-color, #6c757d);
  font-size: .9375rem;
}

/* ============================================================================
   EM2-15 (§6.16) — offering month view (/s?view=calendar)
   A second view of the SAME dates the list shows. Reuses the list's cancelled
   and postponed badges verbatim (FR-15.2's "existing cancelled styling"); the
   only new vocabulary is the grid itself and its view toggle.
   ============================================================================ */

/* The two-view toggle. A quiet segmented pair rather than buttons: choosing how to look at a schedule is not
   an action on it, and the section heading above already carries the visual weight. */
.s-view-toggle {
  display: flex;
  gap: .25rem;
  margin: 0 0 1rem;
}

.s-view-toggle-option {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  padding: .3rem .7rem;
  border: 1px solid #e0e3e7;
  border-radius: .4rem;
  font-size: .9375rem;
  text-decoration: none;
  color: #2c7ac7;
  background: #fff;
}

a.s-view-toggle-option:hover {
  background: #f2f8ff;
  border-color: #2c7ac7;
}

/* The current view is stated, not offered: same geometry, no link colour, so the pair reads as "you are here /
   you can go there" without a second control that does nothing. */
.s-view-toggle-option--current {
  color: var(--bs-body-color, #212529);
  background: #f1f3f5;
  border-color: #d7dbdf;
  font-weight: 600;
}

/* Month navigation: previous · month · next. The end-of-span placeholder keeps the month centred when one of
   the two links is absent (FR-15.2 expresses a bound by omitting the control, never by disabling it). */
.s-calendar-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  margin: 0 0 .6rem;
}

.s-calendar-nav-link {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  font-size: .9375rem;
  font-weight: 600;
  color: #2c7ac7;
  text-decoration: none;
  flex: 0 0 auto;
  min-width: 1.5rem;
}

a.s-calendar-nav-link:hover {
  color: #1f5e9e;
  text-decoration: underline;
}

.s-calendar-nav-link--empty {
  min-height: 1rem;
}

.s-calendar-month {
  font-size: 1rem;
  font-weight: 600;
  margin: 0;
  text-align: center;
  flex: 1 1 auto;
}

/* FR-15.4 — the grid scrolls inside its OWN container. Seven readable columns need more width than a phone
   has, and the one thing that must never scroll sideways is the page body. */
.s-calendar-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border: 1px solid #e9ecef;
  border-radius: .5rem;
  background: #fff;
}

.s-calendar-grid {
  width: 100%;
  min-width: 34rem;
  border-collapse: collapse;
  table-layout: fixed;
}

.s-calendar-grid th {
  font-size: .75rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  font-weight: 600;
  color: var(--bs-secondary-color, #6c757d);
  text-align: left;
  padding: .5rem .55rem;
  border-bottom: 1px solid #e9ecef;
}

.s-calendar-grid th abbr {
  text-decoration: none;
}

.s-calendar-day {
  vertical-align: top;
  width: 14.28%;
  height: 5.25rem;
  padding: .35rem .45rem .5rem;
  border-top: 1px solid #f0f1f3;
  border-left: 1px solid #f0f1f3;
}

.s-calendar-grid tbody tr td:first-child {
  border-left: 0;
}

.s-calendar-daynum {
  display: block;
  font-size: .8125rem;
  font-weight: 600;
  color: var(--bs-secondary-color, #6c757d);
  margin-bottom: .2rem;
}

/* The neighbouring-month days that complete the first and last rows. Kept visible but recessive: blanking them
   would make the grid read as if those days did not exist. */
.s-calendar-day--outside {
  background: #fafbfc;
}

.s-calendar-day--outside .s-calendar-daynum {
  color: #c2c8cf;
}

.s-calendar-day--today {
  background: #eff6ff;
}

.s-calendar-day--today .s-calendar-daynum {
  color: #1f5e9e;
}

.s-calendar-entries {
  list-style: none;
  padding: 0;
  margin: 0;
}

.s-calendar-entries li + li {
  margin-top: .2rem;
}

.s-calendar-entry {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .25rem;
  padding: .15rem .3rem;
  border-radius: .3rem;
  text-decoration: none;
  font-size: .8125rem;
  color: var(--bs-body-color, #212529);
  background: #f2f8ff;
}

a.s-calendar-entry:hover {
  background: #e3f0ff;
}

a.s-calendar-entry:hover .s-calendar-time {
  text-decoration: underline;
}

.s-calendar-time {
  font-weight: 600;
  color: #2c7ac7;
}

/* RO-6 parity: the date the visitor followed reads as the one they followed, here as in the list. */
.s-calendar-entry--referenced {
  outline: 2px solid #2c7ac7;
  outline-offset: 1px;
}

/* The list's cancelled treatment, applied to a cell: struck, muted, and NOT a link. The badge beside it is the
   list's own (.s-upcoming-cancelled-badge), so the two views mark a cancelled date identically. */
.s-calendar-entry--cancelled {
  background: #f6f7f8;
  color: var(--bs-secondary-color, #6c757d);
  cursor: default;
}

.s-calendar-entry--cancelled .s-calendar-time {
  text-decoration: line-through;
  color: inherit;
}

/* RO-14 — named-special cross-link cards. Reuses the upcoming-row rhythm wholesale; the only difference is
   which part leads, because a special is identified by its NAME (it has one of its own — that is the entire
   reason it is a separate offering) while a date row is identified by its date. */
.s-upcoming-title {
  font-weight: 600;
  color: #2c7ac7;
}

.s-upcoming-link:hover .s-upcoming-title {
  color: #1f5e9e;
  text-decoration: underline;
}

/* ShowPublicFunnel-1 (S8) — public Show funnel: grouped performance dates with per-showtime chips.
   Presentation only; reuses the s-section rhythm above. */
.s-showtime-day + .s-showtime-day {
  margin-top: 1.1rem;
}

.s-showtime-date {
  font-size: .8rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  font-weight: 600;
  color: var(--bs-secondary-color, #6c757d);
  margin: 0 0 .5rem;
}

.s-showtime-chips {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
}

.s-chip {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .1rem;
  padding: .5rem .8rem;
  min-width: 6rem;
  border: 1px solid #cfe0f0;
  border-radius: .6rem;
  background: #fff;
  text-decoration: none;
  color: var(--bs-body-color, #212529);
  transition: background .12s ease, border-color .12s ease;
}

a.s-chip:hover {
  background: #f2f8ff;
  border-color: #2c7ac7;
}

.s-chip-time {
  font-weight: 600;
  color: #2c7ac7;
}

a.s-chip:hover .s-chip-time {
  text-decoration: underline;
}

.s-chip-price {
  font-size: .85rem;
  color: var(--bs-secondary-color, #5c636a);
}

.s-chip-badge {
  font-size: .72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .03em;
}

.s-chip-low {
  border-color: #f0c36d;
}

.s-chip-low .s-chip-badge {
  color: #a86a00;
}

.s-chip-disabled {
  background: #f6f7f8;
  border-color: #e3e5e8;
  color: var(--bs-secondary-color, #6c757d);
  cursor: default;
}

.s-chip-disabled .s-chip-time {
  color: var(--bs-secondary-color, #6c757d);
}

.s-chip-soldout .s-chip-badge {
  color: #9a3b3b;
}

.s-chip-cancelled .s-chip-time {
  text-decoration: line-through;
}

.s-chip-cancelled .s-chip-badge {
  color: #9a3b3b;
}

/* ============================================================================
   OrganizerExperiencePolish-1A — accessibility / readability / table polish
   ----------------------------------------------------------------------------
   Conservative polish only (no redesign, no layout/workflow change). Almost
   everything here is SCOPED to the organizer/admin/staff app shell via
   `.app-shell` (added to the _AdminLayout <body>); the public site (_Layout)
   is intentionally left untouched so its hand-tuned op-/ep-/mk- styling is
   unaffected. Introduces a tiny `--el-*` design-token seed used only by the
   improvements below — NOT a full token system.
   Implements review findings A1, A2, A3, M3, V4, and M1 (first pass).
   ============================================================================ */

:root {
  /* A1 — muted/help/metadata ink. Replaces the borderline #6c757d (≈4.2:1 on
     the soft gradients) with a value that clears WCAG AA (≈5.5–6:1) on white,
     ghostwhite, and the gradient panels. */
  --el-text-muted: #5c636a;
  /* A3 — disabled rail items: was #adb5bd (~1.9:1, effectively invisible). */
  --el-nav-disabled: #6c757d;
  /* V4 — subtle zebra stripe for dense tables. */
  --el-table-stripe: #f4f7fa;
  /* M3 — comfortable minimum touch target.

     EM2-18 (§6.18 FR-18.3) corrected the UNIT, not the intent. The token was written `2.75rem` and
     annotated "44px", but every rule that consumes it is scoped to `max-width: 767.98px` — where A2
     (just below) sets the root to 15px. 2.75rem therefore resolved to 41.25px on exactly the phones the
     token exists for, and the measured pass found the Front Desk check-in buttons at 41.3px against a
     normative minimum of 44. Stated in px, the token is 44px wherever it is read, which is what the
     annotation always claimed. */
  --el-touch-min: 44px;

  /* OrganizerShellPolish-1 — app-shell chrome tokens (navy app bar + brand + footer).
     The navy reuses the value already present on the back-to-top button; the orange is
     EventsLog's existing accent, reserved exclusively for the ".net" wordmark suffix. */
  --el-appbar: #1e2d40;                       /* header background (deep admin navy) */
  --el-appbar-edge: #16212f;                  /* header bottom hairline, a shade darker */
  --el-appbar-ink: #ffffff;                   /* primary navbar text/links */
  --el-appbar-ink-dim: rgba(255, 255, 255, .70); /* secondary navbar text (View Site, username) */
  --el-appbar-active: #7fb3e6;                /* navbar active/hover accent (desaturated brand blue) */
  --el-brand-accent: #f97316;                 /* ".net" orange — wordmark ONLY, never reused */
  --el-context-name: #1e2d40;                 /* organizer name in the context strip (echoes header) */
  --el-footer-bg: #eef1f5;                    /* footer band, one step deeper than the strip */
}

/* A2 — base typography: nudge the mobile root from 14px to 15px for easier
   reading on phones (older organizers). Desktop (>=768px) stays 16px. rem-based
   layout scales uniformly, so this is a gentle ~7% bump, not a redesign. */
@media (max-width: 767.98px) {
  html { font-size: 15px; }
}

/* A1 — muted text contrast inside the app shell. Drives the ~950 Bootstrap
   `.text-muted` / `.text-body-secondary` usages plus form help text. */
.app-shell {
  --bs-secondary-color: var(--el-text-muted);
}

.app-shell .text-muted,
.app-shell .text-body-secondary,
.app-shell .form-text,
.app-shell small.text-muted {
  color: var(--el-text-muted) !important;
}

/* V4 — zebra striping for readability/scanning of dense tables. Uses
   Bootstrap's own `--bs-table-bg-type` channel so `.table-hover`
   (`--bs-table-bg-state`) still layers on top. The stripe is applied to EVERY
   cell of a striped row so the whole row shares one background.
   Contextual ROWS (`table-warning`/`table-success`/…) are excluded so their
   status colour is never clobbered. The exclusion is applied at the row level
   only — a per-cell `:not([class*="table-"])` was removed (OrganizerExperience
   Polish-4C) because it matched Bootstrap responsive display utilities such as
   `d-md-table-cell`, which left some cells unstriped and produced mixed
   backgrounds across a single row. No tbody cell uses a contextual `table-*`
   class, so no cell-level protection is needed. Header rows live in <thead>,
   so the tbody-scoped selector leaves `.table-light` headers untouched. */
.app-shell .table > tbody > tr:nth-of-type(odd):not([class*="table-"]) > * {
  --bs-table-bg-type: var(--el-table-stripe);
}

/* A3 — disabled navigation contrast (both rails share .event-sidebar-*). */
.app-shell .event-sidebar-item--disabled,
.app-shell .event-sidebar-item--disabled-reason {
  color: var(--el-nav-disabled);
}

/* M3 — touch targets on phones only (desktop pointer keeps the compact rail).
   Rail links and the in-app navbar links get a comfortable >=44px target. */
@media (max-width: 767.98px) {
  .app-shell .event-sidebar-nav a,
  .app-shell .event-sidebar-nav .event-sidebar-item--disabled,
  .app-shell .event-sidebar-sub-item a {
    min-height: var(--el-touch-min);
    padding-top: .625rem;
    padding-bottom: .625rem;
    display: flex;
    align-items: center;
  }

  .app-shell .navbar .nav-link {
    padding-top: .6rem;
    padding-bottom: .6rem;
  }
}

/* M1 (first pass) — wide data tables get a horizontal-scroll container plus a
   sensible minimum width on phones, so they scroll instead of compressing into
   unreadable columns. Card-stack transforms are intentionally deferred to a
   later slice. Applied only to tables explicitly marked `.el-table-scroll`. */
@media (max-width: 767.98px) {
  .app-shell .el-table-scroll > .table {
    min-width: 42rem;
    margin-bottom: 0;
  }
}

/* ============================================================================
   OrganizerShellPolish-1 — navy app bar, EventsLog.net lockup, nav states, badge
   ----------------------------------------------------------------------------
   Option C shell: a deep-navy global bar replaces the near-black Bootstrap default,
   carrying the EventsLog.net wordmark with a single restrained-orange ".net" spark.
   The active nav state mirrors the rail's blue accent (left-bar on the rail → bottom-
   bar on the dark bar). App-shell scoped only; the public _Layout marketing theme is
   untouched. ORANGE DISCIPLINE: --el-brand-accent appears here on ".net" and nowhere
   else in the console — the active state is intentionally blue, not orange.
   ============================================================================ */
.app-shell .el-appbar {
  background-color: var(--el-appbar);
  border-bottom: 1px solid var(--el-appbar-edge);
}

/* Brand lockup: "EventsLog" white/600 + ".net" orange/500 at ~92% size, one token. */
.app-shell .el-appbar .navbar-brand {
  font-weight: 600;
  color: var(--el-appbar-ink);
}
.app-shell .el-appbar .el-brand-name {
  color: var(--el-appbar-ink);
  font-weight: 600;
}
.app-shell .el-appbar .el-brand-tld {
  color: var(--el-brand-accent);
  font-weight: 500;
  font-size: .92em;
}

/* Admin role chip: a quiet light pill on the navy bar, not a second accent. */
.app-shell .el-appbar .el-admin-badge {
  background-color: rgba(255, 255, 255, .14);
  color: #fff;
  font-weight: 600;
}

/* Nav links. Primary stay full white (their .text-white utility); secondary
   (.el-nav-dim) drop to --el-appbar-ink-dim, brighter than the former text-white-50
   so they clear AA on navy. A transparent 2px under-border is reserved on EVERY link
   so activating one causes no layout shift; the active link fills that border with the
   blue accent and brightens to white. */
.app-shell .el-appbar .navbar-nav .nav-link {
  border-bottom: 2px solid transparent;
}
.app-shell .el-appbar .navbar-nav .nav-link.el-nav-dim {
  color: var(--el-appbar-ink-dim);
}
.app-shell .el-appbar .navbar-nav .nav-link:hover,
.app-shell .el-appbar .navbar-nav .nav-link:focus-visible {
  color: #fff;
}
.app-shell .el-appbar .navbar-nav .nav-link.active {
  color: #fff;
  border-bottom-color: var(--el-appbar-active);
}
.app-shell .el-appbar .navbar-nav .nav-link:focus-visible {
  outline: 2px solid var(--el-appbar-active);
  outline-offset: 2px;
  border-radius: .15rem;
}

/* ============================================================================
   OrganizerExperiencePolish-4 — organizer context bar
   ----------------------------------------------------------------------------
   The light strip directly under the global navbar is the single, fixed home
   for the active organizer name. Calm and readable — a context label, not a
   loud banner and not a normal underlined hyperlink. Left-aligned, full-width
   above the rail/content. Scoped to the admin/organizer/staff shell only.
   ============================================================================ */
.app-shell .topbar-context {
  padding-top: .4rem;     /* slightly more breathing room than the former py-1 (.25rem) */
  padding-bottom: .4rem;
}

.app-shell .topbar-context .breadcrumb {
  font-size: .9375rem;    /* a touch larger than .small for readability; still calm */
  margin-bottom: 0;
  align-items: center;
}

/* Context links (e.g. the organizer name on a class/event page) read as a calm label,
   not an inline hyperlink: no default underline, but an accessible hover/focus affordance. */
.app-shell .topbar-context a {
  /* OrganizerShellPolish-1: secondary scope links (e.g. "People") read muted so the
     organizer anchor below stands out. The first segment is re-asserted navy/600 below. */
  color: #5c636a;
  text-decoration: none;
}
.app-shell .topbar-context a:hover,
.app-shell .topbar-context a:focus-visible {
  color: #1f5e9e;
  text-decoration: underline;
}
.app-shell .topbar-context a:focus-visible {
  outline: 2px solid #0d6efd;
  outline-offset: 2px;
  border-radius: .15rem;
}

/* The organizer (first segment) is the prominent, fixed anchor. Subsequent scope
   segments (class / event) and the current leaf stay readable but secondary. */
.app-shell .topbar-context .breadcrumb-item:first-child,
.app-shell .topbar-context .breadcrumb-item:first-child a {
  /* OrganizerShellPolish-1: the organizer name is the anchor — navy (echoing the header)
     and a touch larger, so the strip reads as the seam between the dark bar and light content. */
  font-weight: 600;
  color: var(--el-context-name);
  font-size: 1rem;
}
.app-shell .topbar-context .breadcrumb-item.active {
  color: #5c636a;
}

/* ============================================================================
   OrganizerExperiencePolish-4A — admin link styling correction
   ----------------------------------------------------------------------------
   Root cause: EventsLog's admin link style (#2c7ac7, no default underline) was
   only applied via per-page `<style> main a` blocks on a few class/schedule
   pages. Pages without that block fell back to Bootstrap's default blue
   underlined links (e.g. /people), and because the rails now render inside
   <main>, those `main a` blocks (and the global content rule below) out-specify
   the rail's own `.event-sidebar-nav a` rules and tinted rail links blue
   (e.g. /schedules). Fix: one global admin content-link rule, plus rail link
   colors re-asserted at higher specificity so neither the content rule nor any
   page-level `main a` block can hijack them. CSS only; no markup/layout change.
   ============================================================================ */

/* Content links inside the admin shell: EventsLog blue, no default underline;
   accessible underline + darker color on hover/focus. Buttons are excluded.
   Scoped to <main>, so the top context bar (in <header>) keeps its own styling. */
.app-shell main a:not(.btn) {
  color: #2c7ac7;
  text-decoration: none;
}
.app-shell main a:not(.btn):hover,
.app-shell main a:not(.btn):focus-visible {
  color: #1f5e9e;
  text-decoration: underline;
}

/* Rails (organizer / class / event) stay navigation-styled: dark text, never the
   content-blue, never underlined. These re-assert only color/decoration at a
   specificity that beats the content rule above and any page-level `main a` block;
   backgrounds, borders, weight, outline and padding still come from the base
   `.event-sidebar*` rules (cascaded per-property). */
.app-shell .event-sidebar .event-sidebar-nav a {
  color: #495057;
  text-decoration: none;
}
.app-shell .event-sidebar .event-sidebar-nav a:hover,
.app-shell .event-sidebar .event-sidebar-nav a:focus-visible {
  color: #212529;
  text-decoration: none;
}
.app-shell .event-sidebar .event-sidebar-nav a[aria-current="page"] {
  color: #212529;
}

/* Event-rail "escape" link keeps its muted style (it is not an .event-sidebar-nav item). */
.app-shell .event-sidebar .event-sidebar-escape a {
  color: #6c757d;
  text-decoration: none;
}
.app-shell .event-sidebar .event-sidebar-escape a:hover,
.app-shell .event-sidebar .event-sidebar-escape a:focus-visible {
  color: #212529;
  text-decoration: underline;
}

/* ============================================================================
   OrganizerExperiencePolish-6 — reusable admin/event form pattern
   ----------------------------------------------------------------------------
   Small, Bootstrap-compatible, .app-shell-scoped. Adapts the public form model
   (soft region + visible field boundaries + grouped/width-disciplined fields)
   for admin/event workspace forms — with NO public hero/marketing styling.
   Public pages (_Layout / .public-form-card) are a different scope and are not
   affected. Opt-in via class; never changes inputs globally.
     .el-form-panel   — soft bordered form region (pair with p-3/p-md-4/mb-* utils)
     .el-form         — marker for "admin form": stronger field borders only
                        (no bg/border) for pages already grouped in cards
     .el-field-grid   — responsive paired fields (stack on mobile)
     .el-form-actions — consistent action footer
     .el-field-narrow — width cap for short numeric/date inputs
   ============================================================================ */

.app-shell .el-form-panel {
  background-color: #fbfcfe;
  border: 1px solid #dee2e6;
  border-radius: .5rem;
}

/* Stronger field boundaries — only inside an opted-in admin form (.el-form-panel
   or .el-form), so no global input change. Resting state only: :focus and the
   validation states (.is-invalid/.is-valid) are excluded so Bootstrap's focus
   ring/border and red/green validation borders remain fully intact and distinct. */
.app-shell .el-form-panel .form-control:not(:focus):not(.is-invalid):not(.is-valid),
.app-shell .el-form-panel .form-select:not(:focus):not(.is-invalid):not(.is-valid),
.app-shell .el-form .form-control:not(:focus):not(.is-invalid):not(.is-valid),
.app-shell .el-form .form-select:not(:focus):not(.is-invalid):not(.is-valid) {
  border-color: #adb5bd;
}

/* RO-10 (PD §5): a recurring date's INHERITED description — the offering's words shown where the editable
   description box would be while the date follows its offering. Sized like the textarea it stands in for so the
   panel does not jump when an exception is opened, and pre-wrap because it is prose the organizer typed. */
.app-shell .el-inherited-description {
  min-height: 6rem;
  white-space: pre-wrap;
  height: auto;
}

/* Responsive paired fields — single column on phones; side-by-side when there's
   room (mirrors the existing .s-led-by-grid approach). Row gap is 0 because the
   paired field wrappers already carry Bootstrap mb-* spacing. */
.app-shell .el-field-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0 1rem;
}
@media (min-width: 576px) {
  .app-shell .el-field-grid {
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  }
}

/* Consistent action footer — primary + secondary grouped with a light divider. */
.app-shell .el-form-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  align-items: center;
  margin-top: 1.25rem;
  padding-top: 1rem;
  border-top: 1px solid #e9ecef;
}

/* Width cap for short numeric/date inputs inside a panel/grid. */
.app-shell .el-field-narrow {
  max-width: 14rem;
}

/* ============================================================================
   KPI / stat cards (OrganizerExperiencePolish-KPI-1, calmed in KPI-1A)
   Reusable, calm, centered number-cards for report pages. App-shell scoped so
   public/marketing pages are untouched. Hierarchy comes from a whisper-warm
   off-white card (distinct from the cool ghostwhite page yet not stark white),
   a defined hairline border, generous spacing, and a bold near-black number;
   exactly one --primary card per logical section gets a very subtle cool-blue
   tint + a 3px top accent edge (the established active-blue) so it reads as the
   focal metric against the warm neutrals.
   KPI-1A: icons were REMOVED from the report markup — they dominated the small
   cards and added clutter. The optional .el-kpi-icon support is RETAINED (muted
   + smaller) for any future opt-in surface, but the report pages no longer use
   it. Colour vocabulary reuses existing values: #eff6ff/#c7dceb (soft-blue
   panel), #0d6efd (active accent), --el-text-muted (AA-cleared label ink).
   Numbers stay near-black. No gradient, no animation, no hover, no dark tiles,
   no bright colour, no category colour-coding.
   ============================================================================ */
:root {
  --el-kpi-bg: #fcfbf8;           /* non-primary: whisper-warm off-white */
  --el-kpi-border: #e6e3dc;       /* defined warm hairline */
  --el-kpi-icon: #6c757d;         /* optional icon: muted (unused on reports) */
  --el-kpi-value: #212529;
  --el-kpi-primary-bg: #eff6ff;
  --el-kpi-primary-border: #c7dceb;
  --el-kpi-primary-accent: #0d6efd;
}

/* Grid: 2-up on phones AND tablets, 4-up at >=lg. KPI-2 moved the multi-column
   breakpoint from md to lg: in the md range the rail is a visible sidebar, so a
   4-up grid inside a report panel cramped and wrapped labels. 2-up stays roomy
   on tablets; full width unlocks 4-up. --thirds is the 3-up money variant. Cards
   stretch to equal height per row (grid default align-items: stretch). */
.app-shell .el-kpi-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: .75rem;
}
@media (min-width: 992px) {
  .app-shell .el-kpi-grid {
    grid-template-columns: repeat(4, 1fr);
  }
  .app-shell .el-kpi-grid--thirds {
    grid-template-columns: repeat(3, 1fr);
  }
}

.app-shell .el-kpi-card {
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  background: var(--el-kpi-bg);
  border: 1px solid var(--el-kpi-border);
  border-radius: .625rem;
  padding: 1.25rem 1rem;
}

/* One per section. Subtle tint + a 3px top accent edge (replaces the 1px top
   border; border-box keeps outer heights equal across the row). The top edge is
   a real border, so the primary stays distinguishable in print where the tint
   is dropped. */
.app-shell .el-kpi-card--primary {
  background: var(--el-kpi-primary-bg);
  border-color: var(--el-kpi-primary-border);
  border-top: 3px solid var(--el-kpi-primary-accent);
}

/* Optional, opt-in only — RETAINED for future surfaces but unused on the report
   pages (KPI-1A removed the icon markup there). Muted + small so it never
   dominates if a future page chooses to include it. */
.app-shell .el-kpi-icon {
  color: var(--el-kpi-icon);
  font-size: .9rem;
  line-height: 1;
  margin-bottom: .4rem;
}

.app-shell .el-kpi-value {
  font-size: 1.75rem;
  font-weight: 700;
  line-height: 1.1;
  color: var(--el-kpi-value);
  font-variant-numeric: tabular-nums;
}

.app-shell .el-kpi-label {
  font-size: .8125rem;
  line-height: 1.25;
  color: var(--el-text-muted);
  margin-top: .2rem;
}

.app-shell .el-kpi-meta {
  font-size: .75rem;
  line-height: 1.25;
  color: var(--el-text-muted);
  margin-top: .1rem;
}

/* Phones: trim the number and padding so a 2-up grid stays compact. */
@media (max-width: 767.98px) {
  .app-shell .el-kpi-value {
    font-size: 1.5rem;
  }
  .app-shell .el-kpi-card {
    padding: 1rem .7rem;
  }
}

/* ============================================================================
   Report section panels (OrganizerExperiencePolish-KPI-2)
   Wraps each report block (heading + cards/table + notes/links) in a calm,
   bordered surface so sections read as distinct units instead of one long
   sheet. An extension of the existing .el-form-panel vocabulary (same #fbfcfe
   surface, #dee2e6 hairline, .5rem radius) — not a new design system. Neutral
   surface only: no per-section colour (gentle separation comes from the border
   + the inter-panel gap, not decoration). App-shell scoped; report pages only.
   ============================================================================ */
.app-shell .el-report-section {
  background-color: #fbfcfe;
  border: 1px solid #dee2e6;
  border-radius: .5rem;
  padding: 1.25rem;
  margin-bottom: 1.5rem;
  break-inside: avoid; /* keep a panel together in print where possible */
}
@media (min-width: 768px) {
  .app-shell .el-report-section {
    padding: 1.5rem 1.75rem;
  }
}
.app-shell .el-report-section:last-child {
  margin-bottom: 0;
}

/* Empty-state panels (e.g. "No ticket orders yet.") read as an intentional, calm placeholder
   with extra vertical breathing room instead of one cramped line in a bordered box. Scoped to
   centred muted sections, which the report pages use exclusively for empty states. */
.app-shell .el-report-section.text-center.text-muted {
  padding-top: 2.25rem;
  padding-bottom: 2.25rem;
}

/* Section heading: clearly stronger than table column headers, still restrained.
   A hairline rule under the title separates it from the section body. */
.app-shell .el-report-section-title {
  font-size: 1.125rem;
  font-weight: 600;
  color: #212529;
  margin: 0 0 1rem;
  padding-bottom: .6rem;
  border-bottom: 1px solid #edf0f3;
}

/* Organizer status summary — the old run-on "Status: …" line presented as calm
   labeled chips. Subtle bordered pills, no colour, sit on the panel surface. */
.app-shell .el-report-statline {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  margin-top: 1rem;
}
.app-shell .el-stat {
  display: inline-flex;
  align-items: baseline;
  gap: .4rem;
  background: #fff;
  border: 1px solid #e6e9ee;
  border-radius: .375rem;
  padding: .3rem .65rem;
  font-size: .8125rem;
  line-height: 1.2;
}
.app-shell .el-stat-label {
  color: var(--el-text-muted);
}
.app-shell .el-stat-value {
  font-weight: 600;
  color: #212529;
  font-variant-numeric: tabular-nums;
}

/* ============================================================================
   Shared workspace content gutter (OrganizerExperiencePolish-WorkspaceGutter-1)
   Promotes the report-page content gutter into a shared organizer/class/event
   workspace convention. Every workspace page uses the same rail + content row:
   `.event-sidebar-col` immediately followed by the `.col-md-9` content column,
   so one adjacent-sibling rule gives the whole workspace consistent breathing
   space off the rail/divider — no per-page markup. md+ only (the rail is an
   offcanvas below md, so mobile is unaffected). This supersedes the
   report-specific `.el-report-body` (now removed) as the single source of truth.
   ============================================================================ */
@media (min-width: 768px) {
  .app-shell .event-sidebar-col + .col-md-9 {
    padding-left: 1.5rem;
  }
}
@media (min-width: 992px) {
  .app-shell .event-sidebar-col + .col-md-9 {
    padding-left: 2rem;
  }
}

/* ============================================================================
   CspNonceHardening-Styles-1 — inline-style externalization
   Utility classes + page-local rules moved out of inline `style=""` attributes and
   per-page `<style>` blocks so the markup carries no inline CSS (the prerequisite for
   tightening `style-src` in a later slice). Every value is reproduced exactly — this is
   a mechanical CSP-prep change, not a restyle. Not `.app-shell`-scoped: several are used
   on public pages too.
   ============================================================================ */

/* max-width content constraints (exact values from the former inline styles) */
.el-mw-150 { max-width: 150px; }
.el-mw-200 { max-width: 200px; }
.el-mw-220 { max-width: 220px; }
.el-mw-320 { max-width: 320px; }
.el-mw-360 { max-width: 360px; }
.el-mw-420 { max-width: 420px; }
.el-mw-500 { max-width: 500px; }
.el-mw-520 { max-width: 520px; }
.el-mw-560 { max-width: 560px; }
.el-mw-640 { max-width: 640px; }
.el-mw-720 { max-width: 720px; }
.el-mw-760 { max-width: 760px; }
.el-mw-8rem  { max-width: 8rem; }
.el-mw-10rem { max-width: 10rem; }
.el-mw-18rem { max-width: 18rem; }   /* EM2-7: the weekly repeat-interval select */
.el-mw-30rem { max-width: 30rem; }

/* fixed widths / min-widths */
.el-w-92    { width: 92px; }
.el-w-3rem  { width: 3rem; }
.el-w-5rem  { width: 5rem; }
.el-w-10rem { width: 10rem; }
.el-minw-11rem { min-width: 11rem; }
.el-qr-reader  { width: 100%; max-width: 500px; }

/* table column proportional widths (exact %, from former inline <th> styles) */
.el-w-pct-5  { width: 5%; }
.el-w-pct-6  { width: 6%; }
.el-w-pct-20 { width: 20%; }
.el-w-pct-21 { width: 21%; }
.el-w-pct-25 { width: 25%; }
.el-w-pct-35 { width: 35%; }
.el-w-pct-37 { width: 37%; }

/* circular avatar image + matching square placeholder boxes (exact sizes) */
.el-avatar-225,
.el-avatar-275,
.el-avatar-3 { object-fit: cover; border-radius: 50%; }
.el-avatar-225, .el-box-225 { width: 2.25rem; height: 2.25rem; }
.el-avatar-275, .el-box-275 { width: 2.75rem; height: 2.75rem; }
.el-avatar-3 { width: 3rem; height: 3rem; }
.el-box-14 { width: 1.4rem; height: 1.4rem; }

/* type / spacing helpers */
.el-fs-07em  { font-size: 0.7em; vertical-align: middle; }
.el-fs-075em { font-size: 0.75em; }
.el-fs-3rem  { font-size: 3rem; line-height: 1; }
.el-badge-lg { font-size: .875rem; padding: .4em .75em; }
.el-tracking { letter-spacing: .04em; }

/* text wrapping */
.el-prewrap   { white-space: pre-wrap; }
.el-break-all { word-break: break-all; }

/* EM2-4 (spec §6.5 FR-4.2) — the scrollable block an organizer's waiver text is read in, on the three public
   commitment surfaces and on the two organizer surfaces that echo it back. A class rather than an inline
   style attribute because CspNonceHardening-Styles-1 admits no exceptions, and because the same measurements
   have to hold on five pages: a waiver that scrolls on the registration form and runs the page long on the
   ticket page would be two different documents to read. The taller variant is the one beside a checkbox the
   visitor is about to tick; the shorter is for the read-back panels, where the text is reference, not a gate. */
.el-scrollbox      { max-height: 14rem; overflow-y: auto; white-space: pre-wrap; }
.el-scrollbox-sm   { max-height: 12rem; overflow-y: auto; white-space: pre-wrap; }

/* misc */
.el-cursor-pointer { cursor: pointer; }

/* off-screen honeypot containers (kept exactly — anti-bot keys off the precise positioning) */
.el-honeypot  { position: absolute; left: -9999px; }
.el-offscreen { position: absolute; left: -5000px; top: auto; width: 1px; height: 1px; overflow: hidden; }

/* page-local link/card rules moved verbatim from per-page <style> blocks (page-specific class/id
   selectors → safe to host globally; they only match on their own pages) */
.evt-row-links a { color: #2c7ac7; text-decoration: none; }
.evt-row-links a:hover,
.evt-row-links a:focus { color: #1f5e9e; text-decoration: underline; }

.conf-card { background-color: #fbfcfe; }

.mk-text-link { color: #2c7ac7; text-decoration: none; }
.mk-text-link:hover,
.mk-text-link:focus-visible { color: #1f5e9e; text-decoration: underline; }
.mk-text-link:focus-visible { outline: 2px solid #258cfb; outline-offset: 2px; border-radius: 2px; }

#reg-form .form-check-input { border-color: #1f2937; }
#reg-form .reg-picker-card > div { margin-bottom: 0; }

/* Session-picker day groups (RegSessionDaySeparation-1): each day is a distinct group, clearly
   separated from the one above by space + a hairline, while the date binds tightly to its own
   sessions below it. The date reads as a header (near-black, not muted) rather than a peer of the
   faint session time text. Presentational only — markup wraps each GroupBy(day) in .reg-session-day. */
.reg-session-day + .reg-session-day {
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid #e9ecef;
}
.reg-session-day-label {
  color: #212529;
  font-size: .875rem;
}
.reg-title-link { color: #2c7ac7; text-decoration: none; }
.reg-title-link:hover,
.reg-title-link:focus-visible { color: #1f5e9e; text-decoration: underline; }
.reg-link { color: #2c7ac7; text-decoration: none; }
.reg-link:hover,
.reg-link:focus-visible { color: #1f5e9e; text-decoration: underline; }
.reg-title-link:focus-visible,
.reg-link:focus-visible { outline: 2px solid #258cfb; outline-offset: 2px; border-radius: 2px; }

/* CopyOnlyVenueEditor-1 (P7-S6 · ADR-032): when a saved venue is linked, the copied address fields are shown
   read-only (their inputs are also disabled, so no manual value is posted). This dims them to make the
   copy-only state visually obvious. Presentational only — the disabling is what enforces the model. */
.venue-manual-readonly {
  opacity: .6;
}
.venue-manual-readonly input,
.venue-manual-readonly select,
.venue-manual-readonly textarea {
  background-color: #f8f9fa;
  cursor: not-allowed;
}

/* VX-5 venue library — search box width (class-based; no inline style, CSP-safe) */
.venue-search-input { max-width: 18rem; }

/* VX-6 C6 confirmation modal — hand-rolled accessible dialog (class-based; no inline style, CSP-safe).
   Progressive: hidden by default via the [hidden] attribute; initConfirmModal toggles it. */
.confirm-modal {
  position: fixed;
  inset: 0;
  z-index: 1080;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  background: rgba(0, 0, 0, .5);
}
.confirm-modal[hidden] { display: none; }
.confirm-modal-dialog {
  background: var(--bs-body-bg, #fff);
  color: var(--bs-body-color, #212529);
  border-radius: .5rem;
  max-width: 32rem;
  width: 100%;
  padding: 1.25rem 1.5rem;
  box-shadow: 0 1rem 3rem rgba(0, 0, 0, .35);
}
.confirm-modal-title { margin-top: 0; }
.confirm-modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: .5rem;
  margin-top: 1.25rem;
}
html.confirm-modal-open { overflow: hidden; }

/* VX-6 venue detail — preserve author line breaks in read-only public/internal text (CSP-safe, class-based) */
.venue-detail-text { white-space: pre-line; }

/* EM2-13 organizer contact inbox — a sender's message is plain text and keeps the line breaks they typed.
   Class-based rather than an inline style attribute, per the CSP inline-style rule. */
.org-contact-message-body { white-space: pre-wrap; }

/* EM2-14 organizer policies (§6.15 FR-14.2) — the collapsible block shown on the /e detail, registration and
   ticket purchase pages. Class-based, no inline styles (the CSP rule), and no JavaScript: <details>/<summary>
   is the codebase's existing disclosure idiom. Deliberately quiet — this is reference text beside a call to
   action, not a second call to action. */
.organizer-policies         { margin: 1.5rem 0; border: 1px solid var(--bs-border-color); border-radius: .5rem; }
.organizer-policies-summary { cursor: pointer; padding: .75rem 1rem; font-weight: 600; }
.organizer-policies-body    { padding: 0 1rem 1rem 1rem; }
.organizer-policies-heading { font-size: 1rem; font-weight: 600; margin: .75rem 0 .25rem 0; }
.organizer-policies-text    { margin-bottom: .5rem; }

/* ── PWD-2 · public back-links, the /o empty state, and Home's attendee entry ──────────────────────────
   PublicWebsiteDiscovery-Spec-1 §6.2 items 2–4. Spacing only: every one of these links reuses the shipped
   .public-content-link colour/focus treatment rather than introducing a new link style, so there is one
   contextual-link appearance across the public surface and nothing here to keep in sync with it.
   The /o and /e containers mirror the .op-footer / .ep-footer rhythm they sit beside. */

.op-events-empty {
  margin-top: 1.5rem;
}

.op-browse-all {
  max-width: 1320px;
  margin: 2rem auto 0;
  padding-top: 1.5rem;
  border-top: 1px solid #dee2e6;
  font-size: .9375rem;
}

.s-browse-all {
  margin: 1.5rem 0 0;
  font-size: .9375rem;
}

.ep-browse-all {
  margin-top: 2rem;
  padding-top: 1.5rem;
  border-top: 1px solid #dee2e6;
  font-size: .9375rem;
}

/* Home's attendee entry sits between the CTA row and the early-access note, so it takes the note's type
   scale and colour and a tighter top margin — a quiet line, not a third call to action (OD-4: "modest"). */
.hp-hero-attendee {
  margin: 1rem 0 0;
  font-size: .9375rem;
  color: #4b5563;
}

/* ============================================================================
   PWD-5 · Reduced motion (PublicWebsiteDiscovery-Spec-1 §6.5 required behaviour (c); PWD-12)
   ============================================================================
   The public pages carried NO prefers-reduced-motion honouring of any kind. A visitor whose operating
   system says "minimise animation" — a vestibular-disorder accommodation, not a preference — still got
   every transition and the smooth scroll of the back-to-top control.

   NOTE — THE ARM BELOW IS DELIBERATELY UNIVERSAL RATHER THAN A LIST OF CLASS NAMES. A hand-written list is
   the shape this repository has now watched fail four times (PWD-3's literal hedge list, PWD-4's banned
   phrase list, and the two ratchet-reach findings behind them): it is correct on the day it is written
   and silently short the moment somebody adds a class. Enumerating .public-back-to-top, .btn-mk-solid,
   .btn-mk-learn, .btn-mk-quiet, .hp-proof-card, .em-chapter-next a and a.s-chip — every animated public
   surface as of this slice — would cover exactly today's set and nothing after it. The universal arm
   covers them all AND everything a later slice adds, which is the property the requirement is really
   about. The class names are still written down, HERE, so the coverage claim can be read and checked.

   NOTE — REACH LIMIT, STATED RATHER THAN LEFT TO BE FOUND: CSS cannot reach a script-driven scroll. The
   back-to-top control calls window.scrollTo({ behavior: 'smooth' }), and an explicit ScrollToOptions
   behavior overrides the scroll-behavior property — so site.js carries its own matchMedia guard for that
   one case, and scroll-behavior below covers CSS-initiated and anchor scrolling only.

   Bootstrap ships its own reduce block for .fade/.collapsing; this neither replaces nor fights it. */
@media (prefers-reduced-motion: reduce) {
  html:focus-within {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ============================================================================
   PWD-5 · /events filter-bar tap targets (PublicWebsiteDiscovery-Spec-1 §6.5 Principal files; PWD-12)
   ============================================================================
   Recorded run, 2026-08-27, 390x844: the three controls in the /events filter bar rendered 29px tall -
   the smallest interactive targets on any of the five public content pages. They clear WCAG 2.2 AA's
   24x24 minimum (2.5.8) but sit well under the 44px comfort target, and they are the FIRST thing a
   visitor on a phone touches on the public directory. §6.5's Principal-files line anticipates exactly
   this rule, conditioned on the run flagging them, and the run flagged them.

   NOTE — SCOPED TO .ev-filter-bar, WHICH ONLY /events RENDERS. Raising .btn / .form-*-sm globally would be
   a design-system change, which §2.3 excludes; the other four pages' smallest controls (36-41px, plus one
   28px checkbox on /o) are recorded in the PWD-5 evidence and deliberately left alone.
   .pagination-sm is NOT changed: the local dataset lists 16 items on one page, so the pager did not
   render and the run could not flag it. A rule for something unobserved would be a guess.
   Narrow viewports only, so the desktop filter bar is byte-for-byte unchanged.

   The minimum is --el-touch-min, EM2-18's token (FR-18.3), NOT a second hard-coded 44. The platform states
   its comfortable touch minimum in exactly one place; a public page restating the number would drift from it
   silently the first time it moved. The token is declared on :root, so the public layout reads it even though
   EM2-18's own consumers are .app-shell-scoped. MobileFitnessGuardTests pins it to 44px AND pins why it must
   be stated in px: every consumer of it sits inside a max-width query where the root font-size is 15px, so a
   rem value silently resolves to 41.25px. */
@media (max-width: 575.98px) {
  .ev-filter-bar .form-select,
  .ev-filter-bar .form-control,
  .ev-filter-bar .btn {
    min-height: var(--el-touch-min);
  }
}
/* ── CSF-7 · the Class public projection (design 8.1, 7) ─────────────────────────────────────────────────
   Four small blocks on the /s Class arm: the upcoming-changes list, the break block, the effective-window
   rider on a regular-schedule line, and the multi-meeting date acknowledgment. No existing selector is
   changed, so Event and Show rendering is untouched. */

.s-class-changes {
  margin-bottom: 1.25rem;
}

.s-class-change-list {
  list-style: none;
  padding: 0;
  margin: 0;
}

.s-class-change {
  padding: .4rem 0;
  border-bottom: 1px solid var(--bs-border-color, #dee2e6);
  font-size: .95rem;
}

.s-class-change:last-child {
  border-bottom: 0;
}

.s-class-break {
  margin: 0 0 1.25rem;
  padding: .75rem 1rem;
  border-left: 3px solid #6c757d;
  background: #f8f9fa;
  border-radius: .25rem;
}

.s-class-break-range {
  margin: 0;
  font-weight: 600;
}

.s-class-break-resume {
  margin: .25rem 0 0;
  font-size: .9rem;
  color: var(--bs-secondary-color, #6c757d);
}

/* The (from ...) / (through ...) rider on a regular-schedule line. Quiet: it qualifies the line, it is not
   a second heading. */
.s-pattern-card-window {
  margin-top: .35rem;
  font-size: .825rem;
  color: var(--bs-secondary-color, #6c757d);
}

/* One day can resolve more than one meeting, so the acknowledgment lists them rather than picking one. */
.s-date-context-meetings {
  list-style: none;
  padding: 0;
  margin: .5rem 0 0;
}

.s-date-context-meetings > li + li {
  margin-top: .5rem;
  padding-top: .5rem;
  border-top: 1px solid var(--bs-border-color, #dee2e6);
}

