/* ==========================================================================
   Techspire Summits - components
   Buttons, forms, cards, tables, navigation, feedback. Every interactive
   element here meets the 44px target floor and has a distinct hover,
   focus, active and disabled state.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */
.ts-btn {
  --_bg: var(--ts-accent);
  --_fg: var(--ts-text-on-accent);
  --_bd: transparent;

  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--ts-space-2);
  min-height: 44px;                     /* touch target floor */
  padding: var(--ts-space-3) var(--ts-space-6);
  border: 1px solid var(--_bd);
  border-radius: var(--ts-radius);
  background: var(--_bg);
  color: var(--_fg);
  font-family: var(--ts-font-display);
  font-size: var(--ts-text-base);
  font-weight: var(--ts-weight-semibold);
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  touch-action: manipulation;           /* removes the 300ms tap delay */
  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),
              box-shadow var(--ts-dur-fast) var(--ts-ease);
}
.ts-btn:hover { background: var(--ts-accent-hover); color: var(--_fg); }
/* Colour + shadow only: nothing here changes the element's box, so pressing
   a button never nudges the content around it. */
.ts-btn:active { background: var(--ts-accent-active); box-shadow: inset 0 2px 4px rgba(0,0,0,.18); }

.ts-btn[disabled], .ts-btn.is-disabled, .ts-btn[aria-disabled="true"] {
  opacity: .45;
  cursor: not-allowed;
  pointer-events: none;
}

.ts-btn--secondary {
  --_bg: transparent; --_fg: var(--ts-text); --_bd: var(--ts-border-strong);
}
.ts-btn--secondary:hover {
  background: var(--ts-bg-subtle); color: var(--ts-text);
  border-color: var(--ts-navy-300);
}
.ts-btn--secondary:active { background: var(--ts-navy-100); box-shadow: none; }

.ts-btn--ghost { --_bg: transparent; --_fg: var(--ts-accent); }
.ts-btn--ghost:hover { background: var(--ts-accent-soft); color: var(--ts-accent-hover); }

/* Destructive actions read as destructive, and are kept apart from the
   primary action rather than sitting beside it. */
