/* ==========================================================================
   Techspire Summits - event sites (one per conference subdomain)
   --------------------------------------------------------------------------
   These pages are Bootstrap 5 with three swappable themes (bold / classic /
   minimal) and per-event colour overrides set in admin. This layer gives them
   the shared design-system foundation while leaving each event free to brand
   its own header through the --ts-event-* variables the layout writes inline.
   ========================================================================== */

.ts-event {
  --ts-header-h: 72px;
  background: var(--ts-bg);
  color: var(--ts-text);
  font-family: var(--ts-font-body);
  font-size: var(--ts-text-base);
  line-height: var(--ts-leading-normal);
}

.ts-event h1, .ts-event h2, .ts-event h3,
.ts-event h4, .ts-event h5, .ts-event h6 {
  font-family: var(--ts-event-heading-font, var(--ts-font-display));
  font-weight: var(--ts-weight-semibold);
  letter-spacing: var(--ts-tracking-tight);
  line-height: var(--ts-leading-tight);
  color: var(--ts-text);
  text-wrap: balance;
}
.ts-event h1 { font-size: var(--ts-text-4xl); }
.ts-event h2 { font-size: var(--ts-text-3xl); }
.ts-event h3 { font-size: var(--ts-text-2xl); }
.ts-event h4 { font-size: var(--ts-text-xl); }

.ts-event p { line-height: var(--ts-leading-relaxed); }
.ts-event .lead { font-size: var(--ts-text-lg); color: var(--ts-text-muted); max-width: var(--ts-measure); }
.ts-event .text-muted { color: var(--ts-text-muted) !important; }

/* --------------------------------------------------------------------------
   Header. Bootstrap's .navbar markup is kept so the theme partials that fill
   @yield('nav') keep working; only the visual language changes.
   -------------------------------------------------------------------------- */
.ts-event .navbar {
  min-height: var(--ts-header-h);
  padding-block: var(--ts-space-3);
  background: var(--ts-event-header-bg, var(--ts-surface)) !important;
  border-bottom: 1px solid var(--ts-border);
  box-shadow: none !important;
}
.ts-event .navbar-brand { padding: 0; font-family: var(--ts-font-display); font-weight: var(--ts-weight-semibold); color: var(--ts-event-header-fg, var(--ts-text)); }
/* An SVG with only a viewBox has no intrinsic size, so `width:auto` inside a
   flex row collapses it to zero. Set the height and stop it shrinking. */
.ts-event .navbar-brand { flex: 0 0 auto; }
/* Conference logos are not all the same shape. A wide wordmark fills the
   260px cap at 44px tall and reads fine; a square badge -- which is what most
   conferences use -- was left as a 44x44 thumbnail with its own name in it,
   too small to read. The taller box helps the square case without changing
   the wide one, which is limited by max-width either way.

   object-fit guards the corner where both limits bind at once: with an
   explicit height, max-width would otherwise squash the artwork sideways. */
.ts-event .navbar-brand img {
  /* Caps rather than a fixed height, so the box tracks the artwork instead of
     reserving a 260x56 slot and letterboxing a wide mark inside it. width and
     height stay auto so the aspect ratio is the image's own. */
  height: auto; width: auto;
  max-height: 56px; max-width: 260px;
  /* A viewBox-only SVG has no intrinsic size; without a floor it renders at
     the UA default and looks arbitrary. */
  min-height: 40px;
  display: block; flex: none;
}
@media (max-width: 575.98px) {
  .ts-event .navbar-brand img { max-height: 40px; min-height: 32px; }
}

.ts-event .navbar-nav { gap: var(--ts-space-1); align-items: center; }
.ts-event .navbar-nav .nav-link {
  display: inline-flex; align-items: center;
  min-height: 44px;
  padding: var(--ts-space-2) var(--ts-space-3);
  border-radius: var(--ts-radius);
  font-family: var(--ts-font-display);
  /* Not --ts-text-base. The body scale was raised for readability and the nav
     inherited it: nine links at 17.5px needed ~1300px of bar, so the menu ran
     off the side of any 1024-1300px laptop. Navigation is chrome, and sizing
     it with the prose is what broke it. */
  font-size: 1rem;
  font-weight: var(--ts-weight-medium);
  color: var(--ts-event-header-fg, var(--ts-text-muted));
  white-space: nowrap;
  transition: background-color var(--ts-dur-fast) var(--ts-ease),
              color var(--ts-dur-fast) var(--ts-ease);
}
.ts-event .navbar-nav .nav-link:hover { background: var(--ts-bg-subtle); color: var(--ts-text); }

/* Current page: weight plus an underline, so it does not rely on colour. */
.ts-event .navbar-nav .nav-link.active,
.ts-event .navbar-nav .nav-link[aria-current="page"] {
  position: relative;
  color: var(--ts-accent);
  font-weight: var(--ts-weight-semibold);
}
.ts-event .navbar-nav .nav-link.active::after,
.ts-event .navbar-nav .nav-link[aria-current="page"]::after {
  content: "";
  position: absolute; left: var(--ts-space-3); right: var(--ts-space-3); bottom: 6px;
  height: 2px; border-radius: 2px; background: currentColor;
}

/* A registration CTA in the nav should read as the primary action. */
.ts-event .navbar-nav .nav-link.ts-nav-cta {
  background: var(--ts-accent);
  color: var(--ts-text-on-accent);
  padding-inline: var(--ts-space-5);
  font-weight: var(--ts-weight-semibold);
}
.ts-event .navbar-nav .nav-link.ts-nav-cta:hover { background: var(--ts-accent-hover); color: var(--ts-text-on-accent); }
.ts-event .navbar-nav .nav-link.ts-nav-cta::after { display: none; }

/* Between the width the menu stops collapsing at and the width the container
   is comfortably wide at, the links are tightened rather than left to overflow. */
@media (min-width: 1200px) and (max-width: 1399.98px) {
  .ts-event .navbar-nav .nav-link { padding-inline: var(--ts-space-2); }
  .ts-event .navbar-nav .nav-link.ts-nav-cta { padding-inline: var(--ts-space-4); }
  .ts-event .navbar-brand img { max-width: 200px; }
}

.ts-event .navbar-toggler {
  width: 44px; height: 44px;
  padding: 0;
  border: 1px solid var(--ts-border-strong);
  border-radius: var(--ts-radius);
}
.ts-event .navbar-toggler:focus-visible { outline: 3px solid var(--ts-ring); outline-offset: 2px; }

@media (max-width: 991.98px) {
  .ts-event .navbar-collapse { padding-top: var(--ts-space-3); }
  .ts-event .navbar-nav .nav-link { width: 100%; min-height: 48px; }
  .ts-event .navbar-nav .nav-link.active::after { display: none; }
  .ts-event .navbar-nav .nav-link.active { background: var(--ts-accent-soft); }
}

/* --------------------------------------------------------------------------
   Sections and page heads
   -------------------------------------------------------------------------- */
.ts-event section, .ts-event .ts-event-section { padding-block: var(--ts-section-y); }
.ts-event .container { padding-inline: var(--ts-gutter); }