.ts-btn--danger { --_bg: var(--ts-danger); --_fg: #FFFFFF; }
.ts-btn--danger:hover { background: #991B1B; }
.ts-btn--danger:active { background: #7F1D1D; }

/* On a dark hero the outline button needs a solid border, not translucency. */
.ts-btn--on-dark {
  --_bg: transparent; --_fg: #FFFFFF; --_bd: rgba(255,255,255,.7);
}
.ts-btn--on-dark:hover { background: rgba(255,255,255,.14); color: #FFFFFF; border-color: #FFFFFF; }

.ts-btn--sm { min-height: 36px; padding: var(--ts-space-2) var(--ts-space-4); font-size: var(--ts-text-sm); }
.ts-btn--lg { min-height: 52px; padding: var(--ts-space-4) var(--ts-space-8); font-size: var(--ts-text-lg); }
.ts-btn--block { display: flex; width: 100%; }

/* Async submit: the spinner replaces nothing, it is added, so the label
   stays readable and the button keeps its width. */
.ts-btn.is-loading { pointer-events: none; opacity: .8; }
.ts-btn.is-loading::before {
  content: "";
  width: 1em; height: 1em;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: ts-spin .6s linear infinite;
}
@keyframes ts-spin { to { transform: rotate(360deg); } }

/* Icon-only controls still need 44px and an aria-label in the markup. */
.ts-icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px;
  border: 0; border-radius: var(--ts-radius);
  background: transparent; color: var(--ts-text-muted);
  cursor: pointer;
  transition: background-color var(--ts-dur-fast) var(--ts-ease),
              color var(--ts-dur-fast) var(--ts-ease);
}
.ts-icon-btn:hover { background: var(--ts-bg-subtle); color: var(--ts-text); }

.ts-btn-row { display: flex; flex-wrap: wrap; gap: var(--ts-space-3); }

/* --------------------------------------------------------------------------
   Forms
   -------------------------------------------------------------------------- */
.ts-field { margin-bottom: var(--ts-space-5); }

.ts-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-label .ts-required { color: var(--ts-danger); margin-left: 2px; }

.ts-input, .ts-select, .ts-textarea {
  display: block;
  width: 100%;
  min-height: 44px;
  padding: var(--ts-space-3) var(--ts-space-4);
  border: 1px solid var(--ts-border-strong);
  border-radius: var(--ts-radius);
  background: var(--ts-surface);
  color: var(--ts-text);
  font-family: var(--ts-font-body);
  font-size: var(--ts-text-base);   /* 16px stops iOS zooming on focus */
  line-height: 1.4;
  transition: border-color var(--ts-dur-fast) var(--ts-ease),
              box-shadow var(--ts-dur-fast) var(--ts-ease);
}
.ts-textarea { min-height: 120px; resize: vertical; }
.ts-input::placeholder, .ts-textarea::placeholder { color: var(--ts-text-subtle); }

.ts-input:hover, .ts-select:hover, .ts-textarea:hover { border-color: var(--ts-navy-300); }
.ts-input:focus, .ts-select:focus, .ts-textarea:focus {
  outline: none;
  border-color: var(--ts-accent);
  box-shadow: 0 0 0 3px var(--ts-accent-soft), 0 0 0 1px var(--ts-accent);
}

/* Persistent helper text, not a placeholder that vanishes on first keypress. */
.ts-help { margin-top: var(--ts-space-2); font-size: var(--ts-text-sm); color: var(--ts-text-muted); }

/* Error sits next to the field it belongs to and is wired up with
   aria-describedby in the markup. */
.ts-error {
  display: flex; align-items: flex-start; gap: var(--ts-space-2);
  margin-top: var(--ts-space-2);
  font-size: var(--ts-text-sm); font-weight: var(--ts-weight-medium);
  color: var(--ts-danger);
}
.ts-input.is-invalid, .ts-select.is-invalid, .ts-textarea.is-invalid {
  border-color: var(--ts-danger);
}
.ts-input.is-invalid:focus { box-shadow: 0 0 0 3px var(--ts-danger-soft), 0 0 0 1px var(--ts-danger); }

/* Disabled and read-only must not look like each other: one is unavailable,
   the other is simply not editable. */
.ts-input[disabled], .ts-select[disabled], .ts-textarea[disabled] {
  background: var(--ts-bg-subtle); color: var(--ts-text-subtle);
  cursor: not-allowed; opacity: .7;
}
.ts-input[readonly] {
  background: var(--ts-bg-subtle); border-style: dashed; color: var(--ts-text);
}

/* Error summary after a failed submit: focusable, links to each bad field. */
.ts-error-summary {
  padding: var(--ts-space-4) var(--ts-space-5);
  margin-bottom: var(--ts-space-6);
  border: 1px solid var(--ts-danger);
  border-left-width: 4px;
  border-radius: var(--ts-radius);
  background: var(--ts-danger-soft);
}
.ts-error-summary h2 { font-size: var(--ts-text-lg); color: var(--ts-danger); margin-bottom: var(--ts-space-2); }
.ts-error-summary ul { margin: 0; padding-left: var(--ts-space-5); }
.ts-error-summary a { color: var(--ts-danger); font-weight: var(--ts-weight-medium); }

.ts-fieldset { border: 0; padding: 0; margin: 0 0 var(--ts-space-8); }
.ts-fieldset > legend {
  padding: 0; margin-bottom: var(--ts-space-4);
  font-family: var(--ts-font-display);
  font-size: var(--ts-text-lg); font-weight: var(--ts-weight-semibold);
}

.ts-check { display: flex; align-items: flex-start; gap: var(--ts-space-3); min-height: 44px; padding-block: var(--ts-space-2); }
.ts-check input { width: 20px; height: 20px; margin-top: 2px; accent-color: var(--ts-accent); flex: none; }

/* --------------------------------------------------------------------------
   Cards
   -------------------------------------------------------------------------- */
.ts-card {
  background: var(--ts-surface);
  border: 1px solid var(--ts-border);
  border-radius: var(--ts-radius-md);
  box-shadow: var(--ts-shadow-sm);
  overflow: hidden;
}
.ts-card__body { padding: var(--ts-space-6); }
.ts-card__head {
  padding: var(--ts-space-5) var(--ts-space-6);
  border-bottom: 1px solid var(--ts-divider);
  display: flex; align-items: center; justify-content: space-between; gap: var(--ts-space-4);
}
.ts-card__head h2, .ts-card__head h3 { margin: 0; font-size: var(--ts-text-lg); }
.ts-card__foot {
  padding: var(--ts-space-4) var(--ts-space-6);
  border-top: 1px solid var(--ts-divider);
  background: var(--ts-bg-subtle);
}
/* Capped so a card that ends up full width does not turn into a 700px
   band of image with the text pushed off the fold. */
.ts-card__media { aspect-ratio: 16 / 10; max-height: 260px; background: var(--ts-bg-subtle); }
.ts-card__media img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Whole-card link: shadow and border move, the box does not. */
.ts-card--link { transition: box-shadow var(--ts-dur) var(--ts-ease), border-color var(--ts-dur) var(--ts-ease); }
.ts-card--link:hover { box-shadow: var(--ts-shadow-lg); border-color: var(--ts-accent-border); }
.ts-card--link:focus-within { border-color: var(--ts-accent); }

/* --------------------------------------------------------------------------
   Badges and status
   -------------------------------------------------------------------------- */
.ts-badge {
  display: inline-flex; align-items: center; gap: var(--ts-space-1);
  padding: 2px 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);
  line-height: 1.6;
  background: var(--ts-bg-subtle); color: var(--ts-text-muted);
  /* Labels wrap rather than shrink; the collection reflows around them. */
  white-space: normal;
}
.ts-badge--success { background: var(--ts-success-soft); color: var(--ts-success); }
.ts-badge--warning { background: var(--ts-warning-soft); color: var(--ts-warning); }
.ts-badge--danger  { background: var(--ts-danger-soft);  color: var(--ts-danger); }
.ts-badge--info    { background: var(--ts-info-soft);    color: var(--ts-info); }
/* Status is never colour alone - a dot carries the same meaning. */
.ts-badge--dot::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: currentColor; flex: none;
}

/* --------------------------------------------------------------------------
   Tables
   -------------------------------------------------------------------------- */
.ts-table-wrap {
  overflow-x: auto;
  border: 1px solid var(--ts-border);
  border-radius: var(--ts-radius-md);
  background: var(--ts-surface);
}
.ts-table { width: 100%; border-collapse: collapse; font-size: var(--ts-text-sm); }
.ts-table th, .ts-table td {
  padding: var(--ts-space-3) var(--ts-space-4);
  text-align: left;
  border-bottom: 1px solid var(--ts-divider);
  vertical-align: middle;
}
.ts-table thead th {
  position: sticky; top: 0; z-index: 1;
  background: var(--ts-bg-subtle);
  font-family: var(--ts-font-display);
  font-size: var(--ts-text-xs);
  font-weight: var(--ts-weight-semibold);
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--ts-text-muted);
  white-space: nowrap;
}
.ts-table tbody tr:last-child td { border-bottom: 0; }
.ts-table tbody tr:hover { background: var(--ts-accent-soft); }
.ts-table td.ts-num, .ts-table th.ts-num { text-align: right; font-variant-numeric: tabular-nums; }

.ts-table th[aria-sort] { cursor: pointer; }
.ts-table th[aria-sort="ascending"]::after  { content: " \2191"; color: var(--ts-accent); }
.ts-table th[aria-sort="descending"]::after { content: " \2193"; color: var(--ts-accent); }

/* --------------------------------------------------------------------------
   Empty, loading and error states
   -------------------------------------------------------------------------- */
.ts-empty {
  padding: var(--ts-space-12) var(--ts-space-6);
  text-align: center;
  color: var(--ts-text-muted);
}
.ts-empty__icon { color: var(--ts-text-subtle); margin-bottom: var(--ts-space-4); }
.ts-empty h3 { font-size: var(--ts-text-lg); color: var(--ts-text); margin-bottom: var(--ts-space-2); }
.ts-empty p { max-width: 46ch; margin-inline: auto; margin-bottom: var(--ts-space-6); }

/* Skeletons reserve the space the real content will take, so nothing on the
   page jumps when it arrives. */
.ts-skeleton {
  background: linear-gradient(90deg, var(--ts-bg-subtle) 25%, var(--ts-navy-150) 37%, var(--ts-bg-subtle) 63%);
  background-size: 400% 100%;
  animation: ts-shimmer 1.4s ease-in-out infinite;
  border-radius: var(--ts-radius-sm);
}
@keyframes ts-shimmer { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }

/* --------------------------------------------------------------------------
   Alerts and toasts
   -------------------------------------------------------------------------- */
.ts-alert {
  display: flex; align-items: flex-start; gap: var(--ts-space-3);
  padding: var(--ts-space-4) var(--ts-space-5);
  margin-bottom: var(--ts-space-5);
  border: 1px solid var(--ts-border);
  border-left: 4px solid var(--ts-text-muted);
  border-radius: var(--ts-radius);
  background: var(--ts-surface);
  color: var(--ts-text);
}
.ts-alert__icon { flex: none; margin-top: 2px; }
.ts-alert--success { border-left-color: var(--ts-success); background: var(--ts-success-soft); }
.ts-alert--warning { border-left-color: var(--ts-warning); background: var(--ts-warning-soft); }
.ts-alert--danger  { border-left-color: var(--ts-danger);  background: var(--ts-danger-soft); }
.ts-alert--info    { border-left-color: var(--ts-info);    background: var(--ts-info-soft); }

.ts-toast-region {
  position: fixed; right: var(--ts-space-4); bottom: var(--ts-space-4);
  z-index: var(--ts-z-toast);
  display: flex; flex-direction: column; gap: var(--ts-space-3);
  width: min(380px, calc(100vw - var(--ts-space-8)));
}
.ts-toast {
  padding: var(--ts-space-4) var(--ts-space-5);
  border-radius: var(--ts-radius);
  background: var(--ts-surface-inverse);
  color: var(--ts-text-inverse);
  box-shadow: var(--ts-shadow-xl);
  animation: ts-toast-in var(--ts-dur-slow) var(--ts-ease-spring);
}
@keyframes ts-toast-in { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }

/* --------------------------------------------------------------------------
   Chips / filters - wrap the collection before shrinking any label
   -------------------------------------------------------------------------- */
.ts-chips { display: flex; flex-wrap: wrap; gap: var(--ts-space-2); }
.ts-chip {
  display: inline-flex; align-items: center; gap: var(--ts-space-2);
  min-height: 36px;
  padding: var(--ts-space-2) var(--ts-space-4);
  border: 1px solid var(--ts-border-strong);
  border-radius: var(--ts-radius-pill);
  background: var(--ts-surface);
  color: var(--ts-text-muted);
  font-size: var(--ts-text-sm);
  cursor: pointer;
  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-chip:hover { border-color: var(--ts-navy-300); color: var(--ts-text); }
.ts-chip[aria-pressed="true"], .ts-chip.is-active {
  background: var(--ts-accent); border-color: var(--ts-accent); color: var(--ts-text-on-accent);
}

/* --------------------------------------------------------------------------
   Scroll reveal - the final state is the default, so content is visible if
   JavaScript never runs or motion is reduced.
   -------------------------------------------------------------------------- */
.ts-reveal { opacity: 1; }
@media (prefers-reduced-motion: no-preference) {
  .js .ts-reveal { opacity: 0; transform: translateY(16px); }
  .js .ts-reveal.is-visible {
    opacity: 1; transform: none;
    transition: opacity var(--ts-dur-slow) var(--ts-ease-out),
                transform var(--ts-dur-slow) var(--ts-ease-out);
  }
}

/* --------------------------------------------------------------------------
   Accordion, built on <details>/<summary>: keyboard-operable and announced
   correctly with no JavaScript, so it works before the page finishes loading.
   -------------------------------------------------------------------------- */
.ts-accordion {
  border: 1px solid var(--ts-border);
  border-radius: var(--ts-radius-md);
  background: var(--ts-surface);
  overflow: hidden;
}
.ts-accordion__item + .ts-accordion__item { border-top: 1px solid var(--ts-divider); }
.ts-accordion__summary {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--ts-space-4);
  min-height: 56px;
  padding: var(--ts-space-4) var(--ts-space-5);
  cursor: pointer;
  list-style: none;
  font-family: var(--ts-font-display);
  font-size: var(--ts-text-lg);
  font-weight: var(--ts-weight-semibold);
  color: var(--ts-text);
  transition: background-color var(--ts-dur-fast) var(--ts-ease);
}
.ts-accordion__summary::-webkit-details-marker { display: none; }
.ts-accordion__summary:hover { background: var(--ts-bg-subtle); }
.ts-accordion__summary:focus-visible { outline: 3px solid var(--ts-ring); outline-offset: -3px; }
.ts-accordion__chevron {
  flex: none; color: var(--ts-text-muted);
  transition: transform var(--ts-dur) var(--ts-ease);
}
.ts-accordion__item[open] .ts-accordion__chevron { transform: rotate(180deg); }
.ts-accordion__panel {
  padding: 0 var(--ts-space-5) var(--ts-space-5);
  color: var(--ts-text-muted);
  line-height: var(--ts-leading-relaxed);
  max-width: var(--ts-measure);
}