.ts-event-hero {
  position: relative;
  display: flex; align-items: center;
  min-height: min(80vh, 680px);
  padding-block: var(--ts-space-16);
  background: var(--ts-navy-900);
  color: #FFFFFF;
  overflow: hidden;
}
.ts-event-hero__media { position: absolute; inset: 0; z-index: 0; }
.ts-event-hero__media img, .ts-event-hero__media video { width: 100%; height: 100%; object-fit: cover; }
/* Constant scrim: the headline stays legible whatever the image behind it. */
.ts-event-hero__scrim {
  position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg, rgba(2,6,23,.74) 0%, rgba(2,6,23,.55) 50%, rgba(2,6,23,.85) 100%);
}
.ts-event-hero__inner { position: relative; z-index: 2; width: 100%; }
.ts-event-hero h1 { color: #FFFFFF; font-size: var(--ts-text-5xl); margin-bottom: var(--ts-space-4); }
.ts-event-hero p { color: rgba(255,255,255,.86); font-size: var(--ts-text-lg); max-width: 46ch; }

.ts-event-facts {
  display: flex; flex-wrap: wrap; gap: var(--ts-space-8);
  margin-top: var(--ts-space-10);
  padding-top: var(--ts-space-6);
  border-top: 1px solid rgba(255,255,255,.2);
}
.ts-event-facts dt {
  font-size: var(--ts-text-xs); text-transform: uppercase;
  letter-spacing: var(--ts-tracking-wide); color: rgba(255,255,255,.65);
  margin-bottom: 2px;
}
.ts-event-facts dd {
  margin: 0; font-family: var(--ts-font-display);
  font-size: var(--ts-text-lg); font-weight: var(--ts-weight-semibold); color: #FFFFFF;
}

.ts-event-pagehead {
  padding-block: var(--ts-space-12);
  background: var(--ts-event-header-bg, var(--ts-navy-800));
  color: #FFFFFF;
}
.ts-event-pagehead h1 { color: var(--ts-event-header-fg, #FFFFFF); margin-bottom: var(--ts-space-2); }
.ts-event-pagehead p { color: rgba(255,255,255,.8); max-width: var(--ts-measure); margin: 0; }

/* --------------------------------------------------------------------------
   Bootstrap components, remapped
   -------------------------------------------------------------------------- */
.ts-event .btn {
  min-height: 44px;
  display: inline-flex; align-items: center; justify-content: center; gap: var(--ts-space-2);
  padding: var(--ts-space-3) var(--ts-space-5);
  border-radius: var(--ts-radius);
  font-family: var(--ts-font-display);
  font-size: var(--ts-text-base);
  font-weight: var(--ts-weight-semibold);
  cursor: pointer; touch-action: manipulation;
  transition: background-color var(--ts-dur-fast) var(--ts-ease),
              border-color var(--ts-dur-fast) var(--ts-ease),
              color var(--ts-dur-fast) var(--ts-ease);
}
.ts-event .btn-primary { background: var(--ts-accent) !important; border-color: var(--ts-accent) !important; color: #FFFFFF !important; }
.ts-event .btn-primary:hover { background: var(--ts-accent-hover) !important; border-color: var(--ts-accent-hover) !important; }
.ts-event .btn-outline-primary { color: var(--ts-accent); border-color: var(--ts-accent); background: transparent; }
.ts-event .btn-outline-primary:hover { background: var(--ts-accent); color: #FFFFFF; }
.ts-event .btn-light { background: var(--ts-surface); border-color: var(--ts-border-strong); color: var(--ts-text); }
/* Secondary action over a dark hero: a solid border reads as a control. */
.ts-event .btn-outline-light { color: #FFFFFF; border-color: rgba(255,255,255,.7); background: transparent; }
.ts-event .btn-outline-light:hover { background: rgba(255,255,255,.14); border-color: #FFFFFF; color: #FFFFFF; }
.ts-event .btn-success { background: var(--ts-success); border-color: var(--ts-success); color: #FFFFFF; }
.ts-event .btn-danger { background: var(--ts-danger); border-color: var(--ts-danger); color: #FFFFFF; }
.ts-event .btn-sm { min-height: 36px; padding: var(--ts-space-2) var(--ts-space-4); font-size: var(--ts-text-sm); }
.ts-event .btn-lg { min-height: 52px; padding: var(--ts-space-4) var(--ts-space-8); font-size: var(--ts-text-lg); }
.ts-event .btn:disabled { opacity: .45; cursor: not-allowed; }

.ts-event .card {
  border: 1px solid var(--ts-border);
  border-radius: var(--ts-radius-md);
  box-shadow: var(--ts-shadow-sm);
  background: var(--ts-surface);
}
.ts-event .card-header { padding: var(--ts-space-4) var(--ts-space-5); background: var(--ts-surface); border-bottom: 1px solid var(--ts-divider); font-family: var(--ts-font-display); font-weight: var(--ts-weight-semibold); }
.ts-event .card-body { padding: var(--ts-space-5); }
.ts-event .card-footer { padding: var(--ts-space-4) var(--ts-space-5); background: var(--ts-bg-subtle); border-top: 1px solid var(--ts-divider); }
.ts-event .shadow-sm { box-shadow: var(--ts-shadow-sm) !important; }
.ts-event .shadow { box-shadow: var(--ts-shadow-md) !important; }

.ts-event label, .ts-event .form-label {
  display: block; margin-bottom: var(--ts-space-2);
  font-family: var(--ts-font-display); font-size: var(--ts-text-sm);
  font-weight: var(--ts-weight-medium); color: var(--ts-text);
}
.ts-event .form-control, .ts-event .form-select {
  min-height: 44px;
  padding: var(--ts-space-3) var(--ts-space-4);
  border: 1px solid var(--ts-border-strong);
  border-radius: var(--ts-radius);
  font-size: var(--ts-text-base);   /* 16px: stops iOS zooming on focus */
  color: var(--ts-text);
  background: var(--ts-surface);
}
.ts-event .form-control:focus, .ts-event .form-select:focus {
  border-color: var(--ts-accent);
  box-shadow: 0 0 0 3px var(--ts-accent-soft);
  outline: none;
}
.ts-event .form-control.is-invalid { border-color: var(--ts-danger); }
.ts-event .invalid-feedback, .ts-event .text-danger { color: var(--ts-danger); font-size: var(--ts-text-sm); }
.ts-event .form-text { color: var(--ts-text-muted); font-size: var(--ts-text-sm); }
.ts-event .form-check-input { width: 20px; height: 20px; accent-color: var(--ts-accent); }

.ts-event .table { font-size: var(--ts-text-sm); color: var(--ts-text); }
.ts-event .table > thead > tr > th {
  padding: var(--ts-space-3) var(--ts-space-4);
  background: var(--ts-bg-subtle);
  border-bottom: 1px solid var(--ts-border);
  font-family: var(--ts-font-display);
  font-size: var(--ts-text-xs); text-transform: uppercase; letter-spacing: .04em;
  color: var(--ts-text-muted); white-space: nowrap;
}
.ts-event .table > tbody > tr > td { padding: var(--ts-space-3) var(--ts-space-4); border-bottom: 1px solid var(--ts-divider); vertical-align: middle; }
.ts-event .table-responsive { overflow-x: auto; border: 1px solid var(--ts-border); border-radius: var(--ts-radius-md); }

.ts-event .alert {
  padding: var(--ts-space-4) var(--ts-space-5);
  border: 1px solid var(--ts-border);
  border-left-width: 4px;
  border-radius: var(--ts-radius);
  font-size: var(--ts-text-sm);
}
.ts-event .alert-success { background: var(--ts-success-soft); border-left-color: var(--ts-success); color: #14532D; }
.ts-event .alert-danger  { background: var(--ts-danger-soft);  border-left-color: var(--ts-danger);  color: #7F1D1D; }
.ts-event .alert-info    { background: var(--ts-info-soft);    border-left-color: var(--ts-info);    color: #0C4A6E; }
.ts-event .alert-warning { background: var(--ts-warning-soft); border-left-color: var(--ts-warning); color: #78350F; }

.ts-event .badge { padding: 4px var(--ts-space-3); border-radius: var(--ts-radius-pill); font-family: var(--ts-font-display); font-size: var(--ts-text-xs); font-weight: var(--ts-weight-semibold); }

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */
/* ==========================================================================
   Conference footer
   --------------------------------------------------------------------------
   Brand block, then one to three link columns (Quick links and Legal only
   appear when there is something in them; Support always does). The template
   sets --ts-foot-cols to the number of link columns, so the grid has exactly
   the tracks it needs and never wraps one column onto a row of its own.
   ========================================================================== */
.ts-event-footer {
  background: var(--ts-navy-900);
  color: rgba(255,255,255,.72);
  padding-block: var(--ts-space-16) var(--ts-space-6);
  font-size: var(--ts-text-sm);
  line-height: var(--ts-leading-normal, 1.6);
}
.ts-event-footer a {
  color: rgba(255,255,255,.82);
  text-decoration: none;
  transition: color var(--ts-dur-fast) var(--ts-ease);
}
.ts-event-footer a:hover { color: #FFFFFF; text-decoration: underline; text-underline-offset: 3px; }
.ts-event-footer a:focus-visible { outline: 2px solid #FFFFFF; outline-offset: 3px; border-radius: 2px; }
.ts-event-footer p { margin: 0; }

.ts-event-footer__grid {
  display: grid;
  gap: var(--ts-space-10) var(--ts-space-8);
  grid-template-columns: minmax(0, 1fr);
  padding-bottom: var(--ts-space-12);
}
.ts-event-footer__grid > * { min-width: 0; }

/* Phone: brand on its own, link columns two across beneath it. With an odd
   number of link columns the last one takes the whole row rather than sitting
   beside a hole (the brand is child 1, so an even-numbered last child is the
   odd one out). */
.ts-event-footer__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.ts-event-footer__brand { grid-column: 1 / -1; }
@media (max-width: 599.98px) {
  .ts-event-footer__col:last-child:nth-child(even) { grid-column: 1 / -1; }
}
/* Tablet: every link column on one row under the brand. */
@media (min-width: 600px) {
  .ts-event-footer__grid { grid-template-columns: repeat(var(--ts-foot-cols, 3), minmax(0, 1fr)); }
}
/* Desktop: brand wider than a link column, all on one row. */
@media (min-width: 992px) {
  .ts-event-footer__grid {
    grid-template-columns: minmax(0, 1.7fr) repeat(var(--ts-foot-cols, 3), minmax(0, 1fr));
    gap: var(--ts-space-8) var(--ts-space-10);
  }
  .ts-event-footer__brand { grid-column: auto; padding-right: var(--ts-space-8); }
}

/* Brand block */
.ts-event-footer__name {
  font-family: var(--ts-font-display);
  font-size: var(--ts-text-lg);
  font-weight: var(--ts-weight-semibold);
  line-height: 1.3;
  color: #FFFFFF;
}
.ts-event-footer__fullname {
  margin-top: var(--ts-space-1) !important;
  color: rgba(255,255,255,.82);
}
.ts-event-footer__tagline {
  margin-top: var(--ts-space-3) !important;
  max-width: 44ch;
}

.ts-event-footer__contact {
  list-style: none;
  margin: var(--ts-space-6) 0 0;
  padding: var(--ts-space-5) 0 0;
  border-top: 1px solid rgba(255,255,255,.1);
  display: grid;
  gap: var(--ts-space-3);
}
.ts-event-footer__contact li {
  display: grid;
  grid-template-columns: 18px minmax(0, 1fr);
  gap: var(--ts-space-3);
  align-items: baseline;
}
.ts-event-footer__contact i {
  color: var(--ts-hero-highlight, #7CC4F5);
  font-size: .875rem;
  text-align: center;
}
/* An email address is one unbroken word; let it break rather than run into
   the next column. */
.ts-event-footer__contact a,
.ts-event-footer__contact span { overflow-wrap: anywhere; }

/* Link columns */
.ts-event-footer h2 {
  color: #FFFFFF;
  font-family: var(--ts-font-display);
  font-size: var(--ts-text-xs, .8125rem);
  font-weight: var(--ts-weight-semibold);
  text-transform: uppercase;
  letter-spacing: .08em;
  margin: 0 0 var(--ts-space-4);
}
.ts-event-footer__col ul {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: var(--ts-space-2);
}
/* On touch screens every footer link is already 44px tall, which is its own
   spacing -- a gap on top of that spread the lists out to twice the height. */
@media (max-width: 991.98px) {
  .ts-event-footer__col ul,
  .ts-event-footer__contact { gap: 0; }
  .ts-event-footer__contact li { align-items: center; }
  .ts-event-footer__contact li > span { padding-block: var(--ts-space-3); }
  .ts-event-footer__grid { gap: var(--ts-space-8) var(--ts-space-6); }
}
/* Two headings side by side on a phone: "Legal Information" at full tracking
   wrapped to two lines and pushed its list out of line with its neighbour. */
@media (max-width: 599.98px) {
  .ts-event-footer h2 { letter-spacing: .04em; font-size: .75rem; }
}

/* Bottom bar */
.ts-event-footer__bottom {
  display: flex; flex-wrap: wrap; gap: var(--ts-space-4);
  align-items: center; justify-content: space-between;
  padding-top: var(--ts-space-6);
  border-top: 1px solid rgba(255,255,255,.1);
  font-size: var(--ts-text-xs, .8125rem);
  color: rgba(255,255,255,.6);
}
@media (max-width: 575.98px) {
  .ts-event-footer__bottom { flex-direction: column; text-align: center; }
}

/* Floating WhatsApp button: keep it clear of the gesture bar / safe area. */
.ts-event .ts-wa {
  bottom: calc(var(--ts-space-4) + env(safe-area-inset-bottom));
  width: 52px; height: 52px;
}

.ts-event a:focus-visible,
.ts-event button:focus-visible,
.ts-event input:focus-visible,
.ts-event select:focus-visible,
.ts-event textarea:focus-visible {
  outline: 3px solid var(--ts-ring);
  outline-offset: 2px;
}

/* Hero deadline pills: quiet, legible on the dark scrim, and the date is a
   <time> so it is machine-readable. */
.ts-hero-deadlines { display: flex; flex-wrap: wrap; gap: var(--ts-space-3); justify-content: center; margin-top: var(--ts-space-6); }
.ts-hero-deadline {
  display: inline-flex; align-items: baseline; gap: var(--ts-space-2);
  padding: var(--ts-space-3) var(--ts-space-5);
  border: 1px solid rgba(255,255,255,.38);
  border-radius: var(--ts-radius-pill);
  background: rgba(255,255,255,.12);
  color: #FFFFFF;
  /* A submission deadline is one of the few things a visitor is looking for.
     At --ts-text-sm on a photographic hero it could not be read without
     zooming, so it steps up a size and the label's contrast comes with it. */
  font-size: var(--ts-text-base);
  font-weight: var(--ts-weight-medium);
  font-variant-numeric: tabular-nums;
}
.ts-hero-deadline__label { color: rgba(255,255,255,.85); font-weight: var(--ts-weight-regular); }

/* ==========================================================================
   Hero title
   --------------------------------------------------------------------------
   A conference name and its subject are one title -- "International Summit
   and Expo on" / "Advanced Energy Technologies" only makes sense read
   together. They were an h1 plus a small .lead, which read as a headline with
   a caption under it. Same face, same weight, same colour; the subject is a
   touch smaller only so the two lines have a hierarchy to sit in.
   ========================================================================== */
.ts-event .ts-hero-subject {
  display: block;
  font-size: .78em;          /* relative, so every theme's h1 scale carries */
  font-weight: inherit;
  letter-spacing: inherit;
  margin-top: .12em;
  /* The subject is what the conference is actually about, so it is picked out
     rather than left as a second line of the same colour. Organisers can set
     the colour in Header Appearance; the default is the event's own accent,
     lightened enough to hold contrast on a dark hero photograph. */
  color: var(--ts-hero-highlight, var(--ts-hero-highlight-default, #7CC4F5));
}

/* The acronym the conference is actually known by. */
.ts-event .ts-hero-acronym {
  font-family: var(--ts-font-display);
  font-size: var(--ts-text-lg);
  font-weight: var(--ts-weight-bold);
  letter-spacing: .18em;
  text-transform: uppercase;
  margin-bottom: var(--ts-space-3);
  opacity: .92;
}

/* ==========================================================================
   Journal collaborations
   --------------------------------------------------------------------------
   One heading above, the journals below it. The old arrangement was a custom
   "image + text" block, which holds a single image and puts the heading beside
   it -- so it could never show more than one journal.
   ========================================================================== */
.ts-event .ts-journals-head { margin-bottom: var(--ts-space-6); }
.ts-event .ts-journals-intro {
  color: var(--ts-text-muted);
  max-width: var(--ts-measure);
  margin: var(--ts-space-2) 0 0;
}

.ts-event .ts-journals {
  display: grid;
  gap: var(--ts-space-6);
  /* Wide artwork: a journal cover or banner needs room to stay legible, so
     the tracks are generous and a single journal simply sits on its own. */
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr));
}

.ts-event .ts-journal {
  display: flex;
  flex-direction: column;
  background: var(--ts-surface);
  border: 1px solid var(--ts-border);
  border-radius: var(--ts-radius-md);
  overflow: hidden;
  color: inherit;
  text-decoration: none;
  transition: border-color var(--ts-dur-fast) var(--ts-ease),
              box-shadow var(--ts-dur-fast) var(--ts-ease);
}
.ts-event a.ts-journal:hover {
  border-color: var(--accent, var(--ts-accent));
  box-shadow: var(--ts-shadow-md);
}

.ts-event .ts-journal__art {
  background: var(--ts-bg-subtle);
  line-height: 0;
}
.ts-event .ts-journal__art img {
  width: 100%;
  height: auto;              /* the artwork keeps its own proportions */
  display: block;
}

.ts-event .ts-journal__body { padding: var(--ts-space-5); }
.ts-event .ts-journal__name {
  font-family: var(--ts-font-display);
  font-size: var(--ts-text-lg);
  font-weight: var(--ts-weight-semibold);
  margin: 0;
}
.ts-event .ts-journal__meta {
  font-size: var(--ts-text-sm);
  color: var(--ts-text-muted);
  margin: var(--ts-space-1) 0 0;
}
.ts-event .ts-journal__desc {
  font-size: var(--ts-text-sm);
  color: var(--ts-text-muted);
  margin: var(--ts-space-3) 0 0;
}
.ts-event .ts-journal__cta {
  display: inline-block;
  margin-top: var(--ts-space-4);
  font-size: var(--ts-text-sm);
  font-weight: var(--ts-weight-semibold);
  color: var(--accent, var(--ts-accent));
}

/* ==========================================================================
   Conference page components
   --------------------------------------------------------------------------
   These were six separate inline <style> blocks, one per partial, each with
   its own hard-coded greys and breakpoints. Consolidated here so the pages of
   a conference site actually match each other.
   ========================================================================== */

/* ---- page banner ------------------------------------------------------- */
.ts-banner {
  position: relative; overflow: hidden;
  padding-block: var(--ts-space-16) var(--ts-space-12);
  background: var(--ts-event-header-bg, var(--ts-navy-800));
  color: #FFFFFF;
}
.ts-banner-img { position: absolute; inset: 0; background-size: cover; background-position: center; }
/* Fixed scrim: the title stays readable over any photo an organiser uploads. */
.ts-banner-scrim {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(2,6,23,.78) 0%, rgba(2,6,23,.6) 50%, rgba(2,6,23,.84) 100%);
}
.ts-banner-inner { position: relative; z-index: 2; }
.ts-banner h1 {
  color: var(--ts-event-header-fg, #FFFFFF);
  font-size: var(--ts-text-4xl);
  margin-bottom: var(--ts-space-3);
}
.ts-event .ts-banner-sub {
  color: rgba(255,255,255,.84);
  font-size: var(--ts-text-lg);
  line-height: var(--ts-leading-relaxed);
  max-width: var(--ts-measure);
  margin: 0 0 var(--ts-space-4);
}
.ts-crumbs { display: flex; flex-wrap: wrap; gap: var(--ts-space-2); font-size: var(--ts-text-sm); color: rgba(255,255,255,.7); }
.ts-crumbs a { color: rgba(255,255,255,.85); text-decoration: none; }
.ts-crumbs a:hover { color: #FFFFFF; text-decoration: underline; }
.ts-crumbs .current { color: #FFFFFF; font-weight: var(--ts-weight-medium); }

/* ---- page body --------------------------------------------------------- */
.ts-page-body { padding-block: var(--ts-section-y); }
.ts-event .ts-page-intro {
  font-size: var(--ts-text-lg);
  line-height: var(--ts-leading-relaxed);
  color: var(--ts-text-muted);
  max-width: var(--ts-measure);
  margin-bottom: var(--ts-space-10);
}

/* Section heading shared across the conference pages. */
.ts-event .ts-event-h2 {
  font-size: var(--ts-text-2xl);
  margin-bottom: var(--ts-space-6);
  padding-bottom: var(--ts-space-3);
  border-bottom: 2px solid var(--ts-border);
}

/* ---- key facts --------------------------------------------------------- */
.ts-facts {
  display: grid; gap: 0; margin: 0 0 var(--ts-space-10);
  border: 1px solid var(--ts-border);
  border-radius: var(--ts-radius-md);
  background: var(--ts-surface);
  overflow: hidden;
}
/* auto-fit rather than fixed breakpoints: the row drops to fewer columns by
   itself when a value (an email address, typically) needs the room. */
.ts-facts { grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr)); }
.ts-facts > div { padding: var(--ts-space-5); border-bottom: 1px solid var(--ts-divider); }
@media (min-width: 700px) { .ts-facts > div { border-right: 1px solid var(--ts-divider); } }
.ts-facts > div:last-child { border-right: 0; border-bottom: 0; }
.ts-facts dt {
  font-size: var(--ts-text-xs); text-transform: uppercase;
  letter-spacing: var(--ts-tracking-wide); color: var(--ts-text-subtle);
  margin-bottom: var(--ts-space-2);
}
.ts-facts dd {
  margin: 0; font-family: var(--ts-font-display);
  font-weight: var(--ts-weight-semibold); color: var(--ts-text);
  font-size: var(--ts-text-base);
  /* An email or URL is one long token: allow a break so it can never force
     the page sideways, but only as a last resort. */
  overflow-wrap: break-word;
}

/* ---- people (committee, speakers) -------------------------------------- */
.ts-people-grid { display: grid; gap: var(--ts-space-6); grid-template-columns: repeat(auto-fill, minmax(min(100%, 200px), 1fr)); }
.ts-people-grid .ts-person { text-align: center; }
.ts-people-grid .ts-person img,
.ts-people-grid .ts-person-placeholder {
  width: 132px; height: 132px; margin: 0 auto var(--ts-space-4);
  border-radius: 50%; object-fit: cover; display: block;
  background: var(--ts-bg-subtle); border: 1px solid var(--ts-border);
}
.ts-people-grid .ts-person h3 { font-size: var(--ts-text-base); font-weight: var(--ts-weight-semibold); margin-bottom: 2px; }
.ts-people-grid .ts-person p { font-size: var(--ts-text-sm); color: var(--ts-text-muted); margin: 0; }

/* ---- topics ------------------------------------------------------------ */
.ts-topics { display: grid; gap: var(--ts-space-5); grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr)); }
.ts-topic {
  height: 100%;
  padding: var(--ts-space-5);
  background: var(--ts-surface);
  border: 1px solid var(--ts-border);
  border-radius: var(--ts-radius-md);
  /* Shadow and border move on hover, the box does not, so the grid never
     shifts under the pointer. */
  transition: box-shadow var(--ts-dur) var(--ts-ease), border-color var(--ts-dur) var(--ts-ease);
}
.ts-topic:hover { box-shadow: var(--ts-shadow-md); border-color: var(--ts-accent-border); }
.ts-topic-icon { color: var(--ts-accent); font-size: 1.4rem; margin-bottom: var(--ts-space-3); display: block; }
.ts-event .ts-topic-title { font-family: var(--ts-font-display); font-size: var(--ts-text-base); font-weight: var(--ts-weight-semibold); color: var(--ts-text); margin-bottom: var(--ts-space-2); }
.ts-event .ts-topic-desc { color: var(--ts-text-muted); font-size: var(--ts-text-sm); line-height: var(--ts-leading-relaxed); }

/* ---- programme --------------------------------------------------------- */
.ts-schedule {
  border: 1px solid var(--ts-border);
  border-radius: var(--ts-radius-md);
  background: var(--ts-surface);
  overflow: hidden;
}
.ts-day-tabs { display: flex; flex-wrap: wrap; border: 0; margin: 0; background: var(--ts-bg-subtle); }
.ts-day-tabs .nav-item { flex: 1 1 160px; }
.ts-day-tabs .nav-link {
  width: 100%; min-height: 64px;
  border: 0; border-bottom: 3px solid transparent; border-radius: 0;
  padding: var(--ts-space-3);
  background: transparent;
  /* 7.4:1 on the subtle background. The previous rgba(255,255,255,.65) on
     navy left the inactive days barely readable. */
  color: var(--ts-text-muted);
  font-family: var(--ts-font-display);
  text-align: center;
  transition: background-color var(--ts-dur-fast) var(--ts-ease), color var(--ts-dur-fast) var(--ts-ease);
}
.ts-day-tabs .nav-link:hover { background: var(--ts-surface); color: var(--ts-text); }
.ts-day-tabs .nav-link.active {
  background: var(--ts-surface);
  color: var(--ts-accent);
  border-bottom-color: var(--ts-accent);
  font-weight: var(--ts-weight-semibold);
}
.ts-day-tabs .nav-link:focus-visible { outline: 3px solid var(--ts-ring); outline-offset: -3px; }
.ts-day-tabs .nav-link small { display: block; font-weight: var(--ts-weight-regular); font-size: var(--ts-text-xs); }

.ts-day-panels { background: var(--ts-surface); }
.ts-schedule .ts-session {
  display: grid; gap: var(--ts-space-2) var(--ts-space-6);
  grid-template-columns: minmax(150px, 190px) 1fr;
  padding: var(--ts-space-4) var(--ts-space-5);
  border-bottom: 1px solid var(--ts-divider);
}
.ts-schedule .ts-session:last-child { border-bottom: 0; }
.ts-session-time { color: var(--ts-accent); font-family: var(--ts-font-display); font-weight: var(--ts-weight-semibold); font-variant-numeric: tabular-nums; }
.ts-event .ts-session-title { font-family: var(--ts-font-display); font-size: var(--ts-text-base); font-weight: var(--ts-weight-semibold); color: var(--ts-text); margin: 0; }
.ts-event .ts-session-speaker { color: var(--ts-text-muted); font-size: var(--ts-text-sm); margin-top: 2px; }
.ts-event .ts-session-desc { color: var(--ts-text-muted); font-size: var(--ts-text-sm); margin-top: var(--ts-space-2); }
@media (max-width: 700px) {
  /* A 190px time column beside the title squeezed session names into a strip. */
  .ts-schedule .ts-session { grid-template-columns: 1fr; }
}

/* ---- mailboxes --------------------------------------------------------- */
.ts-mailboxes { display: grid; gap: var(--ts-space-4); grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr)); margin-bottom: var(--ts-space-8); }
.ts-mailbox {
  padding: var(--ts-space-4) var(--ts-space-5);
  background: var(--ts-bg-subtle);
  border-left: 3px solid var(--ts-accent);
  border-radius: var(--ts-radius);
}
.ts-event .ts-mailbox__label { font-size: var(--ts-text-xs); text-transform: uppercase; letter-spacing: var(--ts-tracking-wide); color: var(--ts-text-subtle); margin-bottom: 2px; }
.ts-mailbox a { overflow-wrap: anywhere; }

/* ---- two-column page split (content + aside) --------------------------- */
.ts-split { display: grid; gap: var(--ts-space-10); grid-template-columns: 1fr; align-items: start; }
@media (min-width: 992px) { .ts-split { grid-template-columns: minmax(0, 1fr) 340px; } }

/* speaker_grid's card is now a real <button> for keyboard activation, so the
   browser default button styling has to be neutralised. */
.ts-event .spk-card {
  display: block; width: 100%; padding: 0;
  font: inherit; color: inherit; text-align: center;
  -webkit-appearance: none; appearance: none;
}
.ts-event .spk-card:focus-visible { outline: 3px solid var(--ts-ring); outline-offset: 2px; }
.ts-event .spk-body span { display: block; }
.ts-event .spk-name { font-family: var(--ts-font-display); font-size: var(--ts-text-base); font-weight: var(--ts-weight-semibold); color: var(--ts-text); }
.ts-event .spk-role, .ts-event .spk-org { font-size: var(--ts-text-sm); color: var(--ts-text-muted); }

/* ==========================================================================
   Home-page sections (front/event/sections/*)
   ========================================================================== */

/* Organiser-selectable section backgrounds, driven by EventSection. */
.ts-event .ts-section--roomy { padding-block: calc(var(--ts-section-y) * 1.4); }
.ts-event .ts-section--accent { background: var(--ts-accent); color: #FFFFFF; }
.ts-event .ts-section--accent h2,
.ts-event .ts-section--accent h3,
.ts-event .ts-section--accent h4 { color: #FFFFFF; }
.ts-event .ts-section--accent p { color: rgba(255,255,255,.86); }
.ts-event .ts-section--accent .ts-event-h2 { border-bottom-color: rgba(255,255,255,.3); }
.ts-event .ts-section--ink .ts-event-h2 { border-bottom-color: rgba(255,255,255,.2); }
.ts-event .ts-section--ink .ts-card { background: rgba(255,255,255,.06); border-color: rgba(255,255,255,.14); }
.ts-event .ts-section--ink .ts-card * { color: rgba(255,255,255,.86); }

/* Tier label above a group of logos. */
.ts-event .ts-tier-label {
  font-family: var(--ts-font-display);
  font-size: var(--ts-text-xs);
  font-weight: var(--ts-weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--ts-tracking-wide);
  color: var(--ts-text-subtle);
  margin-bottom: var(--ts-space-4);
}

/* Logo tiles: a consistent box so logos of different proportions still line
   up, rather than each sitting at its own height. */
.ts-event .ts-logo-tile {
  display: flex; align-items: center; justify-content: center;
  min-height: 96px; padding: var(--ts-space-4);
  background: var(--ts-surface);
  border: 1px solid var(--ts-border);
  border-radius: var(--ts-radius-md);
  transition: border-color var(--ts-dur-fast) var(--ts-ease),
              box-shadow var(--ts-dur-fast) var(--ts-ease);
}
.ts-event .ts-logo-tile:hover { border-color: var(--ts-accent-border); box-shadow: var(--ts-shadow-sm); }
.ts-event .ts-logo-tile img { max-height: 56px; width: auto; max-width: 100%; }

/* Speaker biography disclosure. */
.ts-event .ts-bio { margin-top: var(--ts-space-3); text-align: left; }
.ts-event .ts-bio > summary {
  display: inline-flex; align-items: center; gap: var(--ts-space-1);
  min-height: 36px; padding: var(--ts-space-1) 0;
  list-style: none; cursor: pointer;
  font-family: var(--ts-font-display);
  font-size: var(--ts-text-sm); font-weight: var(--ts-weight-medium);
  color: var(--ts-accent);
}
.ts-event .ts-bio > summary::-webkit-details-marker { display: none; }
.ts-event .ts-bio > summary::after { content: "\203A"; transform: rotate(90deg); display: inline-block; }
.ts-event .ts-bio[open] > summary::after { transform: rotate(-90deg); }
.ts-event .ts-bio > summary:focus-visible { outline: 3px solid var(--ts-ring); outline-offset: 2px; }
/* 36px is fine for a mouse (WCAG 2.2 asks 24) but under the 44px a thumb
   needs, and this is the one control on a speaker tile. */
@media (max-width: 991.98px) {
  .ts-event .ts-bio > summary { min-height: 44px; }
}
.ts-event .ts-bio__panel {
  margin-top: var(--ts-space-2);
  font-size: var(--ts-text-sm);
  line-height: var(--ts-leading-relaxed);
  color: var(--ts-text-muted);
}

/* Updates timeline. */
.ts-event .ts-updates { list-style: none; margin: 0; padding: 0; display: grid; gap: 0; }
.ts-event .ts-update {
  display: grid; gap: var(--ts-space-2) var(--ts-space-6);
  grid-template-columns: minmax(110px, 150px) 1fr;
  padding: var(--ts-space-5) 0;
  border-bottom: 1px solid var(--ts-divider);
}
.ts-event .ts-update:last-child { border-bottom: 0; }
.ts-event .ts-update__date {
  font-family: var(--ts-font-display); font-weight: var(--ts-weight-semibold);
  color: var(--ts-accent); font-variant-numeric: tabular-nums;
}
.ts-event .ts-update__title { font-family: var(--ts-font-display); font-size: var(--ts-text-lg); font-weight: var(--ts-weight-semibold); margin: 0 0 var(--ts-space-2); }
.ts-event .ts-update__body { color: var(--ts-text-muted); font-size: var(--ts-text-sm); line-height: var(--ts-leading-relaxed); }
@media (max-width: 700px) { .ts-event .ts-update { grid-template-columns: 1fr; } }

/* Gallery. */
.ts-event .ts-gallery { display: grid; gap: var(--ts-space-3); grid-template-columns: repeat(auto-fill, minmax(min(100%, 200px), 1fr)); }
.ts-event .ts-gallery__item { margin: 0; border-radius: var(--ts-radius); overflow: hidden; background: var(--ts-bg-subtle); }
.ts-event .ts-gallery__item img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; display: block; }

/* ==========================================================================
   Custom (staff-authored) home sections
   Replaces the inline <style> the partial used to carry, so a custom block
   sits on the same scale and rhythm as the built-in sections.
   ========================================================================== */
.ts-event .ts-custom-heading {
  font-size: var(--ts-text-2xl);
  font-family: var(--ts-font-display);
  font-weight: var(--ts-weight-semibold);
  line-height: var(--ts-leading-tight);
  margin-bottom: var(--ts-space-3);
}
.ts-event .ts-custom-body { color: var(--ts-text-muted); line-height: var(--ts-leading-relaxed); max-width: var(--ts-measure); }
.ts-event .ts-custom-muted-light { color: var(--ts-text-muted); max-width: var(--ts-measure); }
.ts-event .ts-custom-muted { color: rgba(255,255,255,.75); max-width: var(--ts-measure); }

/* image + text */
.ts-event .ts-custom-split {
  display: grid; gap: var(--ts-space-8);
  grid-template-columns: 1fr; align-items: center;
}
@media (min-width: 768px) {
  .ts-event .ts-custom-split:has(.ts-custom-media) { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); }
}
.ts-event .ts-custom-split.is-centred { text-align: center; }
.ts-event .ts-custom-split.is-centred .ts-custom-body,
.ts-event .ts-custom-split.is-centred .ts-custom-muted-light,
.ts-event .ts-custom-split.is-centred .ts-custom-muted { margin-inline: auto; }
.ts-event .ts-custom-media { text-align: center; }
.ts-event .ts-custom-media img {
  max-height: 260px; width: auto; max-width: 100%;
  object-fit: contain; display: block; margin-inline: auto;
  border-radius: var(--ts-radius);
}
@media (max-width: 767.98px) { .ts-event .ts-custom-media img { max-height: 180px; } }

.ts-event .ts-img-link { display: inline-block; transition: opacity var(--ts-dur-fast) var(--ts-ease); }
.ts-event .ts-img-link:hover { opacity: .85; }
.ts-event .ts-img-link:focus-visible { outline: 3px solid var(--ts-ring); outline-offset: 4px; }

/* banner */
.ts-event .ts-custom-banner {
  position: relative; overflow: hidden;
  padding: var(--ts-space-10) var(--ts-space-8);
  border-radius: var(--ts-radius-lg);
  background: var(--ts-bg-subtle);
}
.ts-event .ts-custom-banner.has-image { background: var(--ts-navy-900); color: #FFFFFF; }
.ts-event .ts-custom-banner__img { position: absolute; inset: 0; background-size: cover; background-position: center; }
.ts-event .ts-custom-banner__scrim { position: absolute; inset: 0; background: rgba(2,6,23,.62); }
.ts-event .ts-custom-banner__inner { position: relative; z-index: 1; max-width: var(--ts-measure); }
.ts-event .ts-custom-banner.has-image .ts-custom-heading { color: #FFFFFF; }
.ts-event .ts-custom-banner.has-image p,
.ts-event .ts-custom-banner.has-image .ts-custom-body { color: rgba(255,255,255,.86); }
.ts-event .ts-custom-banner .btn { margin-top: var(--ts-space-4); }

/* quote */
.ts-event .ts-custom-quote { max-width: 60ch; margin-inline: auto; text-align: center; }
.ts-event .ts-custom-quote blockquote {
  margin: 0 0 var(--ts-space-5);
  font-size: var(--ts-text-xl);
  line-height: var(--ts-leading-relaxed);
  color: var(--ts-text);
}
.ts-event .ts-custom-quote figcaption { font-size: var(--ts-text-sm); }
.ts-event .ts-custom-quote figcaption strong { display: block; font-family: var(--ts-font-display); }
.ts-event .ts-custom-quote figcaption span { display: block; }

/* cta */
.ts-event .ts-custom-cta { text-align: center; }
.ts-event .ts-custom-cta .ts-custom-body,
.ts-event .ts-custom-cta .ts-custom-muted-light,
.ts-event .ts-custom-cta .ts-custom-muted { margin-inline: auto; }
.ts-event .ts-custom-cta .btn { margin-top: var(--ts-space-4); }

/* A capped measure inside a centred block still needs auto margins, or the
   narrower box hugs the left edge while everything around it is centred.
   This showed up as the hero tagline sitting left under a centred title. */
.ts-event .text-center .lead,
.ts-event .text-center > p,
.ts-event .text-center .ts-prose { margin-inline: auto; }

/* Empty-state and person-card headings carry their level for the document
   outline; their size comes from here, not from the tag. */
.ts-empty-title, .ts-empty h2 { font-size: var(--ts-text-lg); color: var(--ts-text); margin-bottom: var(--ts-space-2); }
.ts-event .ts-person-name { font-size: var(--ts-text-base); font-weight: var(--ts-weight-semibold); margin-bottom: 2px; }

@media (max-width: 640px) {
  .ts-event .ts-event-hero { min-height: auto; padding-block: var(--ts-space-12); }
  /* A square conference badge caps at 40px tall on a phone, which left the
     link 40px wide -- under the 44px touch floor on the shorter axis. The
     height was already guarded; the width was not. */
  .ts-event .navbar-brand {
    min-height: 44px;
    min-width: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: flex-start;
  }
}
input.form-control, select.form-select, textarea.form-control {
  font-size: max(16px, var(--ts-text-base));
}

/* Footer and standalone content links are navigation on a phone, so they get
   a real target height rather than the 20px their text happens to occupy. */
.ts-event a.small.d-inline-block {
  display: inline-block;
  padding-block: var(--ts-space-3);
}
.ts-event-footer ul a,
.ts-event-footer__bottom a {
  display: inline-block;
  min-height: 24px;
  padding-block: 2px;
}
.pbn-logo, .ts-event .pbn-logo {
  display: inline-flex; align-items: center;
  min-height: 44px;
}

/* A mailto/tel link in the key-facts strip is something people tap. */
.ts-event .ts-facts dd a,
.ts-event .ts-detail-list dd a {
  display: inline-block;
  padding-block: var(--ts-space-2);
}

/* Checkboxes and radios meet the 24px pointer-target floor, and the row they
   sit in is tall enough to tap comfortably. The label is associated, so the
   whole row is the target. */
.ts-event .form-check-input,
.ts-event input[type=checkbox],
.ts-event input[type=radio] { width: 24px; height: 24px; margin-top: .15rem; }
.ts-event .form-check { min-height: 44px; display: flex; align-items: flex-start; gap: var(--ts-space-3); padding-left: 0; }
.ts-event .form-check .form-check-input { margin-left: 0; flex: none; }
.ts-event .form-check-label { padding-block: var(--ts-space-1); }

/* ==========================================================================
   Conference checkout (registration and sponsorship)
   --------------------------------------------------------------------------
   Both screens used to be bare Bootstrap with their own inline colours. They
   now sit on the same banner, container and card language as the rest of the
   conference site, and take the event's accent from --accent like every other
   per-event component.
   ========================================================================== */
.ts-event .ts-checkout-form { max-width: 900px; }

.ts-event .ts-checkout-card {
  background: var(--ts-surface);
  border: 1px solid var(--ts-border);
  border-radius: var(--ts-radius-md);
  margin-block: var(--ts-space-6);
}
.ts-event .ts-checkout-card__body { padding: var(--ts-space-5) var(--ts-space-6); }

.ts-event .ts-checkout-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ts-space-4);
  flex-wrap: wrap;
}

.ts-event .ts-checkout-price {
  font-family: var(--ts-font-display);
  font-size: var(--ts-text-2xl);
  font-weight: var(--ts-weight-bold);
  font-variant-numeric: tabular-nums;
  color: var(--accent, var(--ts-accent));
}
.ts-event .ts-checkout-price--lg { font-size: var(--ts-text-3xl); display: block; margin-block: var(--ts-space-2) var(--ts-space-4); }

/* The heading between form steps. h2 so the outline runs h1 -> h2, which is
   what the page banner's h1 leaves room for. */
.ts-event .ts-checkout-legend {
  font-size: var(--ts-text-lg);
  font-weight: var(--ts-weight-semibold);
  margin-block: var(--ts-space-8) var(--ts-space-4);
}

.ts-event .ts-checkout-field { margin-block: var(--ts-space-6); border: 0; padding: 0; }
.ts-event .ts-checkout-field legend { float: none; width: auto; }

.ts-event .ts-checkout-package-name {
  font-family: var(--ts-font-display);
  font-weight: var(--ts-weight-semibold);
  font-size: var(--ts-text-lg);
}
.ts-event .ts-checkout-benefits {
  list-style: none; padding: 0; margin: 0 0 var(--ts-space-4);
}
.ts-event .ts-checkout-benefits li {
  position: relative;
  padding-left: var(--ts-space-6);
  padding-block: var(--ts-space-1);
  font-size: var(--ts-text-sm);
  color: var(--ts-text-muted);
}
/* A tick drawn in CSS rather than an icon font, so the list still reads
   correctly if the font fails to load. */
.ts-event .ts-checkout-benefits li::before {
  content: "";
  position: absolute;
  left: 2px; top: .75em;
  width: 10px; height: 5px;
  border-left: 2px solid var(--ts-success, #16a34a);
  border-bottom: 2px solid var(--ts-success, #16a34a);
  transform: rotate(-45deg);
}

.ts-event .ts-muted { color: var(--ts-text-muted); font-size: var(--ts-text-sm); }

.ts-event .btn-accent {
  background: var(--accent, var(--ts-accent));
  border-color: var(--accent, var(--ts-accent));
  color: #FFFFFF;
  font-weight: var(--ts-weight-semibold);
  min-height: 48px;
}
.ts-event .btn-accent:hover,
.ts-event .btn-accent:focus { filter: brightness(1.1); color: #FFFFFF; }

/* ==========================================================================
   Conference site on a phone
   --------------------------------------------------------------------------
   The theme's small-button and inline-link sizes land in the 37-41px range,
   which clears WCAG 2.2's 24px floor but is short of the 44px touch target the
   rest of the design system uses. Lifted for touch only, so the desktop
   density of the sponsor and registration tables is unchanged.
   ========================================================================== */
@media (max-width: 767.98px) {
  .ts-event .btn,
  .ts-event .btn-sm {
    min-height: 44px;
    min-width: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  /* Standalone mail/tel/detail links: a real row height, not the 20px their
     text happens to occupy plus a couple of pixels of padding. */
  .ts-event .ts-facts dd a,
  .ts-event .ts-detail-list dd a,
  .ts-event a.small.d-inline-block,
  .ts-event-footer ul a,
  .ts-event-footer__bottom a {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }
}

/* A room choice and its unit count on one row, stacking under 640px where the
   two halves would otherwise be squeezed to nothing. */
.ts-event .ts-accom-row {
  display: flex;
  align-items: flex-start;
  gap: var(--ts-space-4);
  padding-block: var(--ts-space-3);
  border-top: 1px solid var(--ts-divider);
}
.ts-event .ts-accom-row .form-check { flex: 1 1 auto; }
.ts-event .ts-accom-row__qty { flex: 0 0 120px; }
.ts-event .ts-accom-row__qty .form-label { font-size: var(--ts-text-sm); }
@media (max-width: 640px) {
  .ts-event .ts-accom-row { flex-direction: column; gap: var(--ts-space-2); }
  .ts-event .ts-accom-row__qty { flex: 1 1 auto; width: 120px; }
}

/* ==========================================================================
   Hero call-to-action row (all three conference themes)
   --------------------------------------------------------------------------
   The two buttons used to sit in a plain centred block, spaced with Bootstrap's
   `me-2` on the first one, and each theme stacked them on a phone with
   `display:block; margin: 0 auto`. Those two fight: `.me-2` is
   `margin-right: .5rem !important`, so on the stacked layout the first button
   kept a fixed right margin while its left margin stayed `auto` -- pushing it
   ~90px right of the button below it.

   One flex row with a gap instead: no margin utilities, nothing to centre by
   hand, and the same rule serves both orientations.
   ========================================================================== */
.ts-event .ts-hero-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: var(--ts-space-3);
}

@media (max-width: 768px) {
  /* Full-width and stacked, so the two read as a clear first and second
     choice rather than two half-width buttons on a cramped line. */
  .ts-event .ts-hero-actions { flex-direction: column; }
  .ts-event .ts-hero-actions .btn { width: 100%; max-width: 300px; }
}

/* ==========================================================================
   Legal pages (privacy policy, terms, cancellation)
   --------------------------------------------------------------------------
   The longest prose on a conference site, and the worst thing to read at full
   container width -- so it is held to a reading measure and given generous
   leading. The content is staff-authored through the editor, so the styling
   has to cover whatever headings and lists they use.
   ========================================================================== */
.ts-event .ts-legal {
  max-width: var(--ts-measure);
  color: var(--ts-text);
  line-height: var(--ts-leading-relaxed);
}
.ts-event .ts-legal > :first-child { margin-top: 0; }
.ts-event .ts-legal p { margin-bottom: var(--ts-space-5); }
.ts-event .ts-legal h1,
.ts-event .ts-legal h2,
.ts-event .ts-legal h3,
.ts-event .ts-legal h4 {
  font-family: var(--ts-font-display);
  font-weight: var(--ts-weight-semibold);
  line-height: var(--ts-leading-tight);
  margin: var(--ts-space-10) 0 var(--ts-space-4);
}
.ts-event .ts-legal h1 { font-size: var(--ts-text-2xl); }
.ts-event .ts-legal h2 { font-size: var(--ts-text-xl); }
.ts-event .ts-legal h3,
.ts-event .ts-legal h4 { font-size: var(--ts-text-lg); }

.ts-event .ts-legal ul,
.ts-event .ts-legal ol { margin: 0 0 var(--ts-space-5); padding-left: var(--ts-space-6); }
/* The marker has to be set on the li, not the list: the theme resets
   `li { list-style: none }` globally for its nav menus, and that beats a
   list-style-type on the ul. Without this a policy's clauses render as
   indented paragraphs with no bullets at all. */
.ts-event .ts-legal ul > li { list-style: disc outside; }
.ts-event .ts-legal ol > li { list-style: decimal outside; }
.ts-event .ts-legal li { margin-bottom: var(--ts-space-2); }

.ts-event .ts-legal a {
  color: var(--accent, var(--ts-accent));
  text-underline-offset: 2px;
  overflow-wrap: anywhere;   /* policy text often carries bare URLs */
}

/* Cross-links to the other policies, so someone reading one can reach the
   rest without going back to the footer. */
.ts-event .ts-legal-more {
  margin-top: var(--ts-space-12);
  padding-top: var(--ts-space-6);
  border-top: 1px solid var(--ts-divider);
}
.ts-event .ts-legal-more h2 {
  font-size: var(--ts-text-sm);
  font-weight: var(--ts-weight-semibold);
  letter-spacing: var(--ts-tracking-wide);
  text-transform: uppercase;
  color: var(--ts-text-muted);
  margin-bottom: var(--ts-space-3);
}
.ts-event .ts-legal-more ul {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: var(--ts-space-2) var(--ts-space-6);
}
.ts-event .ts-legal-more a {
  display: inline-flex; align-items: center;
  min-height: 44px;
  color: var(--accent, var(--ts-accent));
}

/* ==========================================================================
   Overall content size
   --------------------------------------------------------------------------
   The conference sites were set on a 16px body, which is the floor for
   avoiding iOS zoom-on-focus rather than a comfortable reading size for a
   page people scan on a phone at arm's length.

   Raised by scaling the tokens on .ts-event rather than by editing the shared
   scale: the admin panel and the main site keep their own sizes, and every
   component that already reads --ts-text-* moves together, so the rhythm
   between headings, body and labels is preserved instead of one element
   growing out of step.

   16 -> 17.5px body, with the display sizes taken up proportionally. The two
   floors that exist for a functional reason -- form inputs at 16px, and the
   xs label size -- are deliberately unchanged.
   ========================================================================== */
.ts-event {
  --ts-text-sm:   .9375rem;   /* 15   was 14 */
  --ts-text-base: 1.09375rem; /* 17.5 was 16 */
  --ts-text-lg:   1.25rem;    /* 20   was 18 */
  --ts-text-xl:   clamp(1.375rem, 1.28rem + .35vw, 1.5rem);
  --ts-text-2xl:  clamp(1.625rem, 1.48rem + .6vw,  1.9375rem);
  --ts-text-3xl:  clamp(2.0625rem, 1.8rem + 1vw,   2.5rem);
  --ts-text-4xl:  clamp(2.5rem,   2.1rem + 1.7vw,  3.375rem);
  --ts-text-5xl:  clamp(3rem,     2.3rem + 3vw,    4.5rem);

  /* A larger body needs a little more air between lines to stay comfortable. */
  --ts-leading-normal: 1.6;
}

/* Inputs keep the 16px floor: anything smaller makes iOS zoom on focus and
   never zoom back, and they are already comfortable at that size. */
.ts-event input,
.ts-event select,
.ts-event textarea,
.ts-event .form-control,
.ts-event .form-select { font-size: max(16px, 1rem); }

/* ==========================================================================
   Venue media (home page)
   --------------------------------------------------------------------------
   The map and the venue photographs share the right-hand column. One photo
   sits full width under the map; two or more tile, so a venue with a handful
   of shots does not turn into a long vertical strip.
   ========================================================================== */
/* Address beside the map. Explicit columns rather than auto-fit: auto-fit sized
   a third track for a two-item grid and collapsed it to 0px, leaving a stray
   gap on the right. */
.ts-event .ts-venue-layout {
  display: grid;
  gap: var(--ts-space-8);
  align-items: center;
}
.ts-event .ts-venue-layout > * { min-width: 0; }
@media (min-width: 992px) {
  .ts-event .ts-venue-layout { grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr); }
  .ts-event .ts-venue-layout.is-single { grid-template-columns: minmax(0, 1fr); }
}

.ts-event .ts-venue-map {
  border-radius: var(--ts-radius-md);
  overflow: hidden;
  border: 1px solid var(--ts-border);
}

/* Photographs, full width under the map.

   A fixed column count rather than auto-fit, because the last row has to be
   made to fill and that needs the count to be known. Whatever is left over --
   one photograph in a three-column row, or two -- is stretched across the
   remaining tracks, so the row is never part empty. The crop widens with the
   span so a stretched photograph does not also become enormously tall. */
.ts-event .ts-venue-shots {
  list-style: none; margin: var(--ts-space-8) 0 0; padding: 0;
  display: grid; gap: var(--ts-space-4);
  grid-template-columns: minmax(0, 1fr);
}
/* Bounded at both ends: an unbounded min-width block leaves the two-column
   leftover rule live at three columns, where it made a third photograph -- a
   full row on its own -- span the grid. */
@media (min-width: 600px) and (max-width: 991.98px) {
  .ts-event .ts-venue-shots { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ts-event .ts-venue-shots li:nth-child(2n+1):last-child { grid-column: 1 / -1; }
  .ts-event .ts-venue-shots li:nth-child(2n+1):last-child img { aspect-ratio: 21 / 9; }
}
@media (min-width: 992px) {
  /* Column count set per photograph count in the template. */
  .ts-event .ts-venue-shots { grid-template-columns: repeat(var(--ts-shot-cols, 3), minmax(0, 1fr)); }
  /* Leftovers only arise in thirds, and only for counts that cannot divide by
     three. The rules are confined to that case so two photographs stay two
     equal halves rather than a third beside two thirds. */
  .ts-event .ts-venue-shots.is-thirds li:nth-child(3n+1):last-child { grid-column: 1 / -1; }
  .ts-event .ts-venue-shots.is-thirds li:nth-child(3n+1):last-child img { aspect-ratio: 21 / 9; }
  .ts-event .ts-venue-shots.is-thirds li:nth-child(3n+2):last-child { grid-column: span 2; }
  .ts-event .ts-venue-shots.is-thirds li:nth-child(3n+2):last-child img { aspect-ratio: 16 / 7; }
}
.ts-event .ts-venue-shots figure { margin: 0; }
.ts-event .ts-venue-shots img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;         /* crops rather than distorting whatever is uploaded */
  border-radius: var(--ts-radius-md);
  border: 1px solid var(--ts-border);
  display: block;
}
.ts-event .ts-venue-shots figcaption {
  margin-top: var(--ts-space-2);
  font-size: var(--ts-text-sm);
  color: var(--ts-text-muted);
}

/* ==========================================================================
   Speaker group headings
   --------------------------------------------------------------------------
   Sessions first, then the tier categories. A category can carry its own
   background image; without one the heading renders exactly as before, so an
   event that sets no artwork is unchanged.
   ========================================================================== */
.ts-event .spk-group { margin-bottom: var(--ts-space-5); }
.ts-event .spk-group-intro {
  color: var(--ts-text-muted);
  max-width: var(--ts-measure);
  margin: var(--ts-space-2) 0 0;
}

.ts-event .spk-group.has-bg {
  position: relative;
  background-size: cover;
  background-position: center;
  border-radius: var(--ts-radius-md);
  overflow: hidden;
  padding: var(--ts-space-8) var(--ts-space-6);
}
/* A fixed scrim, so the heading stays legible over whatever photograph an
   organiser uploads rather than depending on the image being dark enough. */
.ts-event .spk-group-scrim {
  position: absolute; inset: 0;
  background: linear-gradient(90deg, rgba(8,15,30,.82) 0%, rgba(8,15,30,.55) 100%);
}
.ts-event .spk-group.has-bg h2 {
  position: relative;
  color: #FFFFFF;
  margin: 0;
}

/* ==========================================================================
   Hero scrim strength
   --------------------------------------------------------------------------
   Extra darkness over the hero photograph, for a banner too bright to carry
   white text. Organisers set it in Header Appearance.

   It ADDS to the theme's own scrim rather than scaling it. Scaling could only
   ever make the hero lighter -- the theme's gradient was already the darkest
   the setting could reach -- so the control did the opposite of what its label
   promised. Unset is 0: nothing painted, the design unchanged.

   An inset shadow rather than another overlay element, because both themes
   have already spent their one free pseudo-element on their own gradient
   (classic ::before, bold ::after). An inset shadow paints above the
   background image and below every descendant, which is exactly the layer
   this needs, and it costs no markup in any theme present or future.

   Not applied to the minimal theme: its hero is white with dark text, so
   darkening it would destroy the contrast rather than protect it.
   ========================================================================== */
.ts-event .classic-hero,
.ts-event .bold-hero {
  box-shadow: inset 0 0 0 100vmax rgba(8, 14, 28, var(--ts-hero-overlay, 0));
}

/* A light hero (the minimal theme) needs the subject in a colour that holds
   contrast on white rather than the light-blue default. */
.ts-event .minimal-hero { --ts-hero-highlight-default: var(--accent, #12507F); }

/* Left-aligned hero, when the organisers choose it. */
.ts-event .hero-inner.is-left,
.ts-event .hero-inner.is-left .ts-hero-deadlines,
.ts-event .hero-inner.is-left .ts-hero-actions { text-align: left; justify-content: flex-start; }
.ts-event .hero-inner.is-left .ts-hero-actions { align-items: flex-start; }

/* ==========================================================================
   Who should attend
   --------------------------------------------------------------------------
   A banner card: the audience on one side, a photograph on the other. This
   used to be a row of small pills inside the registration column, where it
   answered nobody's question. Without an image the text simply takes the full
   card, so the block still works before anyone uploads one.
   ========================================================================== */
.ts-event .ts-audience {
  display: grid;
  gap: 0;
  border: 1px solid var(--ts-border);
  border-radius: var(--ts-radius-lg, 16px);
  overflow: hidden;
  background: var(--ts-surface);
}
@media (min-width: 900px) {
  .ts-event .ts-audience.has-image { grid-template-columns: minmax(0, 1fr) minmax(0, 0.85fr); }
}

.ts-event .ts-audience__body { padding: var(--ts-space-10); }
.ts-event .ts-audience__body h2 { margin-top: 0; }
.ts-event .ts-audience__intro {
  color: var(--ts-text-muted);
  max-width: var(--ts-measure);
}

/* Two columns of short labels rather than one long list: an audience list is
   a dozen one-line items and reads badly as a single tall column. */
.ts-event .ts-audience__list {
  list-style: none; margin: var(--ts-space-6) 0 0; padding: 0;
  display: grid; gap: var(--ts-space-3);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr));
}
.ts-event .ts-audience__list li {
  position: relative;
  padding-left: var(--ts-space-7);
  color: var(--ts-text);
}
/* A tick drawn in CSS, so the list still reads if the icon font fails. */
.ts-event .ts-audience__list li::before {
  content: "";
  position: absolute;
  left: 4px; top: .55em;
  width: 11px; height: 6px;
  border-left: 2px solid var(--accent, var(--ts-accent));
  border-bottom: 2px solid var(--accent, var(--ts-accent));
  transform: rotate(-45deg);
}

.ts-event .ts-audience__media {
  background-size: cover;
  background-position: center;
  min-height: 260px;
}

/* ==========================================================================
   About page layout
   --------------------------------------------------------------------------
   The prose is held to a reading measure, which on a 1400px page left roughly
   half the width empty to its right. The key facts now occupy that space
   instead of sitting far below it, so the page is filled without anyone
   having to read a 140-character line.
   ========================================================================== */
.ts-event .ts-about-split {
  display: grid;
  gap: var(--ts-space-10);
  align-items: start;
  margin-bottom: var(--ts-space-10);
}
/* A grid item defaults to min-width:auto, so a long word or an unbroken URL
   pushes the track wider than the column and the page scrolls sideways. */
.ts-event .ts-about-split > * { min-width: 0; }
/* On the About page the split is followed by the programme, so it carries a
   trailing margin. In the home page's About section it is the last thing in
   the section and the margin only pads the section out. */
.ts-event .ts-about-split:last-child { margin-bottom: 0; }
@media (min-width: 900px) {
  .ts-event .ts-about-split { grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr); gap: var(--ts-space-12); }
}

.ts-event .ts-about-aside {
  background: var(--ts-bg-subtle);
  border: 1px solid var(--ts-border);
  border-radius: var(--ts-radius-md);
  padding: var(--ts-space-6) var(--ts-space-7);
}
.ts-event .ts-about-aside__cta {
  margin-top: var(--ts-space-5);
  padding-top: var(--ts-space-5);
  border-top: 1px solid var(--ts-border);
}
/* The facts list carries a bottom margin for the case where it ends the card.
   With the button under it that margin stacks with the rule above and opened a
   60px hole between the last fact and the button. */
.ts-event .ts-about-aside dl:has(+ .ts-about-aside__cta) { margin-bottom: 0; }
/* Full width in a narrow card: a button floating at one edge of a bordered
   box reads as unfinished. */
.ts-event .ts-about-aside__cta .btn { flex: 1 1 100%; }

.ts-event .ts-about-aside__title {
  font-family: var(--ts-font-display);
  font-size: var(--ts-text-sm);
  font-weight: var(--ts-weight-semibold);
  letter-spacing: var(--ts-tracking-wide);
  text-transform: uppercase;
  color: var(--ts-text-muted);
  margin-bottom: var(--ts-space-4);
}
/* In a narrow aside the label/value pair reads better stacked than in the
   two-column grid the facts strip uses across the full width. */
.ts-event .ts-facts--stacked > div { display: block; padding-block: var(--ts-space-3); }
.ts-event .ts-facts--stacked dt { margin-bottom: 2px; }

/* ==========================================================================
   Brand cards -- media partners and sponsors
   --------------------------------------------------------------------------
   Both were a wall of bare logos with the name only in the alt text, so a
   visitor who did not recognise a mark learned nothing from it. Each is now a
   square card: logo above, name and a line of text below.

   Square because the logos are not a common shape -- wide wordmarks beside
   round emblems -- and a fixed 1:1 frame with the logo contained inside is the
   only way they line up without cropping or stretching any of them.
   ========================================================================== */
.ts-event .ts-brand-card {
  flex: 0 0 auto;
  width: var(--ts-brand-size, 200px);
  aspect-ratio: 1 / 1;
  display: flex;
  flex-direction: column;
  gap: var(--ts-space-3);
  padding: var(--ts-space-5);
  background: var(--ts-surface);
  border: 1px solid var(--ts-border);
  border-radius: var(--ts-radius-md);
  text-align: center;
  text-decoration: none;
  color: var(--ts-text);
  transition: box-shadow var(--ts-dur-fast) var(--ts-ease),
              border-color var(--ts-dur-fast) var(--ts-ease),
              transform var(--ts-dur-fast) var(--ts-ease);
}
a.ts-brand-card:hover {
  box-shadow: var(--ts-shadow-md);
  border-color: var(--ts-accent-border);
  transform: translateY(-2px);
}
a.ts-brand-card:focus-visible { outline: 3px solid var(--ts-ring); outline-offset: 2px; }

.ts-event .ts-brand-card__logo {
  flex: 1 1 auto;
  min-height: 0;               /* a flex item will not shrink below content without this */
  display: flex;
  align-items: center;
  justify-content: center;
}
.ts-event .ts-brand-card__logo img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;         /* contain, not cover: a cropped logo is a damaged logo */
}
.ts-event .ts-brand-card__initial {
  width: 56px; height: 56px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: var(--ts-bg-subtle);
  color: var(--ts-text-muted);
  font-family: var(--ts-font-display);
  font-size: 1.5rem;
  font-weight: var(--ts-weight-semibold);
}

.ts-event .ts-brand-card__body {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.ts-event .ts-brand-card__name {
  font-family: var(--ts-font-display);
  font-size: var(--ts-text-sm);
  font-weight: var(--ts-weight-semibold);
  line-height: var(--ts-leading-snug, 1.3);
  /* Two lines at most, so one long name cannot push the logo out of the card.
     The full name is still in the DOM for a screen reader. */
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.ts-event .ts-brand-card__text {
  font-size: var(--ts-text-xs, .8125rem);
  color: var(--ts-text-muted);
  line-height: var(--ts-leading-snug, 1.3);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}

/* --------------------------------------------------------------------------
   The row the cards sit in, scrolling right to left.
   -------------------------------------------------------------------------- */
.ts-event .ts-brand-row { position: relative; }

.ts-event .ts-brand-viewport {
  overflow-x: auto;
  overflow-y: hidden;
  padding: var(--ts-space-2) var(--ts-gutter);
  /* Still swipeable when the animation is off or paused. */
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.ts-event .ts-brand-viewport::-webkit-scrollbar { display: none; }

.ts-event .ts-brand-track {
  display: flex;
  gap: var(--ts-space-4);
  width: max-content;
  margin-inline: auto;         /* a short row sits centred rather than left-adrift */
}

/* The track holds the cards twice, so translating it by exactly half its width
   lands on an identical frame and the loop has no visible seam. */
.ts-event .ts-brand-row.is-scrolling .ts-brand-viewport { overflow-x: hidden; }
/* Paused means the visitor wants to look, so give them the scrollbar back. */
.ts-event .ts-brand-row.is-scrolling.is-paused .ts-brand-viewport { overflow-x: auto; }
.ts-event .ts-brand-row.is-scrolling .ts-brand-track {
  margin-inline: 0;
  animation: ts-brand-marquee var(--ts-marquee-duration, 40s) linear infinite;
}
.ts-event .ts-brand-row.is-scrolling:hover .ts-brand-track,
.ts-event .ts-brand-row.is-scrolling:focus-within .ts-brand-track,
.ts-event .ts-brand-row.is-paused .ts-brand-track {
  animation-play-state: paused;
}

@keyframes ts-brand-marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

/* Motion off: the row becomes an ordinary horizontal scroller, which still
   shows every card and needs no animation to do it. */
@media (prefers-reduced-motion: reduce) {
  .ts-event .ts-brand-row.is-scrolling .ts-brand-viewport { overflow-x: auto; }
  .ts-event .ts-brand-row.is-scrolling .ts-brand-track { animation: none; }
}

.ts-event .ts-marquee-toggle {
  position: absolute;
  top: calc(-1 * var(--ts-space-8));
  right: var(--ts-gutter);
  z-index: 2;
  min-height: 32px;
  padding: var(--ts-space-1) var(--ts-space-3);
  font-size: var(--ts-text-xs, .8125rem);
  font-family: var(--ts-font-display);
  color: var(--ts-text-muted);
  background: var(--ts-surface);
  border: 1px solid var(--ts-border);
  border-radius: var(--ts-radius-pill);
  cursor: pointer;
}
.ts-event .ts-marquee-toggle:hover { color: var(--ts-text); border-color: var(--ts-border-strong); }
.ts-event .ts-marquee-toggle:focus-visible { outline: 3px solid var(--ts-ring); outline-offset: 2px; }

/* No animation to control, so no control. */
@media (prefers-reduced-motion: reduce) {
  .ts-event .ts-marquee-toggle { display: none; }
}

/* 32px clears the WCAG 2.2 minimum of 24 but not the 44 a thumb wants, and
   this is the only control on the row. */
@media (max-width: 991.98px) {
  .ts-event .ts-marquee-toggle { min-height: 44px; padding-inline: var(--ts-space-4); }
}

@media (max-width: 575.98px) {
  .ts-event .ts-brand-card { --ts-brand-size: 156px; }
}

/* ==========================================================================
   Hero background video (all three themes)
   --------------------------------------------------------------------------
   The wrapper fills the hero; the media inside is sized to "cover" it.

   An iframe has no object-fit, so a 16:9 YouTube player dropped into a 2.5:1
   banner letterboxed with grey bars at the sides. Here the wrapper is a size
   container and the iframe takes whichever of the two is larger -- the full
   width at 16:9, or the full height at 16:9 -- then a further 25%. The extra
   quarter crops YouTube's title bar (the uploaded filename) and logo off the
   edges; nothing in a background video needs to sit that close to the frame.

   Sits at z-index 0: under each theme's scrim (1) and the content (2), so the
   title is kept readable by exactly the same overlay as a banner photograph.
   ========================================================================== */
.ts-event .ts-hero-video {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;     /* hovering must not summon YouTube's controls */
  container-type: size;
}
.ts-event .ts-hero-video video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
}
.ts-event .ts-hero-video iframe {
  position: absolute;
  top: 50%; left: 50%;
  border: 0;
  /* Fallback for browsers without container units: fill, letterboxed. */
  width: 100%; height: 100%;
  width: max(100cqw, 177.78cqh);
  height: max(100cqh, 56.25cqw);
  transform: translate(-50%, -50%) scale(1.25);
  transition: opacity .8s ease;
}

/* YouTube shows a spinner, its title and a play button before the first
   frame. event.js holds the iframe invisible until the player reports that it
   is playing, so until then the visitor sees the event banner (or colour)
   underneath. If autoplay is refused -- low-power mode, data saver -- the
   banner simply stays. Without JavaScript the class is never added and the
   video shows as before. */
.ts-event .ts-hero-video.is-waiting iframe { opacity: 0; }

/* Motion off: keep the still banner. */
@media (prefers-reduced-motion: reduce) {
  .ts-event .ts-hero-video { display: none; }
}