/* Long-form legal copy pasted from a rich-text editor. */
.ts-legal h2 { font-size: var(--ts-text-xl); margin-top: var(--ts-space-8); }
.ts-legal h3 { font-size: var(--ts-text-lg); margin-top: var(--ts-space-6); }
.ts-legal p, .ts-legal li { color: var(--ts-text-muted); line-height: var(--ts-leading-relaxed); }
.ts-legal ul, .ts-legal ol { padding-left: var(--ts-space-6); margin-bottom: var(--ts-space-4); }
.ts-legal li { margin-bottom: var(--ts-space-2); }

/* 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; }

/* ==========================================================================
   Mobile corrections
   ========================================================================== */

/* The purchased theme sets input[type="email"] { font-size: 15px }, an
   attribute selector that outranks a plain class. Anything under 16px makes
   iOS Safari zoom the page when the field is focused, and it never zooms back.
   Type-qualified selectors match that specificity and win on load order. */
input.ts-input, select.ts-select, textarea.ts-textarea,
input.form-control, select.form-select, textarea.form-control {
  font-size: max(16px, var(--ts-text-base));
}

/* The brand link is a tap target, not just a picture. */
.ts-logo { min-height: 44px; }

/* The theme search overlay ships 18px and 20px icon buttons. */
.search__popup .search-close-btn,
.search__popup .search__input button {
  min-width: 44px; min-height: 44px;
  display: inline-flex; align-items: center; justify-content: center;
}
.search__popup .search-input-field { font-size: max(16px, var(--ts-text-base)); }

@media (max-width: 640px) {
  .ts-event-hero { min-height: auto; padding-block: var(--ts-space-12); }
}

/* Chips are filter/tag controls, not prose links: give them a comfortable
   target rather than sitting a pixel under it. */
.ts-chip { min-height: 40px; }

/* A session title is the link to that session, so it needs a real target
   height even though it sits inside a heading. */
.ts-session__title a {
  display: inline-block;
  padding-block: var(--ts-space-3);
}

@media (max-width: 767.98px) {
  /* Small buttons are still primary actions on a phone, so they meet the same
     44px target as everything else rather than staying at their desk size. */
  .ts-btn--sm { min-height: 44px; }
}

/* Footer links on the sign-in / register cards are navigation, not prose:
   they need a real tap target on a phone. */
.ts-auth-links {
  display: flex; flex-wrap: wrap;
  gap: var(--ts-space-2) var(--ts-space-4);
  align-items: center; justify-content: space-between;
  margin-top: var(--ts-space-4);
  padding-top: var(--ts-space-4);
  border-top: 1px solid var(--ts-divider);
  font-size: var(--ts-text-sm);
  color: var(--ts-text-muted);
}
.ts-auth-links a { display: inline-block; min-height: 44px; line-height: 44px; }
