/*
 * homesite.css
 * PeerVoice Homepage (static, non-MDADI)
 *
 * Uses base.css tokens exclusively (colors, type, spacing, radius, transitions).
 * Does NOT import hub.css directly, but ports its exact recipes (btn-pill,
 * carousel arrow, edu-card hover, underline-link hover, focus-visible ring)
 * for cross-project consistency — see CLAUDE.md "Design system" and
 * "Motion & interaction design".
 *
 * BEM naming, hs- prefix throughout.
 *
 * Version : 1.0
 * Updated : 2026-08-25
 */

/* ============================================================
   RESET / BASE
   ============================================================ */
* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--typography-family-sans);
  color: var(--color-slate-1000);
  background: var(--color-slate-100);
}

img { max-width: 100%; display: block; }

a { color: inherit; text-decoration: none; }

/* Missing everywhere in this codebase (checked homesite.css and the shared
   base.css) — every <button> was silently inheriting raw browser UA chrome
   (gray fill, default padding/font, and Chrome's own dimmed :disabled
   rendering). Exact port of curriculum.css's own button reset (~L55). */
button { border: none; background: none; cursor: pointer; padding: 0; font: inherit; }

/* .page-loader itself lives in base.css (shared, ported from Hub) with a
   white (--color-white-1000) background — but the PeerVoice logo SVG (both
   this project's local copy and Hub's own shared CDN asset — checked both)
   is natively fill="white". Same silent white-on-white failure class as the
   search/share icon bugs elsewhere in this file: no error, just invisible.
   brightness(0) forces it solid black regardless of source fill, same
   defensive technique as .hs-hero__logo's own filter (which forces the
   opposite direction, to white, for its dark background). */
.page-loader__logo { filter: brightness(0); }

/* ============================================================
   SHARED: underline-link hover ("roll in") — exact port from hub.css
   ============================================================ */
.hs-link {
  color: var(--color-teal-700-primary-brand);
  background-image: linear-gradient(var(--color-teal-800), var(--color-teal-800));
  background-size: 0% 1px;
  background-repeat: no-repeat;
  background-position: left bottom;
  transition: color var(--transition-base), background-size var(--transition-base);
}
.hs-link:hover,
.hs-link:focus-visible {
  color: var(--color-teal-800);
  background-size: 100% 1px;
}

/* ============================================================
   SHARED: focus-visible ring — exact port from hub.css
   ============================================================ */
.hs-focus-ring:focus-visible {
  outline: 2px solid var(--color-teal-700-primary-brand);
  outline-offset: 3px;
  box-shadow: 0 0 0 6px rgba(var(--color-teal-700-rgb), 0.25);
}
.hs-focus-ring--on-dark:focus-visible {
  outline: 2px solid #ffffff;
  outline-offset: 3px;
  box-shadow: 0 0 0 6px color-mix(in srgb, var(--color-white-1000) 25%, transparent);
}

/* ============================================================
   SHARED: pill button — exact port from hub.css .btn-pill
   ============================================================ */
.hs-btn-pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 24px;
  border: none;
  border-radius: var(--size-radius-full);
  background: var(--color-teal-700-primary-brand);
  color: #ffffff;
  font-family: var(--typography-family-sans);
  font-size: var(--typography-scale-03);
  font-weight: var(--typography-weight-semibold);
  transition: background var(--transition-base), transform var(--transition-base);
  cursor: pointer;
}
/* See the identical comment on .hs-see-more-btn[hidden] — an explicit
   `display` here otherwise silently defeats the `hidden` attribute
   entirely, since author styles always beat the UA default regardless of
   selector specificity. Defensive: nothing currently toggles `hidden` on a
   .hs-btn-pill, but the failure mode is silent (no error) if that ever
   changes without this rule already in place. */
.hs-btn-pill[hidden] { display: none; }
.hs-btn-pill:hover { background: var(--color-teal-800); transform: scale(1.03); outline: none; }
.hs-btn-pill__icon { width: 16px; height: 16px; filter: brightness(0) invert(1); }
.hs-btn-pill:focus-visible {
  background: var(--color-teal-800);
  transform: scale(1.03);
  outline: 2px solid var(--color-teal-700-primary-brand);
  outline-offset: 3px;
  box-shadow: 0 0 0 6px rgba(var(--color-teal-700-rgb), 0.25);
}

/* ============================================================
   SHARED: carousel shell + controls — exact port from curriculum.css
   (.carousel / .carousel__track / .carousel__controls / .carousel__scrubber /
   .carousel__arrow), driven by homesite-carousel.js (index-based transform,
   not native scroll — see that file for the ported controller).
   ============================================================ */
.hs-carousel { overflow: hidden; }

.hs-carousel__track {
  display: flex;
  gap: var(--carousel-gap);
  transition: transform var(--transition-carousel);
  will-change: transform;
}

.hs-carousel__controls {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-top: 20px;
}

/* Scrubber: thin track, taller draggable thumb centred on it */
.hs-carousel__scrubber {
  flex: 1;
  height: 2px;
  border-radius: var(--size-radius-full);
  background: var(--color-slate-200);
  position: relative;
  overflow: visible;
  cursor: pointer;
}
.hs-carousel__scrubber-thumb {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  left: 0;
  height: 6px;
  width: 30%;
  background: var(--color-slate-600-secondary-brand);
  border-radius: var(--size-radius-full);
  cursor: grab;
  min-width: 24px;
}
.hs-carousel__scrubber-thumb:hover { background: var(--color-slate-800); }
.hs-carousel__scrubber-thumb:active,
.hs-carousel__scrubber-thumb[data-dragging] { cursor: grabbing; background: var(--color-slate-900); }

.hs-carousel__arrows { display: flex; gap: 8px; flex-shrink: 0; }

.hs-carousel__arrow {
  width: 40px;
  height: 40px;
  border-radius: var(--size-radius-full);
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1.5px solid var(--color-teal-700-primary-brand);
  background: #ffffff;
  cursor: pointer;
  transition: background var(--transition-base), border-color var(--transition-base), transform var(--transition-base);
}
.hs-carousel__arrow:hover:not(:disabled) { background: var(--color-teal-800); border-color: var(--color-teal-800); transform: scale(1.12); outline: none; }
.hs-carousel__arrow:focus-visible:not(:disabled) {
  background: var(--color-teal-800);
  border-color: var(--color-teal-800);
  transform: scale(1.12);
  outline: 2px solid var(--color-teal-700-primary-brand);
  outline-offset: 3px;
  box-shadow: 0 0 0 6px rgba(var(--color-teal-700-rgb), 0.25);
}
.hs-carousel__arrow-icon { filter: invert(62%) sepia(28%) saturate(700%) hue-rotate(141deg) brightness(95%); }
/* left.svg is a 48×48 viewport, right.svg is 32×32 — sized differently here
   (not both 18px) so the two arrow glyphs read as the same visual size
   despite the source files' different native proportions. Exact port of
   curriculum.css's .carousel__arrow--prev/--next img sizing. */
.hs-carousel__arrow--prev .hs-carousel__arrow-icon { width: 28px; height: 28px; }
.hs-carousel__arrow--next .hs-carousel__arrow-icon { width: 18px; height: 18px; }
.hs-carousel__arrow:hover:not(:disabled) .hs-carousel__arrow-icon,
.hs-carousel__arrow:focus-visible:not(:disabled) .hs-carousel__arrow-icon { filter: brightness(0) invert(1); }
.hs-carousel__arrow:disabled { border-color: var(--color-slate-300); cursor: default; }
.hs-carousel__arrow:disabled .hs-carousel__arrow-icon { filter: invert(80%); }

/* The base scrubber recipe above (slate-200 track, slate-600 thumb) is Hub's
   own default, tuned for a white/near-white section — that's still correct
   as-is for Curricula Highlights (no bg override, inherits body's near-white
   slate-100). Latest Educational Activities deliberately sets its own section
   background to slate-200 (#F4F4F4) — the EXACT same value as the track's
   default color, so the track was rendering fully invisible there, with only
   the low-contrast thumb barely readable against it. Not a Hub porting bug —
   Hub never places this component against that specific background, so its
   recipe never had to account for it. */
.hs-carousel__controls--on-gray .hs-carousel__scrubber { background: var(--color-slate-500); }
.hs-carousel__controls--on-gray .hs-carousel__scrubber-thumb { background: var(--color-slate-800); }
.hs-carousel__controls--on-gray .hs-carousel__scrubber-thumb:hover { background: var(--color-slate-900); }

/* Light variant for the dark-navy Events section — exact port of
   curriculum.css's .carousel__controls--light (~L300-324). CLAUDE.md's
   history notes claimed this was already ported, but it was never actually
   present in this file — same invisible-scrubber bug as the gray-bg case
   above, just against a dark background instead of a light one. */
.hs-carousel__controls--light .hs-carousel__scrubber { background: color-mix(in srgb, var(--color-white-1000) 20%, transparent); }
.hs-carousel__controls--light .hs-carousel__scrubber-thumb { background: color-mix(in srgb, var(--color-white-1000) 65%, transparent); }
.hs-carousel__controls--light .hs-carousel__scrubber-thumb:hover { background: color-mix(in srgb, var(--color-white-1000) 90%, transparent); }
.hs-carousel__controls--light .hs-carousel__scrubber-thumb:active,
.hs-carousel__controls--light .hs-carousel__scrubber-thumb[data-dragging] { background: #ffffff; }
/* No --light overrides for .hs-carousel__arrow — unlike Hub's own arrow
   (transparent by default, which is why Hub's --light variant forces its
   icon white to read against a dark section), this project's arrow button
   has an opaque `background:#ffffff` circle (see base rule above). Forcing
   the icon white on top of that made it invisible against its own white
   circle — confirmed via screenshot on the Events section. The white-circle
   + teal-icon/border resting state, and the teal-800-fill + white-icon hover
   state, already read correctly against any section background, dark or
   light, with zero variant needed. */

/* ============================================================
   HEADER
   ============================================================ */
.hs-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  height: 62px;
  background: var(--color-teal-700-primary-brand);
  transition: transform var(--transition-base);
}
.hs-header--hidden { transform: translateY(-100%); }

.hs-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 62px;
  gap: var(--size-space-800);
}

.hs-header__links {
  display: flex;
  align-items: center;
  gap: var(--size-space-200);
  list-style: none;
  margin: 0;
  padding: 0;
}

.hs-header__link {
  display: inline-flex;
  align-items: center;
  height: 40px;
  padding: 0 var(--size-space-400);
  border-radius: var(--size-radius-full);
  color: #ffffff;
  /* scale-01 = 12px, matches hub.css .topnav__link exactly (was scale-02/14px) */
  font-size: var(--typography-scale-01);
  font-weight: var(--typography-weight-semibold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  transition: background var(--transition-fast);
}
/* Darkening overlay, not lightening — exact port of .topnav__link:hover
   (background: var(--color-black-200)), confirmed 2026-08-25 */
.hs-header__link:hover { background: var(--color-black-200); }

.hs-nav__specialty-trigger {
  display: inline-flex;
  align-items: center;
  gap: var(--size-space-100);
  height: 40px;
  padding: 0 var(--size-space-400);
  border: none;
  border-radius: var(--size-radius-full);
  background: var(--color-blush-700-highlight-brand);
  color: #ffffff;
  font-size: var(--typography-scale-01);
  font-weight: var(--typography-weight-semibold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--transition-fast);
}
/* Down/open state — darker step of the same brand color, same convention as
   .hs-btn-pill:hover using teal-800 off teal-700. */
.hs-nav__specialty-trigger.is-open { background: var(--color-blush-800); }
.hs-nav__specialty-trigger-chevron {
  width: 12px;
  height: 12px;
  transition: transform var(--transition-fast);
}
.hs-nav__specialty-trigger.is-open .hs-nav__specialty-trigger-chevron { transform: rotate(180deg); }

.hs-header__search {
  display: flex;
  align-items: center;
  gap: var(--size-space-200);
  width: 320px;
  max-width: 40vw;
  height: 40px;
  /* Asymmetric — matches the later-refined .hs-subscribe-signup__field
     pattern: full padding on the left for the placeholder text, a tight
     4px on the right so the 32px circular submit button's own shape
     defines the pill's edge instead of stacking another 16px beyond it. */
  padding: 0 4px 0 var(--size-space-400);
  border-radius: var(--size-radius-full);
  background: #ffffff;
  border: none;
}
.hs-header__search input {
  flex: 1;
  border: none;
  outline: none;
  font-family: var(--typography-family-sans);
  font-size: var(--typography-scale-02);
  background: transparent;
  color: var(--color-slate-1000);
}
.hs-header__search input::placeholder { color: var(--color-slate-600-secondary-brand); }

/* Real submit button, not a decorative span — confirmed 2026-08-25: clicking
   it (or pressing Enter in the field) submits the search form. */
.hs-header__search-submit {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  flex-shrink: 0;
  border: none;
  border-radius: var(--size-radius-full);
  background: transparent;
  cursor: pointer;
  transition: background var(--transition-fast);
}
.hs-header__search-submit:hover { background: var(--color-teal-100); }

/* mask-image (not a plain <img>) so the icon can be tinted to an exact color
   — teal, confirmed 2026-08-25, not the icon's own dark (#0C0C0D) source fill. */
.hs-header__search-icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  background-color: var(--color-teal-700-primary-brand);
  -webkit-mask-image: url('https://c.peervoice.com/assets/portal/images/icons/eyeglass.svg');
  mask-image: url('https://c.peervoice.com/assets/portal/images/icons/eyeglass.svg');
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

.hs-header__hamburger { display: none; }
.hs-header__overlay { display: none; }

@media (max-width: 860px) {
  .hs-header__links, .hs-header__search { display: none; }
  .hs-header__hamburger {
    display: flex;
    align-items: center;
    gap: var(--size-space-200);
    color: #ffffff;
    font-size: var(--typography-scale-01);
    font-weight: var(--typography-weight-semibold);
    letter-spacing: 0.08em;
  }
  .hs-header__hamburger-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    flex-shrink: 0;
  }
  .hs-header__hamburger-label { white-space: nowrap; }
  /* Teal bg, edge-to-edge rows, content-height dropdown. Pinned at top:62px
     (never moves — no more translateY from above the viewport, which read as
     the panel "flying in" over/above the header) and instead unfurls straight
     down from under the header using the same 0fr→1fr grid-template-rows
     expand as the accordion panel below, so it only ever grows downward from
     its resting position. */
  .hs-header__overlay {
    display: grid;
    grid-template-rows: 0fr;
    position: fixed;
    top: 62px;
    left: 0;
    right: 0;
    background: var(--color-teal-700-primary-brand);
    transition: grid-template-rows var(--transition-base);
    z-index: 99;
  }
  .hs-header__overlay.is-open { grid-template-rows: 1fr; }
  .hs-header__overlay-inner {
    overflow-y: auto;
    min-height: 0;
    max-height: calc(100vh - 62px);
  }

  /* Search sits above the nav rows, edge-to-edge like every row below it —
     overrides the desktop pill (rounded, fixed-width, margined) with a flush
     rectangular bar so it reads as part of the same panel, not a floating
     control. Still overrides the generic `.hs-header__search{display:none}`
     mobile hide above since this instance lives inside the overlay. */
  .hs-header__overlay .hs-header__search {
    display: flex;
    width: 100%;
    max-width: none;
    height: 56px;
    margin: 0;
    padding: 0 var(--size-space-600);
    border-radius: 0;
  }

  .hs-header__overlay-links {
    display: flex;
    flex-direction: column;
    width: 100%;
    padding: 0;
    list-style: none;
    margin: 0;
  }
  .hs-header__overlay-link {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--size-space-200);
    width: 100%;
    text-align: left;
    padding: 14px var(--size-space-600);
    color: #ffffff;
    font-size: var(--typography-scale-01);
    font-weight: var(--typography-weight-semibold);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    transition: background var(--transition-base);
  }
  .hs-header__overlay-link:hover,
  .hs-header__overlay-link:focus-visible { background: var(--color-black-200); }

  /* Specialty/Clinical Area accordion trigger — same edge-to-edge row as every
     other overlay link, kept blush/red so it still stands out from the teal
     rows around it (was a floating pill button before). */
  .hs-header__overlay-link--accent {
    background: var(--color-blush-700-highlight-brand);
  }
  .hs-header__overlay-link--accent:hover,
  .hs-header__overlay-link--accent:focus-visible { background: var(--color-blush-800); }

  .hs-header__overlay-accordion-chevron {
    width: 12px;
    height: 12px;
    flex-shrink: 0;
    transition: transform var(--transition-fast);
  }
  .hs-header__overlay-link--accent[aria-expanded="true"] .hs-header__overlay-accordion-chevron {
    transform: rotate(180deg);
  }

  /* Smooth expand/collapse without measuring content height in JS — the
     0fr → 1fr grid-template-rows trick; the inner wrapper clips to that row's
     computed height so content doesn't overflow mid-transition. */
  .hs-header__overlay-accordion-panel {
    display: grid;
    grid-template-rows: 0fr;
    background: color-mix(in srgb, var(--color-black-1000) 10%, transparent);
    transition: grid-template-rows var(--transition-base);
  }
  .hs-header__overlay-accordion.is-open .hs-header__overlay-accordion-panel {
    grid-template-rows: 1fr;
  }
  .hs-header__overlay-accordion-panel-inner { overflow: hidden; min-height: 0; }

  .hs-header__overlay-accordion-label {
    margin: var(--size-space-300) var(--size-space-600) var(--size-space-100);
    color: color-mix(in srgb, var(--color-white-1000) 65%, transparent);
    font-size: var(--typography-scale-01);
    font-weight: var(--typography-weight-semibold);
    letter-spacing: 0.08em;
    text-transform: uppercase;
  }
  .hs-header__overlay-accordion-list { list-style: none; margin: 0; padding: 0; }
  .hs-header__overlay-accordion-link {
    display: block;
    width: 100%;
    padding: 12px var(--size-space-600) 12px calc(var(--size-space-600) * 2);
    color: #ffffff;
    font-size: var(--typography-scale-02);
    font-weight: var(--typography-weight-semibold);
    transition: background var(--transition-base);
  }
  .hs-header__overlay-accordion-link:hover,
  .hs-header__overlay-accordion-link:focus-visible { background: color-mix(in srgb, var(--color-black-1000) 15%, transparent); }
}

/* ============================================================
   SPECIALTY / CLINICAL AREA DROPDOWN
   ============================================================ */
.hs-specialty-menu {
  /* position: fixed, not absolute — matches .hs-header's own fixed positioning
     so both live in the same viewport coordinate space. Exact top/left are set
     per-open by JS from the trigger's real getBoundingClientRect() (see
     initSpecialtyDropdown() in homesite-nav.js) — a hardcoded top:62px/left:64px
     only happened to line up on one page's trigger position and drifted on any
     page where the header content shifts the pill's x-offset. */
  position: fixed;
  top: 0;
  left: 0;
  width: 415px;
  max-width: calc(100vw - 32px);
  background: #ffffff;
  /* Top corners square — panel sits flush against the header directly below
     the pill, a rounded top edge reads as detached from it. */
  border-radius: 0 0 var(--size-radius-200) var(--size-radius-200);
  box-shadow: 0 12px 32px rgba(var(--color-black-500), 0.16);
  padding: var(--size-space-400);
  display: none;
  gap: var(--size-space-600);
  z-index: 90;
}
.hs-specialty-menu.is-open { display: flex; }

.hs-specialty-menu__column { flex: 1; min-width: 0; }
.hs-specialty-menu__title {
  margin: 0 0 var(--size-space-400) 0;
  font-size: var(--typography-scale-04);
  font-weight: var(--typography-weight-bold);
  color: var(--color-blue-1000-primary-brand);
}
.hs-specialty-menu__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--size-space-300); }
/* Layout only — color/hover come from the shared .hs-link roll-in underline
   (see homesite-render.js, links are rendered with both classes). */
.hs-specialty-menu__link { font-size: var(--typography-scale-02); }

@media (max-width: 767px) {
  .hs-specialty-menu { flex-direction: column; }
}

/* ============================================================
   RIGHT SIDEBAR — page-nav dots + tooltip + share
   ============================================================ */
.hs-sidebar {
  /* Exact values pulled from Figma get_design_context 2026-08-25 (node
     11833:5844 "Control Items"), not eyeballed:
     - border-radius: 8px on the LEFT corners only (var(--size-radius-200)),
       NOT a full pill — was var(--size-radius-full), a real miss
     - background: teal at 60% opacity, not 92%
     - padding: 12px horizontal / 16px vertical (was swapped: 16/8)
     - a real (subtle) box-shadow, which was missing entirely */
  position: fixed;
  top: 126px;
  right: 0;
  z-index: 80;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--size-space-400);
  padding: var(--size-space-400) var(--size-space-300);
  border-radius: var(--size-radius-200) 0 0 var(--size-radius-200);
  background: rgba(var(--color-teal-700-rgb), 0.6);
  box-shadow: 0 1px 4px color-mix(in srgb, var(--color-black-1000) 10%, transparent);
}

/* Exact port of the Figma dot assets 2026-08-25 (downloaded and inspected the
   actual SVGs, not guessed): both states are a FILLED near-white circle with
   a light-gray border (--color-white-1000 / --color-slate-600-secondary-brand)
   — not a transparent ring. Only the active state additionally shows an inner
   solid gray dot (--color-slate-700). This was wrong before on every axis:
   wrong fill (transparent vs white), wrong border color (white vs gray),
   wrong inner-dot color (white vs gray). */
.hs-sidebar__dot {
  width: 16px;
  height: 16px;
  border-radius: var(--size-radius-full);
  border: 1px solid var(--color-slate-600-secondary-brand);
  background: var(--color-white-1000);
  cursor: pointer;
  position: relative;
  transition: background var(--transition-fast);
}
/* Absolute + translate centering, not flex — a flex ::after item here was
   getting shrunk on its main axis (8px -> 2px) by default flex-shrink math,
   rendering as a bar instead of a circle. Confirmed 2026-08-25 via
   getComputedStyle. */
.hs-sidebar__dot::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 8px;
  height: 8px;
  border-radius: var(--size-radius-full);
  background: var(--color-slate-700);
  opacity: 0;
  transition: opacity var(--transition-fast);
}
.hs-sidebar__dot.is-active::after { opacity: 1; }

/* Speech-bubble tooltip with a pointer arrow, confirmed 2026-08-25 — was a
   plain floating rectangle with no connection to the dot it labels. */
.hs-sidebar__tooltip {
  position: absolute;
  right: calc(100% + 16px);
  top: 50%;
  transform: translateY(-50%);
  background: #ffffff;
  color: var(--color-blue-1000-primary-brand);
  font-size: var(--typography-scale-02);
  font-weight: var(--typography-weight-semibold);
  white-space: nowrap;
  padding: var(--size-space-200) var(--size-space-400);
  border-radius: var(--size-radius-100);
  box-shadow: 0 4px 12px rgba(var(--color-black-400), 0.15);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--transition-fast);
}
.hs-sidebar__tooltip::after {
  content: '';
  position: absolute;
  left: 100%;
  top: 50%;
  transform: translateY(-50%);
  border: 6px solid transparent;
  border-left-color: #ffffff;
}
.hs-sidebar__dot:hover .hs-sidebar__tooltip,
.hs-sidebar__dot:focus-visible .hs-sidebar__tooltip,
.hs-sidebar__share:hover .hs-sidebar__tooltip,
.hs-sidebar__share:focus-visible .hs-sidebar__tooltip { opacity: 1; }

/* Opens the full share modal (see SHARE MODAL block) — not a Web Share API /
   clipboard fallback, confirmed 2026-08-25 to match Hub's share pattern. */
.hs-sidebar__share {
  width: 16px;
  height: 16px;
  border: none;
  background: transparent;
  cursor: pointer;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Real asset (images/icons/share.svg, added 2026-08-25), not a hand-copied
   inline path — mask-image so the icon (source fill: black) can be tinted
   white to match the sidebar's white iconography, same technique as the
   header search icon above. */
.hs-sidebar__share-icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  background-color: #ffffff;
  -webkit-mask-image: url('https://c.peervoice.com/assets/portal/images/icons/share.svg');
  mask-image: url('https://c.peervoice.com/assets/portal/images/icons/share.svg');
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
}

@media (max-width: 1023px) {
  .hs-sidebar { display: none; }
}

/* ============================================================
   HERO — header (dark image zone) + body (white zone the card overlaps into)
   Structure and overlap mechanism ported from hub.css .hero__header/.hero__card
   (~L632-761): the dark zone gets extra padding-bottom "runway"; the card sits
   in the white body below but is pulled up into that runway via negative
   margin, landing half on dark / half on white with a lifting shadow.
   See CLAUDE.md "Motion & interaction design" / this session's hero audit.
   ============================================================ */
.hs-hero { position: relative; }

.hs-hero__header {
  position: relative;
  overflow: hidden;
  /* Runway the carousel card gets pulled up into — see .hs-hero-carousel margin-top below.
     Proportional to Hub's 240px runway relative to their ~420px card height. */
  padding-bottom: 200px;
}
/* For pages with no hero carousel at all (Live Events, and every other
   simple content page still to come — About, Contact, Subscribe, legal
   templates, Sign up, Unsubscribe) — the 200px runway above exists only to
   host the overlapping carousel card, so reserving it here just leaves a
   large dead gap before the next section. Falls back to .hs-section's own
   standard padding value instead, and the page skips .hs-hero__body /
   .hs-hero-carousel entirely (no card to overlap anything).
   .hs-hero__brand's own padding-bottom:56px (tuned for the carousel-hero's
   "gap before the overlapping card" — see that rule's own comment) doesn't
   apply here since there's no card; zeroing it out so this header's own
   64px padding-bottom is the ONLY bottom spacing, matching the ~64px gap
   already visible above the logo (padding-top:126px minus the 62px sticky
   header sitting in front of it) — confirmed via getBoundingClientRect
   the two were previously 64px above vs. 120px below, a real asymmetry,
   not just a screenshot artifact. */
.hs-hero--plain .hs-hero__header { padding-bottom: var(--size-space-1600); }
.hs-hero--plain .hs-hero__brand { padding-bottom: 0; }

.hs-hero__bg {
  position: absolute;
  /* starts below the fixed 62px header (.hs-header) instead of inset:0 —
     the header is opaque and covers that gap, so the image itself begins
     right where the menu ends instead of being cropped underneath it. */
  top: 62px;
  left: 0;
  right: 0;
  bottom: 0;
  background-size: cover;
  background-position: center;
  will-change: background-position;
}
.hs-hero__bg::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(var(--color-blue-700-rgb), 1.0) 0%, rgba(var(--color-teal-700-rgb), 0.15) 100%);
}

.hs-hero__brand {
  /* 126px = exact logo y-position from Figma metadata (Brand frame origin at page
     top; header overlays it via fixed positioning, doesn't push content down).
     display:flex + gap:12px + tagline's own 24px margin-top exactly mirrors
     curriculum.css's .hero__brand/.hero__program-title spacing recipe (~L687-711)
     — flagged 2026-08-25 for consistency with Hub/Curriculum. */
  /* padding-bottom:56px = exact gap between subtitle and the overlapping card,
     measured 2026-08-25 via getBoundingClientRect on the live Curriculum demo
     (ime2.peervoice.com/hubdemo/curriculum_p1/Homepage) — this is
     .hero__header-inner's OWN padding-bottom in curriculum.css, separate from
     and in addition to the logo/title/subtitle flex-gap chain above. Missed on
     the first pass; card sat too close to the subtitle without it. */
  position: relative;
  padding-top: 126px;
  padding-bottom: 56px;
  display: flex;
  flex-direction: column;
  gap: var(--size-space-300);
}
.hs-hero__logo {
  /* height:44px (not a width guess) — exact match to curriculum.css .hero__pv-logo,
     measured 2026-08-25 via getBoundingClientRect on the live Curriculum demo.
     Was width:258px (derived from Figma's logo instance, 258x48) — noticeably
     larger than the live site's actual sizing; height-driven sizing is what
     Hub/Curriculum actually uses. */
  height: 44px;
  width: auto;
  align-self: flex-start;
  /* forces white regardless of source fill, matches hub.css .hero__pv-logo */
  filter: brightness(0) invert(1);
}
.hs-hero__tagline {
  margin: var(--size-space-600) 0 0 0;
  color: #ffffff;
  font-family: var(--typography-family-sans);
  font-size: var(--typography-scale-08);
  font-weight: var(--typography-weight-bold);
}
.hs-hero__subtitle {
  margin: 0;
  max-width: 52rem;   /* standard hero paragraph measure on every page (QA 2026-11, item 13) */
  color: color-mix(in srgb, var(--color-white-1000) 90%, transparent);
  font-size: var(--typography-scale-03);
}

@media (max-width: 767px) {
  .hs-hero__tagline, .hs-hero__subtitle { max-width: 100%; }
}

/* White zone below the dark header — the carousel card overlaps up into the
   header's runway, so this needs no top padding of its own (matches hub.css
   .hero__body { padding: 0 }). */
.hs-hero__body { background: var(--color-slate-100); }
/* Applied via JS (renderCurriculaForTA) on TA pages with no matching
   curricula — without a Curricula section to carry the near-white
   .hs-hero__body background down to the gray Activities section, that
   background stops abruptly right at the overlapping hero card's shadowed
   edge, reading as a stray cut. Matching Activities' own gray here instead
   lets the card sit on the same background straight through. */
.hs-hero__body--on-gray { background: var(--color-slate-200); }

/* ============================================================
   HERO CAROUSEL (overlapping card)
   ============================================================ */
.hs-hero-carousel {
  position: relative;
  z-index: 5;
  /* Pulls the card up by exactly the header's runway amount */
  margin-top: -200px;
}
.hs-hero-carousel__track {
  position: relative;
  border-radius: var(--size-radius-200);
  overflow: hidden;
  box-shadow: 0 4px 28px color-mix(in srgb, var(--color-black-1000) 22%, transparent);
  /* Grid stack: every slide occupies the same cell (1/1), so the row's height
     auto-sizes to the TALLEST slide's real content — no hard aspect-ratio
     ceiling that clips longer titles/speaker lists, no JS height measurement
     needed either. Min-height keeps short slides from looking cramped, using
     Figma's own Event Banner proportions (1152x442) as the floor. */
  display: grid;
  min-height: 442px;
}

/* Confirmed 2026-08-25 against the Figma reference — this is NOT a side-by-side
   split of a separate image box + a separate solid-color box. It's ONE
   full-bleed image spanning the whole card, with a semi-transparent overlay
   (configurable per slide via panelBackground, see content_homesite.json —
   confirmed 2026-08-25 this is a GRADIENT, not a flat color, hence "Background"
   not "Color" in the name) tinting the right 50% where the text sits — the
   photo is still faintly visible underneath. Set inline via the
   --hs-hero-panel-bg custom property from homesite-render.js. */
.hs-hero-slide {
  grid-area: 1 / 1;
  position: relative;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--transition-slow);
}
.hs-hero-slide.is-active { opacity: 1; pointer-events: auto; }

.hs-hero-slide__image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--transition-slow);
}
.hs-hero-slide:hover .hs-hero-slide__image,
.hs-hero-slide:focus-visible .hs-hero-slide__image { transform: scale(1.04); }
/* CTA reads as "hovered" from anywhere on the card, not just when the
   cursor is directly over it — the whole card already navigates to the same
   destination, so the button should visually confirm that regardless of
   exact cursor position. Same values as .hs-btn-pill:hover itself. */
.hs-hero-slide:hover .hs-btn-pill,
.hs-hero-slide:focus-visible .hs-btn-pill { background: var(--color-teal-800); transform: scale(1.03); }

.hs-hero-slide__panel {
  position: absolute;
  inset: 0 0 0 auto; /* pinned right by default */
  width: 50%;
  background: var(--hs-hero-panel-bg, color-mix(in srgb, var(--color-blue-1000-primary-brand) 85%, transparent));
  color: #ffffff;
  padding: var(--size-space-800);
  display: flex;
  flex-direction: column;
  /* align-items:flex-start, confirmed 2026-08-25 — was missing, so the CTA
     button and every other child defaulted to flex's stretch and filled the
     full panel width instead of sizing to its own content. */
  align-items: flex-start;
  justify-content: center; /* vertical centering, confirmed 2026-08-25 */
  gap: var(--size-space-300);
  overflow-y: auto;
}
/* 'hub' slides carry a much bigger element (the 64px logo, vs. plain text
   elsewhere) — the shared 12px gap above reads as genuinely cramped against
   it (confirmed by screenshot: logo/wordmark, description, and CTA all
   visually touching). Scoped wider gap for this one case via :has(), rather
   than raising the shared gap for every slide type or fighting it with a
   margin on the logo itself (tried first — overcorrected to too tight, see
   CLAUDE.md). */
.hs-hero-slide__panel:has(.hs-hero-slide__logo) { gap: var(--size-space-600); }
/* Per-card panelPosition:"left" (event/curriculum/hub/custom only, see
   homesite-render.js) — same box, just pinned to the opposite edge, for
   visual variety across the carousel instead of every slide reading right. */
.hs-hero-slide__panel--left { inset: 0 auto 0 0; }
/* Sizes below pulled 2026-08-26 from real sources, not the earlier guess —
   this is the site's single most prominent content area ("prime area"),
   and the old scale-02 (14px) text across the board read as too timid.
   meta/title/speakers/CTA match the exact Figma "Event Banner" node
   (fileKey Gp6X9g4nlAPqCCdBTC3s2o, node 11574:14933: 18px meta, 28px/700
   title with -0.56px tracking, 16px speakers, 14px/400 CTA label). credit
   (Earn/Language) stays at Hub's real measured 14px (hub-hero.js's
   .hero-panel__earn/__language, verified live) — that line is deliberately
   more compact than the rest, matching the reference exactly, not an
   oversight. Full white (no opacity dimming) throughout — both references
   render this text at full opacity, not dimmed. */
.hs-hero-slide__meta { margin: 0; font-size: var(--typography-scale-04); line-height: 1.2; }
/* Same 4-line clamp mechanic as .hs-hero-activity__title (size/weight/color
   stay this type's own — the Figma Event Banner spec's 28px bold white —
   only the "cap it, don't let it grow unbounded" behavior is shared). */
.hs-hero-slide__title {
  margin: 0;
  font-size: 28px;
  line-height: 1.2;
  letter-spacing: -0.56px;
  font-weight: var(--typography-weight-bold);
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.hs-hero-slide__speakers { margin: 0; font-size: var(--typography-scale-03); line-height: 1.4; }
.hs-hero-slide__tags { display: flex; flex-wrap: wrap; gap: var(--size-space-200); margin: 0; }
/* Dark-glass pill — the site's one tag-on-image treatment, shared with
   .hs-curriculum-card__tag below. Confirmed 2026-08-26: unified after the
   light-glass version (rgba(255,255,255,0.2)) proved unreadable on bright
   images — dark glass + white text stays legible over any photo. */
.hs-hero-slide__tag { padding: var(--size-space-100) var(--size-space-300); border-radius: var(--size-radius-full); background: color-mix(in srgb, var(--color-black-1000) 55%, transparent); color: #ffffff; font-size: var(--typography-scale-01); font-weight: var(--typography-weight-semibold); }
.hs-hero-slide__credit { margin: 0; font-size: var(--typography-scale-02); }
.hs-hero-slide__description { margin: 0; font-size: var(--typography-scale-03); line-height: 1.5; }
/* 'hub' slides carry a logo instead of a title. Sized at the source PNG's
   own native height (476×64) — the sharpest possible render, no upscaling
   blur. No forced-white filter: unlike .hs-hero__logo (a single-color PV
   mark, defensively forced white regardless of source fill), this logo's
   own real colors (sun-orange icon, white wordmark) are the actual design —
   forcing it white was a leftover from the placeholder PeerVoice-logo.svg
   this replaced, not something this specific asset needs.
   Spacing around this element is handled by .hs-hero-slide__panel's own
   :has(.hs-hero-slide__logo) gap override above, not a margin here — a
   negative margin was tried first and overcorrected to too tight. */
.hs-hero-slide__logo { height: 64px; width: auto; }

/* ============================================================
   HERO ACTIVITY SLIDE — structurally different from the other 4 types.
   Exact port of Hub's real .hero__card (curriculum.css ~L728-1029): image
   confined to the left 65% (not full-bleed), a WHITE right panel (not a
   colored gradient overlay), teal 4-line-clamp title. Values below are
   read directly from that source, not approximated.
   ============================================================ */
.hs-hero-slide--activity {
  display: flex;
  flex-direction: row;
  background: #ffffff;
  border-radius: var(--size-radius-200);
  overflow: hidden;
  cursor: pointer;
}
/* Not a real <a> (see JS) — role="link" + tabindex so it's keyboard
   reachable, so it needs its own focus-visible ring rather than relying on
   native anchor focus styling. */
.hs-hero-slide--activity:focus-visible {
  outline: 2px solid var(--color-teal-700-primary-brand);
  outline-offset: -2px;
}
/* Exact port of Hub/Curriculum's real .hero__card-thumb: the outer box
   stretches to the card's full height (which the panel's own content can
   push taller than a plain 16:9 photo), but the image itself keeps a fixed
   16:9 ratio and sits vertically centered — the outer box's own background
   color fills the gutters above/below whenever the card is taller than
   16:9, rather than stretching/cropping the photo to fill the whole box. */
.hs-hero-activity__thumb {
  flex: 0 0 65%;
  display: flex;
  align-items: center;
  overflow: hidden;
  background: var(--color-slate-600-secondary-brand);
  /* Floor so a short panel doesn't crush the image thin — the row still
     grows taller than this if the panel's own content (e.g. a long,
     4-line-clamped title + resources) needs more height. */
  min-height: 340px;
}
/* Fixed-ratio inner box — the actual photo, play button, and notice banner
   all anchor to THIS (not the outer thumb), so they stay pinned to the
   photo itself rather than floating in the gutter when one exists. */
.hs-hero-activity__img-wrap {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  flex-shrink: 0;
  overflow: hidden;
}
.hs-hero-activity__img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform var(--transition-slow); }
.hs-hero-slide--activity:hover .hs-hero-activity__img { transform: scale(1.04); }

.hs-hero-activity__panel { flex: 1; background: #ffffff; display: flex; flex-direction: column; padding: 20px 24px; gap: var(--size-space-200); overflow-y: auto; }
.hs-hero-activity__date { margin: 0; font-size: var(--typography-scale-02); color: var(--color-slate-700); }
.hs-hero-activity__title {
  margin: 0;
  color: var(--color-teal-700-primary-brand);
  font-size: var(--typography-scale-04);
  font-weight: var(--typography-weight-semibold);
  line-height: 1.35;
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
  transition: color var(--transition-base);
}
.hs-hero-slide--activity:hover .hs-hero-activity__title { color: var(--color-teal-800); }
/* Title is a real nested <a> (see JS) — inherits color/no-underline from the
   parent .hs-hero-activity__title, and gets its own focus ring since
   :focus-visible on a link doesn't require hovering the whole card. */
.hs-hero-activity__title-link { color: inherit; text-decoration: none; }
.hs-hero-activity__title-link:focus-visible { outline: 2px solid var(--color-teal-700-primary-brand); outline-offset: 3px; border-radius: 2px; }
.hs-hero-activity__faculty { margin: 0; font-size: var(--typography-scale-02); color: var(--color-black-1000); font-weight: var(--typography-weight-regular); }
.hs-hero-activity__credit { margin: 0; font-size: var(--typography-scale-02); color: var(--color-black-1000); }

.hs-hero-activity__resources { display: flex; flex-direction: column; gap: 2px; margin-top: var(--size-space-200); }
/* Real <a> per resource (see JS) — exact hover/focus port of Hub's
   .hero-resource-link: color shift + icon-wrap darkens together. */
.hs-hero-activity__resource { display: flex; align-items: center; gap: var(--size-space-300); padding: var(--size-space-100) 0; color: var(--color-teal-700-primary-brand); transition: color var(--transition-base); }
.hs-hero-activity__resource:hover { color: var(--color-teal-800); }
.hs-hero-activity__resource:hover .hs-hero-activity__resource-icon-wrap { background: var(--color-teal-800); }
.hs-hero-activity__resource:focus-visible { outline: none; }
.hs-hero-activity__resource:focus-visible .hs-hero-activity__resource-icon-wrap {
  outline: 2px solid var(--color-teal-700-primary-brand);
  outline-offset: 3px;
  box-shadow: 0 0 0 6px rgba(var(--color-teal-700-rgb), 0.25);
}
.hs-hero-activity__resource-icon-wrap { width: 44px; height: 44px; border-radius: 50%; background: var(--color-teal-700-primary-brand); display: flex; align-items: center; justify-content: center; flex-shrink: 0; transition: background var(--transition-base); }
.hs-hero-activity__resource-icon { width: 22px; height: 22px; filter: brightness(0) invert(1); }
.hs-hero-activity__resource-label { font-size: var(--typography-scale-02); color: inherit; }

/* Scoped override, not a change to the shared .hs-btn-pill base (that stays
   an exact port of Hub's real generic .btn-pill for reuse elsewhere) — the
   Figma Event Banner spec's button is smaller/lighter-weight than Hub's
   generic pill: 12px/16px padding, regular (not semibold) weight. */
.hs-hero-slide__panel .hs-btn-pill { padding: 12px 16px; font-weight: var(--typography-weight-regular); }
/* No title color-shift on hover, confirmed 2026-08-26 — the image zoom and
   CTA hover state (above) are the card's hover feedback now, so the title
   stays a fixed color. */

.hs-hero-carousel__pagination {
  display: flex;
  justify-content: center;
  gap: var(--size-space-200);
  margin-top: var(--size-space-400);
}
/* wider gap than the hero's own pagination — the faculty block sits directly
   above with no card/shadow buffer, so the default 16px read as cramped. */
.hs-faculty-quote__pagination { margin-top: var(--size-space-800); }
/* Fill-animation dot, exact port from hub.css .hero__progress-dot (~L1077-1114):
   gray track + a dark ::after layer that scaleX(0)->scaleX(1) fills over the
   slide interval. Confirmed 2026-08-25 — color/mechanism must match Hub/Curriculum
   for consistency (was teal before; wrong). */
.hs-hero-carousel__pagination-dot {
  height: 6px;
  width: 40px;
  border-radius: var(--size-radius-full);
  background: var(--color-slate-400);
  cursor: pointer;
  position: relative;
  overflow: hidden;
  border: none;
  padding: 0;
}
.hs-hero-carousel__pagination-dot::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--color-slate-800);
  transform: scaleX(0);
  transform-origin: left center;
  border-radius: inherit;
}
.hs-hero-carousel__pagination-dot.is-active::after {
  animation: hs-hero-dot-fill var(--hero-interval, 8000ms) linear forwards;
}
.hs-hero-carousel__pagination-dot.is-completed::after { transform: scaleX(1); }

@keyframes hs-hero-dot-fill {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

/* Revised 2026-08-26: below 1023px the panel STAYS an overlay (translucent
   gradient + text on top of the image) — it just stops covering the
   image's full height. A peek band is left uncovered at the top, sized to
   the same 16:9 ratio the activity card's stacked thumb uses (56.25vw ≈
   9/16 of the card's width, since the card spans close to the full
   viewport at these widths).

   The panel switches from position:absolute to normal flow (margin-top for
   the peek band, instead of an absolute `top`) — position:absolute never
   contributes to a parent's height, so with the old approach a
   long/multi-line title could overflow the fixed-height card and scroll
   internally instead of the card growing to fit. In normal flow the
   panel's real content height (plus the line-clamp on the title, above)
   becomes the slide's own intrinsic height, which the grid-stack then
   auto-sizes the whole track to — no scrollbar, no clipping. The image
   stays position:absolute/inset:0 so it still fills whatever height the
   panel's flow ends up producing. */
@media (max-width: 1023px) {
  /* display:flex (not block) so .hs-hero-slide__panel's flex:1 below can
     stretch to fill the row — see that rule for why this matters. */
  .hs-hero-slide:not(.hs-hero-slide--activity) { display: flex; flex-direction: column; }
  .hs-hero-slide__panel {
    position: relative;
    inset: auto;
    /* % (not vw) — for margin-top, percentages resolve against the
       CONTAINING BLOCK'S WIDTH, not viewport width. That makes this an
       exact 16:9-of-the-card's-own-width peek — mathematically identical
       to .hs-hero-activity__thumb's `aspect-ratio:16/9`, not just a visual
       approximation. vw was wrong here: the card is narrower than the
       viewport (container padding), so a vw-based peek came out taller
       than activity's actual image proportion despite looking close. */
    margin-top: 56.25%;
    /* flex:1 — the grid-stack sizes the whole row to the TALLEST slide's
       content (see .hs-hero-carousel__track), so a shorter slide's own
       content doesn't naturally reach that height. Without flex:1 here,
       the panel stopped at its own content's height, leaving the extra
       row space as a gap of bare image showing at the bottom instead of
       gradient. flex:1 stretches the panel (and its gradient) to fill
       whatever height the row actually ends up being. */
    flex: 1;
    width: 100%;
    padding: var(--size-space-600);
    overflow-y: visible;
    /* Base rule centers content vertically (desktop, where the panel is a
       fixed-height side overlay) — here content should sit at the top of
       whatever height the (now-stretched) panel ends up being. */
    justify-content: flex-start;
  }
  .hs-hero-activity__thumb { flex: none; width: 100%; aspect-ratio: 16 / 9; min-height: 0; }
  .hs-hero-slide--activity { flex-direction: column; }
  .hs-hero-activity__panel { padding: var(--size-space-600); }
}

/* ============================================================
   SECTION HEADING
   ============================================================ */
.hs-section { padding: var(--size-space-1600) 0; }
.hs-section-heading {
  margin: 0 0 var(--size-space-800) 0;
  font-size: var(--typography-scale-07);
  font-weight: var(--typography-weight-bold);
  color: var(--color-blue-1000-primary-brand);
}
.hs-section--on-dark .hs-section-heading { color: #ffffff; }
.hs-section-heading--has-intro { margin-bottom: var(--size-space-400); }
.hs-section-intro { margin: 0 0 var(--size-space-800) 0; font-size: var(--typography-scale-03); line-height: 1.5; color: var(--color-slate-900); }
.hs-section-intro[hidden] { display: none; }
.hs-section-intro p { margin: 0; }
.hs-section-intro p + p { margin-top: var(--size-space-300); }
.hs-section-intro__cta { font-weight: var(--typography-weight-semibold); }

/* TA page "Latest Activities in {TA}" — confirmed 2026-08-25: NOT a
   carousel, a wrapping grid with a "Load More" button (same pattern as Live
   Events' Past Live Events), unlike every other card section on this site.
   .hs-card itself needs no changes — it has no fixed width of its own
   outside the carousel (that comes from homesite-carousel.js's per-breakpoint
   flex-basis math), so it stretches to fill its grid cell here same as any
   other grid item.

   align-items:stretch (reverted 2026-09-03, was align-items:start since
   2026-08-27) — the homepage's own carousel relies on flex's default
   stretch + .hs-card__footer's margin-top:auto to bottom-align every card's
   Earn/Language/icon row across a row, and the user asked for this grid to
   match that same look rather than each card sizing to its own content
   height. Reintroduces the exact tradeoff the 2026-08-27 change was made to
   avoid: a card whose row-mate has notably taller content (long faculty
   list, more resource icons) will show a visible gap above its own footer.
   Deliberate, not an oversight — flagged for whoever revisits this next if
   that gap becomes a real problem on a specific TA page's real data. */
.hs-ta-activities-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--size-space-600); align-items: stretch; }
.hs-ta-load-more-row { display: flex; justify-content: center; margin-top: var(--size-space-800); }

/* "See More" — outlined pill (not the solid .hs-btn-pill fill), fills solid
   teal-800 on hover. The icon uses the same mask-image precision-tint
   technique as the header search icon so it tracks the text color exactly
   (teal at rest, white on hover) rather than fighting the source SVG's own
   dark stroke fill. Hides itself once every filtered item is already shown
   — see renderActivitiesForTA() in homesite-render.js, not a separate
   concern from the restyle. */
.hs-see-more-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--size-space-200);
  padding: 10px 24px;
  border: 1.5px solid var(--color-teal-700-primary-brand);
  border-radius: var(--size-radius-full);
  background: #ffffff;
  color: var(--color-teal-700-primary-brand);
  font-family: var(--typography-family-sans);
  font-size: var(--typography-scale-03);
  font-weight: var(--typography-weight-semibold);
  cursor: pointer;
  transition: background var(--transition-base), color var(--transition-base), transform var(--transition-base);
}
/* An explicit `display` here otherwise silently wins over the browser's
   default `[hidden]{display:none}` UA rule — different cascade origins,
   author styles always beat user-agent ones regardless of selector
   specificity — so setting the `hidden` attribute in JS had no visual
   effect at all (renderActivitiesForTA() was still correctly setting it,
   the button just stayed visible anyway). Same fix needed on .hs-btn-pill,
   see its own [hidden] rule below. */
.hs-see-more-btn[hidden] { display: none; }
.hs-see-more-btn:hover { background: var(--color-teal-800); color: #ffffff; transform: scale(1.03); }
.hs-see-more-btn__icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  background-color: var(--color-teal-700-primary-brand);
  -webkit-mask-image: url('https://c.peervoice.com/assets/portal/images/icons/plus.svg');
  mask-image: url('https://c.peervoice.com/assets/portal/images/icons/plus.svg');
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  transition: background-color var(--transition-base);
}
.hs-see-more-btn:hover .hs-see-more-btn__icon { background-color: #ffffff; }

/* Outlined pill CTA — white bg / teal outline / teal text, fills solid
   teal-800 on hover. Same visual language as .hs-see-more-btn (own name
   here since this is a nav CTA, not a load-more control) — icon uses the
   same mask-image precision-tint technique so it tracks the text color
   exactly (teal at rest, white on hover) instead of fighting the source
   SVG's own dark fill. */
.hs-btn-pill-outline {
  display: inline-flex;
  align-items: center;
  gap: var(--size-space-200);
  padding: 10px 24px;
  border: 1.5px solid var(--color-teal-700-primary-brand);
  border-radius: var(--size-radius-full);
  background: #ffffff;
  color: var(--color-teal-700-primary-brand);
  font-family: var(--typography-family-sans);
  font-size: var(--typography-scale-03);
  font-weight: var(--typography-weight-semibold);
  cursor: pointer;
  transition: background var(--transition-base), color var(--transition-base), transform var(--transition-base);
}
.hs-btn-pill-outline:hover { background: var(--color-teal-800); color: #ffffff; transform: scale(1.03); }
.hs-btn-pill-outline__icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  background-color: var(--color-teal-700-primary-brand);
  -webkit-mask-image: url('https://c.peervoice.com/assets/portal/images/icons/right.svg');
  mask-image: url('https://c.peervoice.com/assets/portal/images/icons/right.svg');
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  transition: background-color var(--transition-base);
}
.hs-btn-pill-outline:hover .hs-btn-pill-outline__icon { background-color: #ffffff; }

@media (max-width: 1023px) {
  .hs-ta-activities-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 767px) {
  .hs-ta-activities-grid { grid-template-columns: 1fr; }
}

/* Live Events page — "Upcoming"/"Past"/"Congress Spotlights" wrapping
   grids. Same recipe as .hs-ta-activities-grid above (4-up wrapping grid,
   no carousel), but its own class since this page's real Figma spec (node
   11610:10363, pulled 2026-08-27 after the first pass was built from
   CLAUDE.md's prose description alone, not the actual design — see that
   day's build notes) uses a 32px gap, not activities' 24px. At the 1280px
   container width (.container is max-width:1280px + 64px side padding =
   1152px content, matching this page's own Figma frame exactly), 4
   columns at 1fr with a 32px gap reproduces Figma's fixed 264px cards
   pixel-for-pixel — confirmed by the arithmetic (1152 - 3*32) / 4 = 264. */
.hs-events-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--size-space-800); align-items: stretch; }
@media (max-width: 1023px) {
  .hs-events-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 767px) {
  .hs-events-grid { grid-template-columns: 1fr; }
}

/* ============================================================
   LIVE EVENTS PAGE CARD ("Event Card" in Figma) — used identically for
   Upcoming/Past Live Events (live.json) and Congress Spotlights
   (activities.json, since it's the same underlying content, just
   filtered) — genuinely one shared card across all three sections, not
   three lookalike components. Deliberately NOT .hs-event-card (that
   component's teal-500/400 text only works on the homepage's dark navy
   Events section — this page's real background is white/light-gray, per
   Figma, and reusing the dark-mode card here was the first pass's actual
   mistake) and NOT .hs-card (that one's play-button-reveal-on-hover
   mechanic and layout don't match this design either). Badge icon is
   date.svg for a still-upcoming event, play.svg for anything already
   recorded (past events + congress spotlights) — mirrors the real
   distinction in the Figma file, not an arbitrary choice. */
.hs-live-card { display: flex; flex-direction: column; cursor: pointer; }
.hs-live-card__thumb {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--size-radius-200);
  border: 1px solid var(--color-teal-700-primary-brand);
  overflow: hidden;
  background: var(--color-slate-200);
}
.hs-live-card__thumb-img { width: 100%; height: 100%; object-fit: cover; transition: transform var(--transition-slow); }
.hs-live-card:hover .hs-live-card__thumb-img { transform: scale(1.04); }
/* Fixed-width pill, clip-path reveal on hover — same mechanic AND same
   exact sizing as .hs-card__play / .hs-event-card__register elsewhere on
   this site (40px height/collapsed-circle, 16px icon, scale-02 label) —
   deliberately uniform across all three, not just similar (first pass used
   a scaled-down 32px version and it read as visibly inconsistent). Two
   width variants for the two label lengths, matching those components'
   own widths exactly ("Watch Now" 128px = .hs-card__play's width,
   "Register" 100px = .hs-event-card__register's width). */
.hs-live-card__badge {
  position: absolute;
  top: var(--size-space-400);
  left: var(--size-space-400);
  height: 40px;
  border-radius: var(--size-radius-full);
  background: var(--color-teal-700-primary-brand);
  display: flex;
  align-items: center;
  justify-content: flex-start;
  padding: 0 12px;
  white-space: nowrap;
  pointer-events: none;
  clip-path: inset(0 calc(100% - 40px) 0 0 round 20px);
  transition: clip-path var(--transition-base), background var(--transition-base);
}
.hs-live-card__badge--watch { width: 128px; }
.hs-live-card__badge--register { width: 100px; }
/* will-change scoped to the hover/focus trigger, not the base rule — with
   many cards in the DOM at once (most off-screen in a carousel), applying
   will-change unconditionally to every instance makes the browser try to
   pre-promote a compositor layer for all of them simultaneously, which can
   itself be slow and jank the first few real hovers until it settles. See
   CLAUDE.md. */
.hs-live-card:hover .hs-live-card__badge,
.hs-live-card:focus-visible .hs-live-card__badge { clip-path: inset(0 0 0 0 round 20px); background: var(--color-teal-800); will-change: clip-path; }
.hs-live-card__badge-icon { width: 16px; height: 16px; flex-shrink: 0; filter: brightness(0) invert(1); }
.hs-live-card__badge-label { color: #ffffff; font-size: var(--typography-scale-02); font-weight: var(--typography-weight-semibold); margin-left: 6px; flex-shrink: 0; opacity: 0; transition: opacity var(--transition-base); }
.hs-live-card:hover .hs-live-card__badge-label,
.hs-live-card:focus-visible .hs-live-card__badge-label { opacity: 1; }
/* Content layout — exact port of the real Hub/Curriculum .pvevt-card__content
   (Hub_Curriculum/assets/css/hub_curriculum/curriculum.css ~L1490-1575, the
   authentic source .hs-event-card was itself ported from), not just a
   visually-similar approximation: a CSS grid with one auto row per content
   element and a trailing 1fr spacer, same 6px row-gap. Colors are the one
   deliberate adaptation — the real component is white-on-dark (built for a
   navy section); this card sits on a light background per the real Figma
   design (see the Live Events build notes in CLAUDE.md), so title is
   teal-700/800 instead of teal-500/400 and body text is near-black instead
   of white. Structure, spacing, and the line-clamp/alignment mechanism are
   unchanged from the source. */
/* Flex column, not a grid-with-trailing-1fr-row (that only padded blank
   space at the very bottom of the card — it never pulled the Time/Location
   block itself down to meet it, so those rows still landed at whatever Y
   the title/faculty content above happened to leave them at). Switched
   2026-09-03, same request as the Activity card's own .hs-card__footer
   treatment: .hs-live-card__meta-row--first now gets margin-top:auto
   instead, pinning the whole Time/Location(/resource-icons) block to the
   card's actual bottom regardless of how tall title/faculty are above it. */
.hs-live-card__body {
  padding-top: var(--size-space-400);
  display: flex;
  flex-direction: column;
  gap: var(--size-space-150);
  /* Lets the body actually grow to fill .hs-live-card when the outer
     .hs-events-grid stretches a card to match a taller row-mate (2026-09-03,
     same fix as .hs-ta-activities-grid) — without this, the card's own box
     would stretch but the body wouldn't have the extra height for its own
     margin-top:auto child to push against. */
  flex: 1;
}
.hs-live-card__date { margin: 0; font-size: var(--typography-scale-01); color: var(--color-black-1000); }
/* line-clamp:3, matching .hs-card__title's convention (2026-09-03) — was
   4, inherited from .hs-event-card__title/.pvevt-card__title, but the user
   asked for this page's cards to match the Activity card treatment
   applied elsewhere the same day. */
.hs-live-card__title {
  margin: 0;
  font-size: var(--typography-scale-02);
  font-weight: var(--typography-weight-bold);
  color: var(--color-teal-700-primary-brand);
  line-height: 1.35;
  /* Reserves the full 3-line clamp height regardless of actual title
     length (2026-09-03) — bottom-pinning the meta block alone still left
     "Time:"/"Location:" landing at very different Y positions row-to-row,
     since title (and faculty) height still varied above it. em-based so it
     tracks this element's own font-size/line-height rather than a
     hardcoded px value. */
  min-height: calc(1.35em * 3);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  transition: color var(--transition-base);
}
.hs-live-card:hover .hs-live-card__title { color: var(--color-teal-800); }
.hs-live-card__faculty { margin: 0; font-size: var(--typography-scale-01); line-height: 1.5; color: var(--color-black-1000); }
.hs-live-card__meta-row { margin: 0; font-size: var(--typography-scale-01); line-height: 1.4; color: var(--color-black-1000); }
/* Pins Time/Location (and the resource-icons row after it, if present) to
   the bottom of the stretched card — see .hs-live-card__body's own comment
   above. Was a fixed var(--size-space-200) top gap under the old grid
   layout; margin:auto now does double duty as both that spacing AND the
   bottom-pin. */
.hs-live-card__meta-row--first { margin-top: auto; }
/* No custom strong styling (2026-09-03, removed) — matches .hs-card__credit/
   .hs-card__lang's hands-off treatment (default browser bold, no explicit
   font-weight override). Was font-weight:semibold, lighter than the
   reference component's plain default-bold "Earn:"/"Language:" labels. */
.hs-live-card__icons { display: flex; gap: var(--size-space-300); margin-top: var(--size-space-100); }
.hs-live-card__icon-btn {
  width: 32px;
  height: 32px;
  border-radius: var(--size-radius-full);
  background: var(--color-teal-700-primary-brand);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background var(--transition-base);
}
.hs-live-card__icon-btn:hover { background: var(--color-teal-800); }
.hs-live-card__icon-btn img { width: 16px; height: 16px; filter: brightness(0) invert(1); }

/* Fast custom tooltip for icon-only resource buttons — the native `title`
   attribute has a ~1s browser hover delay before it appears, too slow for
   a row of unlabeled icons the user needs to identify quickly. Exact port
   of the sidebar's .hs-sidebar__tooltip technique (real nested element +
   its own ::after arrow, not two independent sibling pseudo-elements —
   that first version left the arrow floating unattached from the box, not
   visibly connected to it) — just flipped to sit above the trigger with
   the arrow pointing down, since these live inside a card body rather
   than beside a fixed sidebar. */
.hs-icon-tooltip { position: relative; }
.hs-icon-tooltip__bubble {
  position: absolute;
  bottom: calc(100% + 12px);
  left: 50%;
  transform: translateX(-50%);
  background: #ffffff;
  color: var(--color-blue-1000-primary-brand);
  font-size: var(--typography-scale-01);
  font-weight: var(--typography-weight-semibold);
  white-space: nowrap;
  padding: var(--size-space-100) var(--size-space-300);
  border-radius: var(--size-radius-100);
  box-shadow: 0 4px 12px rgba(var(--color-black-400), 0.15);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--transition-fast);
  z-index: 5;
}
.hs-icon-tooltip__bubble::after {
  content: '';
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  border: 6px solid transparent;
  border-top-color: #ffffff;
}
.hs-icon-tooltip:hover .hs-icon-tooltip__bubble,
.hs-icon-tooltip:focus-visible .hs-icon-tooltip__bubble { opacity: 1; }

/* A centered bubble on the group's first/last icon bleeds toward the
   nearest card/carousel edge and gets clipped there (seen live: the first
   icon's "Presentation Slides" label cut off on the left). Anchor the two
   end icons' bubbles to grow inward instead — left-edge-aligned for the
   first icon, right-edge-aligned for the last — so they extend away from
   the edge instead of across it. A lone icon (matches both :first-child
   and :last-child) is excluded via :not() and stays centered. */
.hs-card__icons > a:first-child:not(:last-child) .hs-icon-tooltip__bubble,
.hs-live-card__icons > a:first-child:not(:last-child) .hs-icon-tooltip__bubble {
  left: 0;
  transform: none;
}
.hs-card__icons > a:first-child:not(:last-child) .hs-icon-tooltip__bubble::after,
.hs-live-card__icons > a:first-child:not(:last-child) .hs-icon-tooltip__bubble::after {
  left: 22px;
  transform: none;
}
.hs-card__icons > a:last-child:not(:first-child) .hs-icon-tooltip__bubble,
.hs-live-card__icons > a:last-child:not(:first-child) .hs-icon-tooltip__bubble {
  left: auto;
  right: 0;
  transform: none;
}
.hs-card__icons > a:last-child:not(:first-child) .hs-icon-tooltip__bubble::after,
.hs-live-card__icons > a:last-child:not(:first-child) .hs-icon-tooltip__bubble::after {
  left: auto;
  right: 22px;
  transform: none;
}

.hs-live-card:focus-visible {
  outline: 2px solid var(--color-teal-700-primary-brand);
  outline-offset: 2px;
}

/* ============================================================
   CARD — shared thumb/hover treatment (exact port from hub.css .edu-card)
   ============================================================ */
/* width is set per-card by homesite-carousel.js (flex-basis/min-width,
   computed per breakpoint visible-count) — not a fixed CSS value, so the
   carousel can show 4/3/2/1.5 cards responsively like the ported source. */
.hs-card { display: flex; flex-direction: column; flex-shrink: 0; cursor: pointer; transition: box-shadow var(--transition-base); }
/* Not a real <a> (see buildActivityCard() in homesite-render.js — the
   resource-icon buttons inside are real nested <a> elements, which can't
   legally sit inside an outer <a>) — role="link" + tabindex so it's keyboard
   reachable, so it needs its own focus-visible ring rather than relying on
   native anchor focus styling. Same pattern as .hs-hero-slide--activity. */
.hs-card:focus-visible {
  outline: 2px solid var(--color-teal-700-primary-brand);
  outline-offset: 2px;
}

.hs-card__thumb {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--size-radius-200);
  border: 1px solid var(--color-teal-700-primary-brand);
  overflow: hidden;
  background: var(--color-slate-200);
  flex-shrink: 0;
}
.hs-card__thumb-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--transition-slow);
}
.hs-card:hover .hs-card__thumb-img { transform: scale(1.04); }

/* ============================================================
   CURRICULUM CARD — a genuinely different component from .hs-card, not a
   reuse. Pulled 2026-08-26 via get_design_context on the exact Figma node
   (fileKey Gp6X9g4nlAPqCCdBTC3s2o, node 11574:14996 "Curricula Highlight
   Image Container") after the earlier build wrongly reused the Activities
   .hs-card layout (image + separate white meta area below) for Curricula.
   The real design has NO separate meta area: the whole 264×220 card IS the
   image, with the tag pinned top-left and the title overlaid at the bottom
   on a gradient — and the image itself is a more square 264/220 ratio, not
   16:9.
   ============================================================ */
.hs-curriculum-card {
  position: relative;
  flex-shrink: 0;
  aspect-ratio: 264 / 220;
  border-radius: var(--size-radius-200);
  border: 1px solid var(--color-teal-700-primary-brand);
  /* overflow:clip, not hidden — hidden makes the card a scroll container, which
     zeroes the automatic min-height, so aspect-ratio could never grow and long
     titles got cut off. clip still rounds the corners but lets the card grow
     taller than 264/220 when tag + title need the room. */
  overflow: clip;
  display: flex;
  flex-direction: column;
  cursor: pointer;
  background: var(--color-slate-200);
}
.hs-curriculum-card__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--transition-slow);
}
.hs-curriculum-card:hover .hs-curriculum-card__img { transform: scale(1.04); }

/* min-width:0 — flex items default to min-width:auto, which stops them
   shrinking below their content's intrinsic width. Without this, the tag's
   long text pushes this row (and the tag's own max-width:100%/ellipsis,
   which resolves against this row) past the card edge instead of truncating. */
.hs-curriculum-card__tag-row { position: relative; min-width: 0; padding: var(--size-space-300); }
/* Deliberate override of the Figma spec's solid #F7A327 fill — reads too
   hot/saturated over bright/warm images. Dark glass (not light glass — see
   .hs-hero-slide__tag above) so it stays legible over any photo, bright or
   dark; this is now the site's one shared tag-on-image treatment. */
.hs-curriculum-card__tag {
  display: inline-flex;
  align-items: center;
  max-width: 100%;
  padding: var(--size-space-100) var(--size-space-200);
  border-radius: var(--size-radius-400);
  background: color-mix(in srgb, var(--color-black-1000) 55%, transparent);
  color: #ffffff;
  font-size: var(--typography-scale-01);
  font-weight: var(--typography-weight-regular);
}
/* text-overflow doesn't apply to flex containers per spec — the ellipsis has
   to live on a nested block/inline-block text span, not the pill itself. */
.hs-curriculum-card__tag-text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.hs-curriculum-card__content {
  position: relative;
  margin-top: auto;
  padding: 64px var(--size-space-300) var(--size-space-300);
  /* 0%/50% stops match the user's own Figma config exactly, but a 2-stop
     gradient holds flat at 50% opacity from the midpoint all the way to the
     bottom edge — right where the title text sits — so it read as too light
     there. Added a 3rd stop so it keeps darkening past the midpoint instead
     of plateauing. */
  background: linear-gradient(to bottom, color-mix(in srgb, var(--color-black-1000) 0%, transparent) 0%, color-mix(in srgb, var(--color-black-1000) 60%, transparent) 40%, color-mix(in srgb, var(--color-black-1000) 90%, transparent) 100%);
}
.hs-curriculum-card__title {
  margin: 0;
  max-width: 240px;
  font-size: var(--typography-scale-02);
  font-weight: var(--typography-weight-bold);
  line-height: 1.4;
  color: #fefefe;
}

/* "Access Now" strip slides up from below on hover — exact port of
   curriculum.css's .guideline-card__reveal ("Read More" on the Guidelines
   and Publications cards). */
.hs-curriculum-card__reveal {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  padding: 10px 20px;
  background: var(--color-teal-700-primary-brand);
  color: #ffffff;
  font-size: var(--typography-scale-02);
  font-weight: var(--typography-weight-semibold);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  transform: translateY(100%);
  transition: transform var(--transition-base);
  pointer-events: none;
}
.hs-curriculum-card__reveal-icon { width: 14px; height: 14px; flex-shrink: 0; filter: brightness(0) invert(1); }
.hs-curriculum-card:hover .hs-curriculum-card__reveal { transform: translateY(0); background: var(--color-teal-800); }

/* Exact port of .edu-card__play from curriculum.css: the pill is ALWAYS
   128px wide in the DOM (never animates width) — a clip-path masks it down
   to a 40px circle by default, then opens to reveal the full pill on hover.
   This sidesteps the earlier centering bug entirely (see homesite-carousel.js
   notes): because the box's real width never changes, the icon's flex
   position is identical before/after hover, so there's no risk of an
   invisible label's layout width throwing off centering math. */
.hs-card__play {
  position: absolute;
  top: 16px;
  left: 16px;
  height: 40px;
  width: 128px;
  border-radius: 20px;
  background: rgba(var(--color-teal-700-rgb), 0.92);
  display: flex;
  align-items: center;
  justify-content: flex-start;
  padding: 0 12px;
  white-space: nowrap;
  pointer-events: none;
  clip-path: inset(0 calc(100% - 40px) 0 0 round 20px);
  transition: clip-path var(--transition-base), background var(--transition-base);
}
/* will-change scoped to hover/focus, not the base rule — see the identical
   note on .hs-live-card__badge above: many cards sit in the DOM at once
   (most off-screen in a carousel), and promoting a compositor layer for
   every one of them unconditionally can itself be slow, janking the first
   few real hovers until the browser's compositor settles. */
.hs-card:hover .hs-card__play,
.hs-hero-slide--activity:hover .hs-card__play { clip-path: inset(0 0 0 0 round 20px); background: var(--color-teal-800); will-change: clip-path; }

.hs-card__play-icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  background-color: #ffffff;
  -webkit-mask-image: url('https://c.peervoice.com/assets/portal/images/icons/play.svg');
  mask-image: url('https://c.peervoice.com/assets/portal/images/icons/play.svg');
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
}
.hs-card__play-label { color: #ffffff; font-size: var(--typography-scale-02); font-weight: var(--typography-weight-semibold); margin-left: 6px; flex-shrink: 0; opacity: 0; transition: opacity var(--transition-base); }
.hs-card:hover .hs-card__play-label,
.hs-hero-slide--activity:hover .hs-card__play-label { opacity: 1; }

/* Optional per-activity disclaimer banner — exact port of Hub's `notice` field
   (hub.js/hub-hero.js render it verbatim if item.notice.trim() is truthy;
   see hub-handoff.md's Education docs — "renders as a small disclaimer on
   the card, e.g. 'Not intended for UK and Ireland-based Physicians.'"). Same
   optional `notice` string field on any activities.json item or heroCarousel
   'activity' slide — left unset on real data for now since which specific
   activities need it is a content decision, not implied by the mechanism. */
.hs-card__notice {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  background: var(--color-blush-700-highlight-brand);
  color: #ffffff;
  font-size: var(--typography-scale-01);
  font-weight: var(--typography-weight-semibold);
  line-height: 1.3;
  padding: 5px 8px;
  text-align: center;
  z-index: 2;
}
.hs-hero-activity__notice {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  background: var(--color-blush-700-highlight-brand);
  color: #ffffff;
  font-size: var(--typography-scale-02);
  font-weight: var(--typography-weight-semibold);
  line-height: 1.3;
  padding: 6px 12px;
  text-align: center;
  z-index: 2;
}

.hs-card__body { padding-top: var(--size-space-400); display: flex; flex-direction: column; gap: var(--size-space-300); flex: 1; }
.hs-card__date { margin: 0; font-size: var(--typography-scale-01); color: var(--color-slate-700); }
.hs-card__title {
  margin: 0;
  font-size: var(--typography-scale-02);
  font-weight: var(--typography-weight-bold);
  color: var(--color-teal-700-primary-brand);
  /* line-height made explicit (was browser-default) so the min-height
     below reserves a predictable, exact 3-line height (2026-09-03) —
     matches .hs-live-card__title/.hs-event-card__title's own values. */
  line-height: 1.35;
  min-height: calc(1.35em * 3);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.hs-card:hover .hs-card__title { color: var(--color-teal-800); }
.hs-card__speakers { margin: 0; font-size: var(--typography-scale-01); color: var(--color-black-1000); }
.hs-card__footer { margin-top: auto; display: flex; flex-direction: column; gap: var(--size-space-100); }
.hs-card__credit, .hs-card__lang { margin: 0; font-size: var(--typography-scale-01); color: var(--color-black-1000); }
/* 44px teal circle + white icon — exact port of .edu-card__resource-icon-wrap */
.hs-card__icons { display: flex; gap: 6px; margin-top: 10px; }
.hs-card__icon-btn {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--color-teal-700-primary-brand);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  cursor: pointer;
  transition: background var(--transition-base);
}
.hs-card__icon-btn:hover { background: var(--color-teal-800); }
.hs-card__icon-btn img { width: 18px; height: 18px; filter: brightness(0) invert(1); }

.hs-section--on-dark .hs-card__date,
.hs-section--on-dark .hs-card__speakers,
.hs-section--on-dark .hs-card__credit,
.hs-section--on-dark .hs-card__lang { color: color-mix(in srgb, var(--color-white-1000) 85%, transparent); }

/* ============================================================
   EVENTS SECTION — navy gradient + faint texture bg (shared w/ Hub/Curriculum)
   ============================================================ */
.hs-section--events {
  position: relative;
  background: linear-gradient(180deg, var(--color-blue-600), var(--color-blue-1000-primary-brand));
  overflow: hidden;
}
.hs-section--events::before {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: url('https://c.peervoice.com/assets/portal/images/event-bg-transparent.png') center bottom / cover no-repeat;
}
.hs-section--events .hs-section-heading { color: #ffffff; }
.hs-section--events .container { position: relative; z-index: 1; }

/* ============================================================
   EVENT CARD — exact port of .pvevt-card (curriculum.css), a distinct card
   family from .hs-card (not a modifier) since the real Hub/Curriculum
   implementation itself splits Education and PVEvents into two separate
   component families rather than one shared card with variants.
   ============================================================ */
.hs-event-card { flex-shrink: 0; border-radius: var(--size-radius-200); overflow: hidden; display: flex; flex-direction: column; cursor: pointer; transition: box-shadow var(--transition-base); }
.hs-event-card:hover { box-shadow: var(--drop-shadow-400); }

.hs-event-card__image-wrap {
  position: relative;
  aspect-ratio: 16 / 9;
  background: var(--color-blue-800);
  overflow: hidden;
  flex-shrink: 0;
  border: 1px solid var(--color-teal-700-primary-brand);
  border-radius: var(--size-radius-200);
}
.hs-event-card__bg {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  transition: transform var(--transition-slow);
}
.hs-event-card:hover .hs-event-card__bg { transform: scale(1.04); }

/* Register badge — mirrors .hs-card__play: fixed-width pill, clip-path reveal */
.hs-event-card__register {
  position: absolute;
  top: 16px;
  left: 16px;
  height: 40px;
  width: 100px;
  border-radius: 20px;
  background: rgba(var(--color-teal-700-rgb), 0.92);
  display: flex;
  align-items: center;
  justify-content: flex-start;
  padding: 0 12px;
  white-space: nowrap;
  z-index: 2;
  pointer-events: none;
  clip-path: inset(0 calc(100% - 40px) 0 0 round 20px);
  transition: clip-path var(--transition-base), background var(--transition-base);
}
/* will-change scoped to hover, not the base rule — see the identical note
   on .hs-card__play above. */
.hs-event-card:hover .hs-event-card__register { clip-path: inset(0 0 0 0 round 20px); background: var(--color-teal-800); will-change: clip-path; }
.hs-event-card__register-icon { width: 16px; height: 16px; flex-shrink: 0; background-color: #ffffff; -webkit-mask-image: url('https://c.peervoice.com/assets/portal/images/icons/date.svg'); mask-image: url('https://c.peervoice.com/assets/portal/images/icons/date.svg'); -webkit-mask-size: contain; mask-size: contain; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-position: center; mask-position: center; }
.hs-event-card__register-label { color: #ffffff; font-size: var(--typography-scale-02); font-weight: var(--typography-weight-semibold); margin-left: 6px; flex-shrink: 0; opacity: 0; transition: opacity var(--transition-base); }
.hs-event-card:hover .hs-event-card__register-label { opacity: 1; }
/* Past event: "Watch Now" pill with the play icon (128px, same as .hs-card__play / .hs-live-card__badge--watch). */
.hs-event-card__register--watch { width: 128px; }
.hs-event-card__register--watch .hs-event-card__register-icon { -webkit-mask-image: url('https://c.peervoice.com/assets/portal/images/icons/play.svg'); mask-image: url('https://c.peervoice.com/assets/portal/images/icons/play.svg'); }

/* Flex column, not a grid-with-trailing-1fr-row (2026-09-03 — same fix as
   .hs-live-card__body: a trailing empty grid row only pads blank space at
   the very bottom, it never pulls Time/Location down to meet it, so those
   rows still landed at whatever Y the title/faculty content above them
   happened to leave). .hs-event-card__time now gets margin-top:auto
   instead of a fixed gap, pinning Time/Location to the bottom of the card
   — same mechanism as .hs-card__footer/.hs-live-card__meta-row--first. */
.hs-event-card__content { padding-top: var(--size-space-400); display: flex; flex-direction: column; gap: 6px; flex: 1; }
.hs-event-card__date { font-size: var(--typography-scale-01); color: color-mix(in srgb, var(--color-white-1000) 55%, transparent); margin: 0; }
.hs-event-card__title {
  margin: 0;
  font-size: var(--typography-scale-02);
  font-weight: var(--typography-weight-semibold);
  color: var(--color-teal-500);
  line-height: 1.35;
  /* line-clamp:3 + reserved min-height (2026-09-03) — was 4, matching
     .hs-card__title/.hs-live-card__title's own 3-line convention now, plus
     the same reserved-height fix so "Time:" starts at the same Y across a
     row regardless of actual title length. */
  min-height: calc(1.35em * 3);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  transition: color var(--transition-base);
}
.hs-event-card:hover .hs-event-card__title { color: var(--color-teal-400); }
.hs-event-card__faculty { margin: 0; font-size: var(--typography-scale-01); color: var(--color-white-1000); line-height: 1.5; }
.hs-event-card__time, .hs-event-card__location { margin: 0; font-size: var(--typography-scale-01); color: var(--color-white-1000); line-height: 1.4; }
.hs-event-card__time { margin-top: auto; }
/* No custom strong styling (2026-09-03, removed) — matches .hs-card__credit/
   .hs-card__lang's own hands-off treatment: default browser bold + the
   parent's already-set color (white here), not a dimmed/lighter-weight
   label. Was font-weight:semibold + 90%-opacity white, making the "Time:"/
   "Location:" label read LESS prominent than its own value text — the
   opposite of the reference component's convention. */

/* ============================================================
   FACULTY QUOTES
   ============================================================ */
/* Pulled 2026-08-26 via get_design_context on the exact Figma node (fileKey
   Gp6X9g4nlAPqCCdBTC3s2o, node 11574:15258 "Expertise Statement Container")
   — the previous version used the wrong font family (serif display instead
   of DM Sans italic), wrong weight (looked bold), and wrong color (brand
   navy instead of near-black #0C0C0D). */
.hs-faculty-quote { text-align: center; max-width: 960px; margin: 0 auto; transition: opacity 0.25s ease; }
.hs-faculty-quote__text {
  font-family: var(--typography-family-sans);
  font-style: italic;
  font-weight: var(--typography-weight-regular);
  font-size: var(--typography-scale-04);
  color: var(--color-black-1000);
  line-height: 1.2;
  margin: 0 0 var(--size-space-800) 0;
}
.hs-faculty-quote__author { display: flex; align-items: center; justify-content: center; gap: var(--size-space-400); }
.hs-faculty-quote__avatar { width: 96px; height: 96px; border-radius: var(--size-radius-full); object-fit: cover; border: 1px solid var(--color-slate-300); }
.hs-faculty-quote__info { display: flex; flex-direction: column; gap: var(--size-space-100); align-items: flex-start; }
.hs-faculty-quote__name { margin: 0; font-weight: var(--typography-weight-bold); font-size: var(--typography-scale-01); color: var(--color-black-1000); }
.hs-faculty-quote__credentials { margin: 0; font-size: var(--typography-scale-01); color: var(--color-black-1000); white-space: pre-line; text-align: left; }

/* ============================================================
   AWARDS (infinite scroll strip)
   ============================================================ */
.hs-awards { overflow: hidden; }
.hs-awards__track {
  display: flex;
  align-items: center;
  gap: var(--size-space-2400);
  width: max-content;
  animation: hs-awards-scroll 30s linear infinite;
}
.hs-awards__logo { height: 90px; width: auto; opacity: 0.85; }
@keyframes hs-awards-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
@media (hover: none) {
  .hs-awards__track { animation-play-state: running; }
}

/* ============================================================
   MODAL + SHARE MODAL — exact port from hub.css (~L311-470), confirmed
   2026-08-25. Reused by PeerVoice/CLAUDE.md's documented modal pattern
   (overlay rgba(navy,0.80) + backdrop-filter blur(6px) + translateY entry).
   ============================================================ */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(var(--color-blue-1000-rgb), 0.80);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  z-index: 2000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--transition-slow);
}
.modal-overlay.is-open { opacity: 1; pointer-events: auto; }

.modal {
  background: #ffffff;
  border-radius: var(--size-radius-200);
  padding: 40px;
  max-width: 760px;
  width: 100%;
  max-height: 88vh;
  overflow-y: auto;
  position: relative;
  transform: translateY(20px);
  transition: transform var(--transition-slow);
  /* HomesiteModal.open() focuses this panel (tabindex="-1", set via JS) as
     an accessible landing point, not a real interactive control — its own
     default focus ring would just be a big box around the whole modal, so
     it's suppressed here. .modal__close still keeps its own focus-visible
     ring for genuine keyboard Tab navigation to it. */
  outline: none;
}
.modal-overlay.is-open .modal { transform: translateY(0); }

.modal__close {
  position: absolute;
  top: 20px;
  right: 24px;
  border: none;
  outline: none;
  background: none;
  cursor: pointer;
  font-size: var(--typography-scale-03);
  font-weight: var(--typography-weight-regular);
  color: var(--color-teal-700-primary-brand);
  background-image: linear-gradient(var(--color-teal-800), var(--color-teal-800));
  background-size: 0% 1px;
  background-repeat: no-repeat;
  background-position: left bottom;
  transition: color var(--transition-base), background-size var(--transition-base);
}
.modal__close:hover { color: var(--color-teal-800); background-size: 100% 1px; }
/* HomesiteModal.open() calls closeBtn.focus() on every modal open (correct
   for accessibility) — with no custom focus styling, the browser drew its
   own native focus ring (blue rounded box) instead of this site's teal
   ring. Matches the standard .hs-focus-ring values used everywhere else on
   this site (see PeerVoice/CLAUDE.md's non-negotiable focus-visible rule)
   rather than adding the utility class across all 31 pages' modal markup. */
.modal__close:focus-visible {
  outline: 2px solid var(--color-teal-700-primary-brand);
  outline-offset: 3px;
  box-shadow: 0 0 0 6px rgba(var(--color-teal-700-rgb), 0.25);
  border-radius: 2px;
}

.share-modal__heading {
  font-size: var(--typography-scale-04);
  font-weight: var(--typography-weight-bold);
  color: var(--color-blue-1000-primary-brand);
  line-height: 1.3;
  margin: 0 0 24px 0;
}
.share-modal__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 16px; }
.share-modal__btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 20px 16px;
  background: var(--color-teal-700-primary-brand);
  border: none;
  border-radius: var(--size-radius-200);
  color: #ffffff;
  font-family: inherit;
  cursor: pointer;
  width: 100%;
  transition: background var(--transition-base), transform var(--transition-base);
}
.share-modal__btn:hover { background: var(--color-teal-800); transform: scale(1.03); }
.share-modal__icon { width: 36px; height: 36px; flex-shrink: 0; }
.share-modal__label { font-size: var(--typography-scale-02); font-weight: var(--typography-weight-semibold); letter-spacing: 0.03em; }

.share-modal__copy-row {
  display: flex;
  gap: 0;
  border: 1.5px solid var(--color-teal-700-primary-brand);
  border-radius: var(--size-radius-100);
  overflow: hidden;
}
.share-modal__copy-input {
  flex: 1;
  padding: 10px 14px;
  border: none;
  outline: none;
  font-family: var(--typography-family-sans);
  font-size: var(--typography-scale-02);
  color: var(--color-slate-700);
  background: #ffffff;
  min-width: 0;
}
.share-modal__copy-btn {
  padding: 10px 20px;
  background: var(--color-teal-700-primary-brand);
  color: #ffffff;
  font-family: var(--typography-family-sans);
  font-size: var(--typography-scale-02);
  font-weight: var(--typography-weight-semibold);
  border: none;
  cursor: pointer;
  transition: background var(--transition-base);
  flex-shrink: 0;
}
.share-modal__copy-btn:hover { background: var(--color-teal-800); }

/* ============================================================
   SEARCH RESULTS MODAL — client-side only, activities-only for now.
   Reuses the shared .modal/.modal__close shell (same white card, same
   teal underline-grow-in "Close" link already matching the reference
   layout's own close treatment) — only the inner content is new.
   ============================================================ */
.hs-search-results__heading {
  margin: 0 0 var(--size-space-600) 0;
  padding-right: var(--size-space-1200);
  font-size: var(--typography-scale-04);
  font-weight: var(--typography-weight-bold);
  color: var(--color-blue-1000-primary-brand);
  line-height: 1.3;
}
.hs-search-results__count {
  font-weight: var(--typography-weight-regular);
  color: var(--color-slate-700);
}
.hs-search-results__empty { margin: 0; font-size: var(--typography-scale-03); color: var(--color-slate-700); }

.hs-search-results__list { display: flex; flex-direction: column; }

/* .hs-card--list: reuses every .hs-card__* class as-is (thumb, play button,
   date, title, speakers, footer/credit/lang, resource icons) — only repoints
   the card from the carousel's stacked thumb-over-body layout to a
   horizontal thumb-beside-body row, plus the divider/spacing a list needs
   between rows that a carousel doesn't. See buildActivityCard() in
   homesite-render.js for the shared markup this modifies. */
.hs-card--list {
  flex-direction: row;
  /* align-items defaults to stretch on a flex container — with the thumb's
     width fixed (below) and the row's height driven by the taller text
     column, stretch was giving the thumb a definite (tall) height that
     overrode its own aspect-ratio, so the image rendered stretched instead
     of a clean 16:9. flex-start makes the thumb size purely from its own
     aspect-ratio and keeps it top-aligned with the text, not centered or
     stretched to match it. */
  align-items: flex-start;
  gap: var(--size-space-600);
  padding: var(--size-space-600) 0;
  border-bottom: 1px solid var(--color-slate-300);
}
.hs-search-results__list > .hs-card--list:first-child { padding-top: 0; }
.hs-search-results__list > .hs-card--list:last-child { padding-bottom: 0; border-bottom: none; }
.hs-card--list .hs-card__thumb { width: 240px; flex-shrink: 0; }
.hs-card--list .hs-card__body { padding-top: 0; flex: 1; min-width: 0; }

@media (max-width: 767px) {
  .hs-card--list { flex-direction: column; }
  .hs-card--list .hs-card__thumb { width: 100%; }
}

/* ============================================================
   PODCAST — TA-page-only section ("Podcast Episodes in {TA}"), exact port
   of Hub's real .podcast__* component (hub.css ~L2375-2656, hub-podcast.js)
   with the hs- prefix, not a re-approximation. Real audio player: Now
   Playing panel + episode list + platform subscribe buttons.
   ============================================================ */
.hs-podcast__player {
  display: grid;
  grid-template-columns: 1fr 1fr;
  height: 300px;
  border-radius: var(--size-radius-200);
  overflow: hidden;
  box-shadow: 0 12px 40px var(--color-black-300);
  margin-bottom: var(--size-space-800);
}

.hs-podcast__now-playing {
  background: linear-gradient(90deg, var(--color-blue-700-secondary-brand) 0%, var(--color-blue-1000-primary-brand) 100%);
  padding: var(--size-space-600);
  display: flex;
  flex-direction: column;
  gap: var(--size-space-300);
  position: relative;
  overflow: hidden;
}
/* Decorative headset watermark — shared CDN asset, not re-uploaded locally
   (see PeerVoice/CLAUDE.md "Shared CDN Assets"). */
.hs-podcast__now-playing::after {
  content: '';
  position: absolute;
  right: -61px;
  bottom: 14px;
  width: 260px;
  height: 260px;
  background: url('https://c.peervoice.com/assets/images/hub_curriculum/Headset.svg') center / contain no-repeat;
  opacity: 0.04;
  pointer-events: none;
}
/* Corrected 2026-09-01 against the real Hub source (hub.css's real
   .podcast__np-label carries only color — its font-size/weight come from
   the separate .BodySmall utility class in the markup: scale-02/14px
   regular, not the scale-01/12px semibold guessed here originally). */
/* margin:0 needed — unlike .hs-podcast__episodes-label just below (which
   already zeroes its own margin), this <p> had no reset, so the browser's
   default UA-stylesheet <p> margin (1em ≈ 14px at this font-size) was
   pushing "Now Playing" out of top-alignment with "Episodes" — confirmed
   via getBoundingClientRect, not guessed. */
.hs-podcast__np-label { margin: 0; color: var(--color-teal-500); font-size: var(--typography-scale-02); font-weight: var(--typography-weight-regular); }
.hs-podcast__np-title { color: #ffffff; font-size: var(--typography-scale-04); font-weight: var(--typography-weight-bold); line-height: 1.3; margin: 0; }
.hs-podcast__np-date { color: var(--color-white-600); font-size: var(--typography-scale-02); margin: 0; }
.hs-podcast__np-artwork { display: none; }

.hs-podcast__controls { display: flex; align-items: center; gap: 14px; margin-top: auto; }
.hs-podcast__play-btn {
  width: 48px;
  height: 48px;
  border-radius: var(--size-radius-full);
  background: var(--color-teal-700-primary-brand);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: background var(--transition-base), transform var(--transition-base);
}
.hs-podcast__play-btn:hover:not(:disabled) { background: var(--color-teal-800); transform: scale(1.06); }
.hs-podcast__play-btn:focus-visible {
  outline: 2px solid var(--color-teal-700-primary-brand);
  outline-offset: 3px;
  box-shadow: 0 0 0 6px rgba(var(--color-teal-700-rgb), 0.25);
}
.hs-podcast__play-btn:disabled { opacity: 0.4; cursor: default; }
.hs-podcast__play-btn img { width: 20px; height: 20px; filter: brightness(0) invert(1); margin-left: 2px; }

.hs-podcast__scrubber-wrap { flex: 1; position: relative; height: 20px; display: flex; align-items: center; }
.hs-podcast__scrubber {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 4px;
  background: var(--color-white-200);
  border-radius: var(--size-radius-full);
  cursor: pointer;
  position: relative;
  z-index: 1;
}
.hs-podcast__scrubber:disabled { cursor: default; opacity: 0.4; }
.hs-podcast__scrubber::-webkit-slider-thumb { -webkit-appearance: none; width: 14px; height: 14px; border-radius: 50%; background: var(--color-teal-700-primary-brand); cursor: pointer; }
.hs-podcast__scrubber-fill {
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  height: 4px;
  width: 0%;
  background: var(--color-teal-700-primary-brand);
  border-radius: var(--size-radius-full);
  pointer-events: none;
}
.hs-podcast__time { color: var(--color-white-600); white-space: nowrap; flex-shrink: 0; font-family: var(--typography-family-mono); font-size: var(--typography-scale-01); }

.hs-podcast__episodes {
  background: #ffffff;
  border: 1.5px solid var(--color-teal-700-primary-brand);
  border-radius: var(--size-radius-0) var(--size-radius-200) var(--size-radius-200) var(--size-radius-0);
  padding: var(--size-space-600);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
/* Same real-BodySmall correction as .hs-podcast__np-label above. */
.hs-podcast__episodes-label { color: var(--color-blue-1000-primary-brand); font-size: var(--typography-scale-02); font-weight: var(--typography-weight-regular); margin: 0 0 var(--size-space-300) 0; }
.hs-podcast__episodes-list {
  flex: 1;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
  scrollbar-width: thin;
  scrollbar-color: var(--color-slate-300) transparent;
  list-style: none;
  margin: 0;
  padding: 0;
}
.hs-podcast__episodes-empty { margin: auto; padding: var(--size-space-600); text-align: center; color: var(--color-slate-700); font-size: var(--typography-scale-02); }
.hs-podcast__episode { display: block; padding: 10px 12px; border-radius: var(--size-radius-100); cursor: pointer; transition: background var(--transition-base); }
.hs-podcast__episode.is-active { background: var(--color-blue-100); }
.hs-podcast__episode-title { color: var(--color-teal-700-primary-brand); font-size: var(--typography-scale-02); font-weight: var(--typography-weight-semibold); line-height: 1.35; margin: 0 0 3px 0; transition: color var(--transition-base); }
.hs-podcast__episode:not(.is-active):hover .hs-podcast__episode-title { color: var(--color-teal-800); }
.hs-podcast__episode:focus-visible {
  outline: 2px solid var(--color-teal-700-primary-brand);
  outline-offset: 2px;
  box-shadow: 0 0 0 5px rgba(var(--color-teal-700-rgb), 0.25);
}
.hs-podcast__episode.is-active .hs-podcast__episode-title { color: var(--color-blue-1000-primary-brand); }
.hs-podcast__episode-date { color: var(--color-slate-600-secondary-brand); font-size: var(--typography-scale-01); margin: 0; }

.hs-podcast__footer { display: flex; flex-direction: column; align-items: flex-start; gap: var(--size-space-400); }
/* "These episodes are part of PeerVoice's '...' series" — same real
   attribution-line pattern as Hub_Curriculum's own seriesNote copy
   (content_curriculum.json), reused here instead of a standalone channel
   name/artwork treatment (tried, then reverted per direct feedback). */
.hs-podcast__series-note { margin: 0; font-size: var(--typography-scale-02); color: var(--color-slate-700); }
/* Real Apple Podcast/Spotify/TuneIn links for the matched channel —
   reinstated 2026-09-01 (was removed entirely on 2026-08-27 back when
   every TA pointed at the same placeholder channel with no real per-TA
   relevance) now that taPodcastChannel maps to real per-TA channels and
   all 8 channels have real platform URLs. Exact reuse of the Subscribe
   page's own .hs-subscribe-platform-btn component/icon technique. */
.hs-podcast__subscribe { display: flex; flex-wrap: wrap; gap: var(--size-space-200); }

@media (max-width: 767px) {
  .hs-podcast__player { grid-template-columns: 1fr; height: auto; }
  .hs-podcast__episodes { border-radius: 0 0 var(--size-radius-200) var(--size-radius-200); border-top: none; max-height: 280px; }
}

/* ============================================================
   LEGAL PAGES / CONTACT US — long-form prose content. Values pulled
   directly from the real Figma node (11824:4649 "Legal Pages", 11617:14669
   "Contact Us"), not approximated: light gray-to-white gradient background
   (distinct from Live Events' Past section gradient — different stop
   colors), numbered section headers as bold body-weight text (NOT the
   28px teal page-title style Contact Us's own topic headers use — legal
   docs and Contact Us intentionally use two different heading treatments
   in the source design, not an inconsistency to reconcile), static
   underlined teal inline links (not the animated roll-in-underline
   .hs-link treatment used for nav/card links elsewhere).
   ============================================================ */
.hs-legal-content {
  background: linear-gradient(180deg, #f4f4f4, #fefefe);
}
/* Subscribe reuses .hs-legal-content for its shared page-shell typography,
   but per the real Figma Subscribe mockup its content area has no gray
   gradient at all — plain #fefefe, same as the page's outer background.
   The gradient stays correct for Contact Us/Legal, which is what this
   class was actually built for. */
.hs-legal-content--white { background: #fefefe; }
/* Flat gray, not the gradient above — same "should not be a gradient,
   should be full gray" correction already applied to Past Live Events
   elsewhere on this site (see the Live Events CLAUDE.md section). */
.hs-legal-content--gray { background: var(--color-slate-200); }
.hs-legal-body { font-size: var(--typography-scale-02); line-height: 1.4; color: var(--color-black-1000); }
.hs-legal-body p { margin: 0 0 var(--size-space-400) 0; }

/* Numbered legal clauses (Terms of Use, e.g. "6.2.8.1.") — corrected
   2026-08-28 against the real live site (peervoice.com/terms.html), which
   renders these as an indented, multi-level hanging-indent list (number
   flush at its own depth, clause text hanging at a fixed offset so wrapped
   lines align under the text, not the number) rather than flush-left
   paragraphs. Kept as <p>, not <li> — these already carry their own number
   label, so a <ul> marker would just be a redundant/unwanted bullet (the
   exact bug this replaced). text-indent pulls only the first line (the
   number) back to its depth's left edge; padding-left sets where wrapped
   continuation lines land — the standard CSS hanging-indent technique. */
.hs-legal-clause--1 { padding-left: 40px; text-indent: -24px; }
.hs-legal-clause--2 { padding-left: 72px; text-indent: -32px; }
.hs-legal-clause--3 { padding-left: 104px; text-indent: -40px; }

.hs-legal-body h2 { margin: var(--size-space-600) 0 var(--size-space-200) 0; font-size: var(--typography-scale-02); font-weight: var(--typography-weight-bold); color: var(--color-black-1000); }
.hs-legal-body h2:first-child { margin-top: 0; }
.hs-legal-body ul, .hs-legal-body ol { margin: 0 0 var(--size-space-400) 0; padding-left: var(--size-space-600); }
.hs-legal-body li { margin-bottom: var(--size-space-200); }
.hs-legal-body strong { font-weight: var(--typography-weight-bold); }
.hs-legal-body a { color: var(--color-teal-700-primary-brand); text-decoration: underline; }
.hs-legal-body a:hover { color: var(--color-teal-800); }

/* Contact Us / About Us topic headers — the 28px teal page-title style,
   distinct from legal doc section headers above. */
/* .hs-legal-body .hs-topic-heading (not just .hs-topic-heading) — needs to
   out-specificity .hs-legal-body h2 above, since Contact Us reuses
   .hs-legal-body's paragraph/link typography for its own topic headers
   without wanting the legal-doc h2 styling too. */
.hs-legal-body .hs-topic-heading { margin: 0; font-size: var(--typography-scale-07); font-weight: var(--typography-weight-bold); color: var(--color-blue-1000-primary-brand); letter-spacing: -0.56px; }
/* Was an inline style on Contact Us's own container only — moved to a real
   shared class (2026-09-02) so the same JSON-driven sections[] renderer can
   target it on any page (Contact Us, Unsubscribe Success/Error) without
   repeating the inline style per page. A single-section page renders
   identically either way (flex-column with one child = normal block flow). */
.hs-content-sections { display: flex; flex-direction: column; gap: var(--size-space-800); }
.hs-address-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--size-space-800); width: 100%; }
.hs-address-grid h3 { margin: 0 0 var(--size-space-100) 0; font-size: var(--typography-scale-05); font-weight: var(--typography-weight-semibold); color: var(--color-blue-1000-primary-brand); }
.hs-address-grid p { margin: 0; font-size: var(--typography-scale-02); line-height: 1.4; color: var(--color-black-1000); }
@media (max-width: 767px) {
  .hs-address-grid { grid-template-columns: 1fr; gap: var(--size-space-600); }
}

/* ============================================================
   SUBSCRIBE PAGE — channel CTA banners + podcast channel list.
   Figma's own "PeerVoice YouTube Banner" component used Inter font and raw
   Tailwind gray hex values (#111827/#6b7280) rather than this project's
   real tokens — adapted to DM Sans + --color-black-1000/slate-600 per
   PeerVoice/CLAUDE.md's "use CSS custom properties exclusively" rule,
   keeping the exact layout/spacing (44px icon, 18px title, pill CTA).
   ============================================================ */
/* Full-width Sign Up capture box, above the YouTube/Slideshare banners.
   Copy is real, sourced from the live optin page's own intro paragraph
   (peervoice.com/optin), not invented. */
.hs-subscribe-signup {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--size-space-600);
  width: 100%;
  padding: var(--size-space-400) var(--size-space-600);
  background: #ffffff;
  border: 1px solid var(--color-teal-700-primary-brand);
  border-radius: var(--size-radius-200);
}
.hs-subscribe-signup__left { display: flex; align-items: center; gap: var(--size-space-400); flex: 1; min-width: 0; }
.hs-subscribe-signup__text { flex: 1; min-width: 0; }
.hs-legal-body p.hs-subscribe-signup__title { margin: 0 0 var(--size-space-100) 0; font-size: var(--typography-scale-04); font-weight: var(--typography-weight-bold); color: var(--color-black-1000); }
.hs-legal-body p.hs-subscribe-signup__subtitle { margin: 0; font-size: var(--typography-scale-02); color: var(--color-black-1000); }
/* Styled like the header's search field — a single rounded-pill container
   (not a separate gray input box + separate button) with the input
   flowing borderless/transparent inside it, and the action anchored at
   the right edge of the same pill. Bordered here (unlike the header's
   plain white, which sits on the teal header bar) so it's visible against
   this section's own white background. */
.hs-subscribe-signup__field {
  display: flex;
  align-items: center;
  gap: var(--size-space-200);
  flex-shrink: 0;
  padding: 4px 4px 4px var(--size-space-400);
  border-radius: var(--size-radius-full);
  background: #ffffff;
  border: 1px solid var(--color-teal-700-primary-brand);
}
.hs-subscribe-signup__field input {
  flex: 1;
  min-width: 240px;
  border: none;
  outline: none;
  background: transparent;
  font-family: inherit;
  font-size: var(--typography-scale-02);
  color: var(--color-black-1000);
}
.hs-subscribe-signup__field input::placeholder { color: var(--color-slate-600-secondary-brand); }
/* Icon-only submit, exact port of the header search field's own submit
   button/icon (.hs-header__search-submit/__search-icon) — plain arrow on
   white instead of a solid filled .hs-btn-pill, matching that field's
   restrained treatment rather than a heavy CTA. */
.hs-subscribe-signup__submit {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  flex-shrink: 0;
  border: none;
  border-radius: var(--size-radius-full);
  background: transparent;
  cursor: pointer;
  transition: background var(--transition-fast);
}
.hs-subscribe-signup__submit:hover { background: var(--color-teal-100); }
.hs-subscribe-signup__submit-icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  background-color: var(--color-teal-700-primary-brand);
  -webkit-mask-image: url('https://c.peervoice.com/assets/portal/images/icons/right.svg');
  mask-image: url('https://c.peervoice.com/assets/portal/images/icons/right.svg');
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}
@media (max-width: 767px) {
  .hs-subscribe-signup { flex-direction: column; align-items: stretch; }
  .hs-subscribe-signup__field { flex-direction: row; }
  /* The 320px desktop min-width (set above to close the gap before the
     field on wide screens) would overflow a narrow phone otherwise — the
     field is already stretched to the container's full width here via
     align-items:stretch, so the input just needs to be free to shrink
     with it instead of forcing its own fixed minimum. */
  .hs-subscribe-signup__field input { min-width: 0; }
}

/* .hs-legal-body a's underline (meant for inline legal-doc links) otherwise
   bleeds onto these big card-style anchors, since both reuse .hs-legal-body
   for its base paragraph typography — .hs-legal-body a.hs-subscribe-banner
   needed to out-specificity .hs-legal-body a's class+element selector. */
.hs-legal-body a.hs-subscribe-banner { text-decoration: none; }
.hs-subscribe-banners { display: flex; gap: var(--size-space-800); width: 100%; }
.hs-subscribe-banner {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--size-space-400);
  padding: var(--size-space-400);
  background: #ffffff;
  border: 1px solid var(--color-teal-700-primary-brand);
  border-radius: var(--size-radius-200);
}
/* Same scoped override already used for the hero carousel's CTA
   (.hs-hero-slide__panel .hs-btn-pill) — confirmed against the real Figma
   Subscribe node: this button is 12px/16px padding and regular weight,
   not the shared .hs-btn-pill base's bigger 10px/24px semibold treatment.
   Not a change to the shared base, which stays correct for other CTAs. */
.hs-subscribe-banner .hs-btn-pill { padding: 12px 16px; font-weight: var(--typography-weight-regular); }
/* CTA reads as "hovered" from anywhere on the card, not just when the
   cursor is directly over the small pill — the whole card already
   navigates to the same destination. Same technique/values as the hero
   carousel's .hs-hero-slide:hover .hs-btn-pill. */
.hs-subscribe-banner:hover .hs-btn-pill,
.hs-subscribe-banner:focus-visible .hs-btn-pill { background: var(--color-teal-800); transform: scale(1.03); }
.hs-subscribe-banner__left { display: flex; align-items: center; gap: var(--size-space-400); }
.hs-subscribe-banner__icon { width: 44px; height: 44px; border-radius: 50%; flex-shrink: 0; display: flex; align-items: center; justify-content: center; }
.hs-subscribe-banner__icon img { width: 20px; height: 20px; filter: brightness(0) invert(1); }
/* .hs-legal-body p's 16px bottom margin (meant for legal-doc paragraph
   spacing) was winning over these two rules' own margins — same class+
   element specificity bleed already fixed for text-decoration/color above,
   just hitting margin this time. .hs-legal-body p is (0,1,1); a bare class
   selector like .hs-subscribe-banner__title is only (0,1,0), so it lost.
   This is what was blowing up the card's vertical spacing (title/subtitle
   sitting 16px apart instead of 4px, plus 16px of dead space below the
   subtitle) — out-specify with the tag qualified onto .hs-legal-body p. */
.hs-legal-body p.hs-subscribe-banner__title { margin: 0 0 var(--size-space-100) 0; font-size: var(--typography-scale-04); font-weight: var(--typography-weight-bold); color: var(--color-black-1000); }
.hs-legal-body p.hs-subscribe-banner__subtitle { margin: 0; font-size: var(--typography-scale-02); color: var(--color-black-1000); }
/* Slideshare icon (slideshare_bubble.svg) is a complete, pre-composited
   44px icon — its own navy circle + white glyph baked in, unlike every
   other icon on this page which is a bare glyph tinted via the wrapper's
   background + filter:brightness(0) invert(1). Applying that tint here
   would flatten the whole multi-shape SVG to a solid white blob (exactly
   the "wrong icon" bug reported) — this modifier turns both off and lets
   the icon fill its wrapper edge-to-edge instead. */
.hs-subscribe-banner__icon--flat { background: none; }
.hs-subscribe-banner__icon--flat img { width: 100%; height: 100%; filter: none; }
/* Below 860px the card itself (not just the two-up wrapper, which already
   stacks at 767px) doesn't have room for icon+text beside the CTA on one
   row — the "Watch Now"/"View Now" label was wrapping to two lines.
   Starting the column switch at 860px instead of waiting for the 767px
   wrapper-stack breakpoint covers the narrow-but-still-side-by-side case
   too (confirmed from a real screenshot: two ~350px-wide cards, still in
   a row, already wrapping). align-items:flex-start so the CTA hugs its
   own width instead of stretching full-width once stacked. */
@media (max-width: 860px) {
  .hs-subscribe-banner { flex-direction: column; align-items: flex-start; }
}
@media (max-width: 767px) {
  .hs-subscribe-banners { flex-direction: column; }
}

.hs-subscribe-podcasts {
  display: flex;
  flex-direction: column;
  width: 100%;
  border: 1px solid var(--color-teal-700-primary-brand);
  border-radius: var(--size-radius-200);
  overflow: hidden;
}
.hs-subscribe-podcast-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--size-space-400);
  padding: var(--size-space-400);
  border-bottom: 1px solid var(--color-teal-700-primary-brand);
}
.hs-subscribe-podcast-row:last-child { border-bottom: none; }
.hs-subscribe-podcast-row__left { display: flex; align-items: center; gap: var(--size-space-400); min-width: 0; }
.hs-subscribe-podcast-row__art { width: 70px; height: 70px; border-radius: var(--size-radius-200); border: 1px solid var(--color-teal-700-primary-brand); object-fit: cover; flex-shrink: 0; }
/* Same .hs-legal-body p margin-bleed as the banner title/subtitle above —
   out-specified the same way. Was adding 16px of dead space under each
   podcast row's channel name, inflating every row's height. */
.hs-legal-body p.hs-subscribe-podcast-row__name { margin: 0; font-size: var(--typography-scale-02); font-weight: var(--typography-weight-bold); color: var(--color-black-1000); }
.hs-subscribe-podcast-row__platforms { display: flex; gap: var(--size-space-200); flex-wrap: wrap; justify-content: flex-end; }
.hs-legal-body a.hs-subscribe-platform-btn { text-decoration: none; }
/* .hs-legal-body a:hover's teal-800 text color (meant for inline legal-doc
   links) out-specifies .hs-subscribe-platform-btn:hover's white text below
   ((0,2,1) beats (0,2,0)) — same class+element-selector bleed already
   fixed for text-decoration above, just for color this time. Without this,
   hovering turns the button's background AND text the same teal-800,
   making the label invisible. */
.hs-legal-body a.hs-subscribe-platform-btn:hover { color: #ffffff; }
.hs-subscribe-platform-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--size-space-200);
  padding: var(--size-space-300) var(--size-space-400);
  border: 1px solid var(--color-teal-700-primary-brand);
  border-radius: var(--size-radius-full);
  background: #ffffff;
  color: var(--color-teal-700-primary-brand);
  font-size: var(--typography-scale-02);
  font-weight: var(--typography-weight-regular);
  white-space: nowrap;
  transition: background var(--transition-base), color var(--transition-base);
}
.hs-subscribe-platform-btn:hover { background: var(--color-teal-800); color: #ffffff; }
.hs-subscribe-platform-btn__icon { width: 16px; height: 16px; flex-shrink: 0; background-color: var(--color-teal-700-primary-brand); -webkit-mask-size: contain; mask-size: contain; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-position: center; mask-position: center; transition: background-color var(--transition-base); }
.hs-subscribe-platform-btn:hover .hs-subscribe-platform-btn__icon { background-color: #ffffff; }
.hs-subscribe-podcast-empty { padding: var(--size-space-400); margin: 0; color: var(--color-slate-600-secondary-brand); font-size: var(--typography-scale-02); }
@media (max-width: 767px) {
  .hs-subscribe-podcast-row { flex-direction: column; align-items: flex-start; }
  .hs-subscribe-podcast-row__platforms { justify-content: flex-start; }
}

/* ============================================================
   SIGN UP FORM — homesite's first real form-input styling.
   No prior input pattern exists in this file to reuse (checked) —
   border/radius/padding values follow the same 8px spacing grid
   and match the header search field's own bg/border treatment.
   ============================================================ */
/* align-items:flex-start — a column flex container with no align-items set
   defaults to stretch, which was stretching the Register button to fill
   the full 420px form width instead of hugging its own "Register →"
   content (the same flex-stretch trap already documented for
   .hs-hero-slide__panel elsewhere in this file). */
.hs-signup-form { display: flex; flex-direction: column; align-items: flex-start; max-width: 420px; }
.hs-signup-form__label { margin: 0 0 var(--size-space-100) 0; font-size: var(--typography-scale-02); font-weight: var(--typography-weight-semibold); color: var(--color-blue-1000-primary-brand); }
.hs-signup-form__input {
  width: 100%;
  padding: var(--size-space-300) var(--size-space-400);
  background: #f4f4f4;
  border: 1px solid var(--color-slate-600-secondary-brand);
  border-radius: var(--size-radius-200);
  font-family: inherit;
  font-size: var(--typography-scale-03);
  color: var(--color-black-1000);
  transition: border-color var(--transition-base);
}
.hs-signup-form__input::placeholder { color: var(--color-slate-600-secondary-brand); }
.hs-signup-form__input:focus { outline: none; border-color: var(--color-teal-700-primary-brand); }

/* Step 2 — the fuller registration form revealed after the email step,
   ported from the real live optin flow (see signup.html's own comment for
   the Playwright investigation this is based on). Wider than the email-only
   step 1 form since it carries a lot more field density. */
.hs-signup-form2 { max-width: 640px; }
.hs-signup-field { margin-top: var(--size-space-400); position: relative; }
.hs-signup-field:first-child { margin-top: 0; }
.hs-signup-required { color: var(--color-blush-700-highlight-brand); }
/* Native <select>, appearance reset + a chevron matching the exact path
   already used for .hs-nav__specialty-trigger-chevron elsewhere on this
   site — delivered as a mask-image (not a background <img>) since a native
   select can't hold a child element for the icon; the mask lets it take
   the same slate tint via background-color instead of a fixed baked-in
   color, same technique as this file's search/share icons. */
.hs-signup-form__select { appearance: none; -webkit-appearance: none; cursor: pointer; padding-right: 40px; }
.hs-signup-field--select::after {
  content: '';
  position: absolute;
  right: var(--size-space-400);
  bottom: 17px;
  width: 12px;
  height: 8px;
  background-color: var(--color-slate-600-secondary-brand);
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1L6 6L11 1' stroke='black' stroke-width='2' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1L6 6L11 1' stroke='black' stroke-width='2' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  pointer-events: none;
}

.hs-signup-checkbox { display: flex; align-items: flex-start; gap: var(--size-space-200); font-size: var(--typography-scale-02); color: var(--color-black-1000); cursor: pointer; }
.hs-signup-checkbox input { width: 18px; height: 18px; flex-shrink: 0; margin-top: 2px; accent-color: var(--color-teal-700-primary-brand); cursor: pointer; }

/* Real submission failure (Phoenix API) — no prior error-message convention
   existed on this site to reuse. */
.hs-signup-form__error { margin: var(--size-space-300) 0 0 0; font-size: var(--typography-scale-02); color: var(--color-red-700); }

.hs-signup-verification-panel { margin-top: var(--size-space-400); }
.hs-signup-dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--size-space-200);
  padding: var(--size-space-600);
  background: #f4f4f4;
  border: 1px dashed var(--color-slate-600-secondary-brand);
  border-radius: var(--size-radius-200);
  text-align: center;
  cursor: pointer;
  transition: border-color var(--transition-base), background var(--transition-base);
}
.hs-signup-dropzone:hover,
.hs-signup-dropzone:focus-visible,
.hs-signup-dropzone.is-dragover { border-color: var(--color-teal-700-primary-brand); background: #eaf9f8; outline: none; }
.hs-signup-dropzone__icon { width: 24px; height: 24px; background-color: var(--color-teal-700-primary-brand); -webkit-mask-image: url('https://c.peervoice.com/assets/portal/images/icons/plus.svg'); mask-image: url('https://c.peervoice.com/assets/portal/images/icons/plus.svg'); -webkit-mask-size: contain; mask-size: contain; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-position: center; mask-position: center; }
.hs-legal-body p.hs-signup-dropzone__text { margin: 0; font-size: var(--typography-scale-02); color: var(--color-black-1000); }
.hs-signup-dropzone__browse { color: var(--color-teal-700-primary-brand); font-weight: var(--typography-weight-semibold); text-decoration: underline; }
.hs-legal-body p.hs-signup-hint { margin: var(--size-space-200) 0 0 0; font-size: var(--typography-scale-01); color: var(--color-slate-600-secondary-brand); }
.hs-legal-body p.hs-signup-filename { margin: var(--size-space-200) 0 0 0; font-size: var(--typography-scale-02); font-weight: var(--typography-weight-semibold); color: var(--color-teal-800); }

/* ============================================================
   FOOTER — homesite's own instance, NOT a reuse of footer.css
   ============================================================ */
/* Spacing/sizing below matches footer.css's .site-footer exactly (checked
   2026-08-26 against Hub_Curriculum's real stylesheet, not approximated) —
   40px has no matching --size-space-* token (the scale jumps 32→48) so it's
   the one raw px value here, same exception already established elsewhere
   in this file for the hero brand spacing. */
.hs-footer { background: var(--color-blue-1000-primary-brand); color: #ffffff; padding: 64px 0; }
.hs-footer__top { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--size-space-600); flex-wrap: wrap; margin-bottom: 40px; }
.hs-footer__brand { display: flex; flex-direction: column; align-items: flex-start; gap: var(--size-space-200); }
/* width:230px + filter — exact match to footer.css .site-footer__logo */
.hs-footer__logo { width: 230px; height: auto; filter: brightness(0) invert(1); }
.hs-footer__copyright { margin: 0; font-size: var(--typography-scale-02); color: var(--color-white-800); }
.hs-footer__sponsor-logos { display: flex; align-items: center; gap: var(--size-space-600); flex-wrap: wrap; }
.hs-footer__sponsor-logo { height: 52px; width: auto; object-fit: contain; }
/* Per-badge overrides — different source aspect ratios read disproportionate
   at one flat height; EBAC is wide/horizontal so it needs to be shorter. */
.hs-footer__sponsor-logo[alt="EBAC accredited"] { height: 40px; }
.hs-footer__sponsor-logo[alt="gCMEp"] { height: 65px; }

.hs-footer__links { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--size-space-800); margin-bottom: 40px; }
.hs-footer__col-heading { margin: 0 0 var(--size-space-300) 0; font-size: var(--typography-scale-03); font-weight: var(--typography-weight-bold); color: #ffffff; }
.hs-footer__col-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--size-space-200); }
/* color override only — the underline-grow-in hover mechanic itself comes
   from the shared .hs-link class already on these links; .hs-link's own
   default (teal-700/800, tuned for light backgrounds) isn't legible enough
   on this dark navy footer, and unlike .hs-link, footer links don't change
   color on hover at all in the source — only the underline grows in. */
.hs-footer__col-link { color: var(--color-teal-500); font-size: var(--typography-scale-02); line-height: 1.4; }
.hs-footer__col-link:hover, .hs-footer__col-link:focus-visible { color: var(--color-teal-500); }
/* background-color, not the `background` shorthand — shorthand also resets
   background-image, which is exactly what .hs-link's underline-grow-in hover
   trick relies on, silently killing the hover effect on this one button. */
.hs-footer__cookie-btn { background-color: transparent; border: none; padding: 0; cursor: pointer; font-family: inherit; text-align: left; }

.hs-footer__description { margin: 0; font-size: var(--typography-scale-01); color: var(--color-white-800); line-height: 1.65; max-width: 960px; }

@media (max-width: 767px) {
  .hs-footer__top { flex-direction: column; }
  .hs-footer__links { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 479px) {
  .hs-footer__links { grid-template-columns: 1fr; }
}

/* ============================================================
   RESPONSIVE — breakpoints ported from hub.css (1279/1023/860/767/479)
   see CLAUDE.md "Responsive design"
   ============================================================ */
@media (max-width: 1279px) {
  .hs-hero__tagline { font-size: var(--typography-scale-07); }
}

@media (max-width: 767px) {
  .hs-carousel__track { margin-right: -32px; }
  .hs-section { padding: var(--size-space-1200) 0; }

  /* .hs-hero__brand's 126px/56px padding is a desktop-only measurement
     (matched pixel-for-pixel against the live Curriculum demo — see the
     comment on the base rule above), never revisited for narrow viewports.
     At mobile widths it pushes the logo far down the hero image and leaves
     a large dead gap before the carousel card appears, well past what a
     phone-height viewport can show above the fold. Scaled down to the
     project's spacing grid — but padding-top must clear .hs-header's own
     62px (position:fixed, opaque, z-index above the hero) with real margin
     to spare: 48px < 62px clipped the top of the logo behind the header on
     first pass (visually confirmed). 96px (--size-space-2400) is the
     smallest grid step comfortably above that floor. */
  .hs-hero__brand { padding-top: var(--size-space-2400); padding-bottom: var(--size-space-800); }
}

@media (max-width: 479px) {
  .hs-carousel__track { margin-right: -24px; }
  .hs-hero__brand { padding-bottom: var(--size-space-600); }
}

/* ============================================================
   ACCESSIBILITY
   ============================================================ */
@media (hover: none) {
  .hs-card:hover .hs-card__thumb-img { transform: none; }
  .hs-card:hover .hs-card__play,
  .hs-hero-slide--activity:hover .hs-card__play { clip-path: inset(0 calc(100% - 40px) 0 0 round 20px); background: rgba(var(--color-teal-700-rgb), 0.92); }
  .hs-card:hover .hs-card__play-label,
  .hs-hero-slide--activity:hover .hs-card__play-label { opacity: 0; }
  .hs-hero-slide--activity:hover .hs-hero-activity__img { transform: none; }
  .hs-hero-slide:hover .hs-hero-slide__image { transform: none; }
  .hs-hero-slide:hover .hs-btn-pill { background: var(--color-teal-700-primary-brand); transform: none; }
  .hs-curriculum-card:hover .hs-curriculum-card__img { transform: none; }
  .hs-curriculum-card:hover .hs-curriculum-card__reveal { transform: translateY(100%); }
  .hs-event-card:hover { box-shadow: none; }
  .hs-event-card:hover .hs-event-card__bg { transform: none; }
  .hs-event-card:hover .hs-event-card__register { clip-path: inset(0 calc(100% - 40px) 0 0 round 20px); background: rgba(var(--color-teal-700-rgb), 0.92); }
  .hs-event-card:hover .hs-event-card__register-label { opacity: 0; }
  .hs-live-card:hover .hs-live-card__thumb-img { transform: none; }
  .hs-live-card:hover .hs-live-card__badge { clip-path: inset(0 calc(100% - 40px) 0 0 round 20px); background: var(--color-teal-700-primary-brand); }
  .hs-live-card:hover .hs-live-card__badge-label { opacity: 0; }
  .hs-carousel__arrow:hover:not(:disabled) { background: transparent; border-color: var(--color-teal-700-primary-brand); transform: none; }
  .hs-carousel__arrow:hover:not(:disabled) .hs-carousel__arrow-icon { filter: invert(62%) sepia(28%) saturate(700%) hue-rotate(141deg) brightness(95%); }
  .hs-carousel__scrubber-thumb:hover { background: var(--color-slate-600-secondary-brand); }
  .hs-btn-pill:hover { background: var(--color-teal-700-primary-brand); transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; }
  .hs-awards__track { animation: none; }
}

/* ============================================================
   OSANO — hide the default floating "reopen cookie preferences" widget
   icon. Not a compliance regression: the same functionality already
   exists via the footer's "Manage Cookie Preferences" link, which calls
   window.Osano.cm.showDrawer(...) directly (see renderFooter() in
   homesite-render.js) — this only removes the redundant floating button.
   !important is warranted here since it's overriding a stylesheet Osano's
   own script injects at runtime, whose load-order relative to this file
   isn't guaranteed. ============================================================ */
.osano-cm-widget { display: none !important; }

/* ============================================================
   ORPHAN CONTROL — added 2026-10-05
   `balance` evens out line lengths on short text (headlines, titles);
   `pretty` stops a lone word landing on the last line of longer prose.
   Both are progressive enhancements: unsupported browsers (pretty is not
   yet in Firefox) just wrap as before, nothing breaks.
   ============================================================ */
.hs-hero__tagline,
.hs-section-heading,
.hs-topic-heading,
.hs-hero-slide__title,
.hs-hero-activity__title,
.hs-card__title,
.hs-live-card__title,
.hs-event-card__title,
.hs-curriculum-card__title { text-wrap: balance; }

.hs-hero__subtitle,
.hs-section-intro,
.hs-hero-slide__description,
.hs-faculty-quote__text,
.hs-legal-body p,
.hs-legal-body li { text-wrap: pretty; }

/* ============================================================
   HERO WITHOUT A SUBHEADLINE — added 2026-10-05
   With no subtitle, headline → carousel gap equals logo → headline gap
   (12px brand flex-gap + 24px tagline margin-top = 36px) instead of the
   56px subtitle→card padding, which assumed a subtitle line above it.
   Applies at every breakpoint, so it also overrides the mobile
   padding-bottom values above. Plain pages (.hs-hero--plain) keep their own.
   ============================================================ */
.hs-hero:not(.hs-hero--plain) .hs-hero__brand.hs-hero__brand--no-subtitle {
  padding-bottom: calc(var(--size-space-300) + var(--size-space-600));
}

/* ============================================================
   ABOUT US — marketing page. Added 2026-10-05.
   Editorial layout: DM Sans only (no serif — user preference, 2026-10-05); numerals
   and statements get weight/size contrast instead. No resting card shadows, no gradient text, pills only for
   interactive things; content blocks are separated by hairlines, not boxed
   cards (DESIGN.md Do's and Don'ts). Copy/measure is controlled with grid
   columns, never a max-width on a paragraph (site convention).
   ============================================================ */
.hs-about-heading {
  margin: 0 0 var(--size-space-600) 0;
  font-size: var(--typography-scale-08);
  font-weight: var(--typography-weight-bold);
  letter-spacing: -0.02em;
  line-height: 1.2;
  color: var(--color-blue-1000-primary-brand);
}
.hs-about-heading--on-dark { color: var(--color-white-1000); }

/* Count-up figures: serif numerals, teal suffix, fixed-width digits so the
   number doesn't jitter while it counts. */
.hs-about-figure {
  display: block;
  font-weight: var(--typography-weight-bold);
  line-height: 1;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  color: var(--color-blue-1000-primary-brand);
}
.hs-about-figure__suffix { color: var(--color-teal-700-primary-brand); }
.hs-about-figure--proof   { font-size: var(--typography-scale-10); }
.hs-about-figure--outcome { font-size: var(--typography-scale-10); }
.hs-about-figure--lima    { font-size: var(--typography-scale-08); color: var(--color-white-1000); }
/* The one deliberate off-scale display size on the page (96px desktop, 48px on phones). */
.hs-about-figure--anchor  { font-size: 96px; color: var(--color-white-1000); }
.hs-about-lima .hs-about-figure__suffix { color: var(--color-teal-400); }

/* Image slots. A null image in the JSON renders the placeholder: a quiet
   brand-tint block at the real aspect ratio, so layout can be reviewed
   before photography exists. */
.hs-about-media { position: relative; overflow: hidden; border-radius: var(--size-radius-200); border: 1px solid var(--color-slate-300); background: var(--color-slate-200); }
.hs-about-media img { display: block; width: 100%; height: 100%; object-fit: cover; }
.hs-about-media--placeholder { background: linear-gradient(160deg, var(--color-teal-200), var(--color-blue-200)); }
.hs-about-media--landscape { aspect-ratio: 4 / 3; }   /* team photo (1200x896) — was a tall 4/5 portrait */
.hs-about-media--step { aspect-ratio: 16 / 10; }
.hs-about-media--split { aspect-ratio: 4 / 3; }

/* ---- Chapter 1: About PeerVoice ---- */
.hs-about-intro { background: var(--color-white-1000); padding: var(--size-space-2400) 0 var(--size-space-1600); }
.hs-about-intro__grid { display: grid; grid-template-columns: minmax(0, 6fr) minmax(0, 6fr); gap: var(--size-space-1600); align-items: start; }
.hs-about-lead {
  margin: 0 0 var(--size-space-800) 0;
  font-size: var(--typography-scale-05);
  font-weight: var(--typography-weight-semibold);
  letter-spacing: -0.02em;
  line-height: 1.4;
  color: var(--color-blue-1000-primary-brand);
}
.hs-about-intro__cols { display: flex; flex-direction: column; gap: var(--size-space-400); }
.hs-about-intro__cols p { margin: 0; font-size: var(--typography-scale-03); line-height: 1.5; color: var(--color-slate-1000); }
/* Full-colour EBAC / gCMEp marks (images/about/*.svg) sit directly on the white page. The footer keeps its own white-on-navy PNGs. */
.hs-about-recognition { display: flex; align-items: center; gap: var(--size-space-800); margin-top: var(--size-space-800); }
/* EBAC is a wide wordmark and gCMEp a round seal: different heights so they carry equal visual weight. */
.hs-about-recognition img { display: block; width: auto; }
.hs-about-recognition img:first-child { height: 80px; }
.hs-about-recognition img:last-child { height: 100px; }

/* ---- Proof strip ---- */
.hs-about-proof { background: var(--color-white-1000); padding: 0 0 var(--size-space-2400); }
.hs-about-proof__list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: var(--size-space-600); }
.hs-about-proof__item { display: flex; flex-direction: column; gap: var(--size-space-200); padding-top: var(--size-space-400); border-top: 2px solid var(--color-teal-700-primary-brand); }
.hs-about-proof__label { font-size: var(--typography-scale-02); line-height: 1.4; color: var(--color-slate-900); }

/* ---- Chapter 2: How we deliver (sticky sequence) ---- */
.hs-about-deliver { background: var(--color-slate-100); }
.hs-about-deliver__head { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--size-space-1600); align-items: start; margin-bottom: var(--size-space-1200); }
.hs-about-deliver__head .hs-about-heading { margin: 0; }
.hs-about-deliver__intro { margin: 0; font-size: var(--typography-scale-03); line-height: 1.5; color: var(--color-slate-1000); }
/* "How we deliver". DEFAULT (phones, tablets, short windows, reduced motion, no-JS): a plain
   stacked sequence, each step with its own inline image — nothing pinned, no parallax.
   When initAboutSteps() decides the viewport can take it (>=1024px wide, tall enough to show the
   whole block, motion allowed) it adds .is-pinned to the section: the block then pins to the
   viewport with heading + intro fixed, image and text side by side, and the three steps
   cross-fading IN PLACE while you scroll (plus a subtle image parallax). After "Measure" the pin
   releases and the outcome figures scroll away with the section. */
.hs-about-steps { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--size-space-1200); }
.hs-about-steps__stage { display: none; }
.hs-about-steps__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--size-space-1200); }
.hs-about-step { display: flex; flex-direction: column; }
.hs-about-step__num { font-size: var(--typography-scale-10); font-weight: var(--typography-weight-bold); letter-spacing: -0.03em; line-height: 1; color: var(--color-teal-700-primary-brand); }
.hs-about-step__title { margin: var(--size-space-200) 0 var(--size-space-400) 0; font-size: var(--typography-scale-08); font-weight: var(--typography-weight-bold); letter-spacing: -0.02em; color: var(--color-blue-1000-primary-brand); }
.hs-about-step__text { margin: 0; font-size: var(--typography-scale-03); line-height: 1.5; color: var(--color-slate-1000); }
.hs-about-step__inline-media { display: block; margin: 0 0 var(--size-space-400) 0; }
/* pinned mode (class added by JS; track height + pin offset are set inline from the real content height) */
.hs-about-deliver.is-pinned .hs-about-deliver__pin { position: sticky; top: var(--size-space-400); }
.hs-about-deliver.is-pinned .hs-about-deliver__head { margin-bottom: var(--size-space-800); }
.hs-about-deliver.is-pinned .hs-about-steps { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--size-space-1600); align-items: center; }
.hs-about-deliver.is-pinned .hs-about-steps__stage { display: block; position: relative; aspect-ratio: 16 / 10; max-height: 40vh; }
/* the outcome figures are part of the pinned block, visible from the start */
.hs-about-deliver.is-pinned .hs-about-outcomes { margin-top: var(--size-space-1200); }
.hs-about-deliver.is-pinned .hs-about-steps__frame { position: absolute; inset: 0; opacity: 0; transition: opacity 400ms ease; }
.hs-about-deliver.is-pinned .hs-about-steps__frame.is-active { opacity: 1; }
.hs-about-deliver.is-pinned .hs-about-steps__frame .hs-about-media { width: 100%; height: 100%; aspect-ratio: auto; }
.hs-about-deliver.is-pinned .hs-about-steps__frame img { transform: translateY(calc(var(--hs-par, 0) * -16px)) scale(1.12); }
.hs-about-deliver.is-pinned .hs-about-steps__frame.is-active img { will-change: transform; }
.hs-about-deliver.is-pinned .hs-about-steps__list { display: grid; gap: 0; }
.hs-about-deliver.is-pinned .hs-about-step { grid-area: 1 / 1; justify-content: center; opacity: 0; transform: translateY(16px); pointer-events: none; transition: opacity 350ms ease, transform 350ms ease; }
.hs-about-deliver.is-pinned .hs-about-step.is-active { opacity: 1; transform: none; pointer-events: auto; transition-delay: 0.1s; }
.hs-about-deliver.is-pinned .hs-about-step__inline-media { display: none; }
.hs-about-outcomes { list-style: none; margin: var(--size-space-1600) 0 0 0; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--size-space-800); }
.hs-about-outcomes__item { display: flex; flex-direction: column; gap: var(--size-space-200); }
.hs-about-outcomes__label { font-size: var(--typography-scale-03); line-height: 1.4; color: var(--color-slate-900); }

/* ---- Practice-change band ---- */
/* Flat gray by default (site convention; also keeps it from merging with the navy LiMA band below).
   With a photo set in the JSON it flips to a navy-tinted image band with light text. */
.hs-about-impact { background: var(--color-slate-200); padding: var(--size-space-2400) 0; }
.hs-about-impact__text-col { display: flex; flex-direction: column; gap: var(--size-space-600); }
.hs-about-impact__grid { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: var(--size-space-1600); align-items: center; }
/* Full-width heading row, then the statement (large, teal) beside the supporting paragraph. */
.hs-about-impact__lead { margin: 0; font-size: var(--typography-scale-10); font-weight: var(--typography-weight-bold); letter-spacing: -0.03em; line-height: 1.15; color: var(--color-teal-700-primary-brand); }
.hs-about-impact__text { margin: 0; font-size: var(--typography-scale-03); line-height: 1.5; color: var(--color-slate-1000); }
.hs-about-impact__text strong { color: var(--color-blue-1000-primary-brand); font-weight: var(--typography-weight-bold); }

/* ---- Chapter 3: LiMA reach ---- */
.hs-about-lima { position: relative; overflow: hidden; background: linear-gradient(180deg, var(--color-blue-1000-primary-brand), var(--color-blue-900)); padding: var(--size-space-2400) 0; }
.hs-about-lima .container { position: relative; z-index: 1; }
/* Paragraph sits right beside the number (no dead gap). */
.hs-about-lima__top { display: grid; grid-template-columns: minmax(0, 4fr) minmax(0, 8fr); gap: var(--size-space-1200); align-items: center; margin-top: var(--size-space-1200); padding-bottom: var(--size-space-1200); }
.hs-about-anchor__label { display: block; margin-top: var(--size-space-200); font-size: var(--typography-scale-03); color: var(--color-teal-400); }
.hs-about-lima__text { margin: 0; font-size: var(--typography-scale-03); line-height: 1.5; color: color-mix(in srgb, var(--color-white-1000) 90%, transparent); }
/* Every hairline-separated block in this section (stats row, each text row) has the same
   48px above and below its content, so the vertical rhythm is uniform. */
.hs-about-lima__stats { list-style: none; margin: 0; padding: var(--size-space-1200) 0; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--size-space-600); border-top: 1px solid color-mix(in srgb, var(--color-white-1000) 20%, transparent); }
.hs-about-lima__stat { display: flex; flex-direction: column; gap: var(--size-space-200); }
.hs-about-lima__stat-label { font-size: var(--typography-scale-02); line-height: 1.4; color: color-mix(in srgb, var(--color-white-1000) 85%, transparent); }
/* Two stacked rows, each title above its copy (no side-by-side columns). */
.hs-about-lima__cols { display: flex; flex-direction: column; gap: var(--size-space-1200); }
.hs-about-lima__cols > div { display: flex; flex-direction: column; gap: var(--size-space-300); }
.hs-about-lima__col-title { margin: 0; font-size: var(--typography-scale-05); font-weight: var(--typography-weight-semibold); color: var(--color-white-1000); }
.hs-about-lima__cols p { margin: 0; font-size: var(--typography-scale-03); line-height: 1.5; color: color-mix(in srgb, var(--color-white-1000) 85%, transparent); }

/* ---- Why PeerVoice ---- */
.hs-about-why { background: var(--color-white-1000); }
.hs-about-why__list { list-style: none; margin: var(--size-space-800) 0 0 0; padding: 0; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--size-space-800); }
.hs-about-why__item { padding-top: var(--size-space-400); border-top: 1px solid var(--color-slate-600-secondary-brand); }
.hs-about-why__num { display: block; font-size: var(--typography-scale-08); font-weight: var(--typography-weight-bold); letter-spacing: -0.03em; line-height: 1; color: var(--color-teal-700-primary-brand); }
.hs-about-why__title { margin: var(--size-space-300) 0 var(--size-space-200) 0; font-size: var(--typography-scale-05); font-weight: var(--typography-weight-semibold); letter-spacing: -0.01em; color: var(--color-blue-1000-primary-brand); }
.hs-about-why__item p { margin: 0; font-size: var(--typography-scale-03); line-height: 1.5; color: var(--color-slate-1000); }

/* ---- Partner chapter: copy + web form ---- */
.hs-about-contact { position: relative; overflow: hidden; background: linear-gradient(180deg, var(--color-blue-700-secondary-brand), var(--color-blue-1000-primary-brand)); padding: var(--size-space-2400) 0; }
.hs-about-contact__network { position: absolute; left: 0; bottom: 0; width: 100%; height: 100%; object-fit: cover; object-position: left bottom; opacity: 0.35; pointer-events: none; }
.hs-about-contact__grid { position: relative; z-index: 1; display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); gap: var(--size-space-1600); align-items: start; }
.hs-about-contact__copy p { margin: 0 0 var(--size-space-400) 0; font-size: var(--typography-scale-03); line-height: 1.5; color: color-mix(in srgb, var(--color-white-1000) 90%, transparent); }
.hs-about-contact__copy .hs-about-contact__lead { font-size: var(--typography-scale-05); font-weight: var(--typography-weight-semibold); letter-spacing: -0.01em; line-height: 1.3; color: var(--color-white-1000); }
/* Same roll-in underline as .hs-link, in the light teal that reads on navy (colour stays put, the underline grows in). */
.hs-about-contact__copy a { color: var(--color-teal-400); text-decoration: none; background-image: linear-gradient(currentColor, currentColor); background-size: 0% 1px; background-repeat: no-repeat; background-position: left bottom; transition: background-size var(--transition-base); }
.hs-about-contact__copy a:hover, .hs-about-contact__copy a:focus-visible { background-size: 100% 1px; }
.hs-about-contact__copy a:focus-visible { outline: 2px solid var(--color-white-1000); outline-offset: 3px; border-radius: var(--size-radius-100); }
.hs-about-contact__panel { background: var(--color-white-1000); border: 1px solid var(--color-slate-300); border-radius: var(--size-radius-200); padding: var(--size-space-1200); }
.hs-about-form[hidden], .hs-about-form__success[hidden] { display: none; }
.hs-about-form .hs-signup-form__label { display: block; }
.hs-about-form__textarea { min-height: 156px; resize: vertical; }
.hs-about-form__submit { margin-top: var(--size-space-600); }
.hs-about-form__submit:disabled { opacity: 0.6; cursor: progress; transform: none; }
.hs-about-form__legal { text-wrap: pretty; margin: var(--size-space-400) 0 0 0; font-size: var(--typography-scale-01); line-height: 1.4; color: var(--color-slate-800); }
.hs-about-form__success { outline: none; }
.hs-about-form__success-title { margin: 0 0 var(--size-space-300) 0; font-size: var(--typography-scale-05); font-weight: var(--typography-weight-bold); color: var(--color-blue-1000-primary-brand); }
.hs-about-form__success p { margin: 0; font-size: var(--typography-scale-03); line-height: 1.5; color: var(--color-slate-1000); }
/* reCAPTCHA v3's floating badge is hidden on this page; the required
   attribution is shown in-line under the form instead (.hs-about-form__legal). */
body[data-content="about"] .grecaptcha-badge { visibility: hidden; }

/* ---- About: responsive ---- */
@media (max-width: 1023px) {
  .hs-about-lima__stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 1279px) {
  .hs-about-proof__list { grid-template-columns: repeat(3, minmax(0, 1fr)); row-gap: var(--size-space-800); }
  .hs-about-why__list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 1023px) {
  .hs-about-intro__grid, .hs-about-deliver__head, .hs-about-impact__grid,
  .hs-about-lima__top, .hs-about-contact__grid { grid-template-columns: minmax(0, 1fr); gap: var(--size-space-800); }
  .hs-about-lima__top { padding-bottom: var(--size-space-800); }
  .hs-about-lima__stats { padding-top: var(--size-space-800); padding-bottom: var(--size-space-800); }
  .hs-about-lima__cols { gap: var(--size-space-800); }
  .hs-about-impact__lead { font-size: var(--typography-scale-08); }
}
@media (max-width: 767px) {
  .hs-about-intro { padding: var(--size-space-1200) 0; }
  .hs-about-recognition { gap: var(--size-space-600); }
  .hs-about-recognition img:first-child { height: 50px; }
  .hs-about-recognition img:last-child { height: 64px; }
  .hs-about-proof { padding-bottom: var(--size-space-1200); }
  .hs-about-proof__list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .hs-about-figure--proof { font-size: var(--typography-scale-08); }
  .hs-about-outcomes { grid-template-columns: minmax(0, 1fr); }
  .hs-about-figure--outcome { font-size: var(--typography-scale-08); }
  .hs-about-figure--anchor { font-size: var(--typography-scale-10); }
  .hs-about-impact, .hs-about-lima, .hs-about-contact { padding: var(--size-space-1200) 0; }
  .hs-about-impact__lead { font-size: var(--typography-scale-08); }
  .hs-about-lima__stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .hs-about-figure--lima { font-size: var(--typography-scale-08); }
  .hs-about-why__list { grid-template-columns: minmax(0, 1fr); }
  .hs-about-contact__panel { padding: var(--size-space-600); }
}

/* ---- About: motion + touch safety (required by DESIGN.md) ---- */
@media (prefers-reduced-motion: reduce) {
  .hs-about-deliver.is-pinned .hs-about-steps__frame, .hs-about-deliver.is-pinned .hs-about-step { transition: none; }
}
@media (hover: none) {
  .hs-about-contact__copy a:hover { background-size: 0% 1px; }
}

/* ============================================================
   ABOUT US — orphan control (same rule as the site-wide block above, which
   predates the .hs-about-* classes). `balance` on short text (headings, titles,
   figure labels), `pretty` on paragraphs and leads. Added 2026-10-05.
   ============================================================ */
.hs-about-heading,
.hs-about-step__title,
.hs-about-why__title,
.hs-about-lima__col-title,
.hs-about-impact__lead,
.hs-about-proof__label,
.hs-about-outcomes__label,
.hs-about-lima__stat-label,
.hs-about-anchor__label { text-wrap: balance; }

.hs-about-lead,
.hs-about-intro__cols p,
.hs-about-deliver__intro,
.hs-about-step__text,
.hs-about-impact__text,
.hs-about-lima__text,
.hs-about-lima__cols p,
.hs-about-why__item p,
.hs-about-contact__lead,
.hs-about-contact__copy p,
.hs-about-form__success p { text-wrap: pretty; }

/* ============================================================
   ABOUT — STAT RULES (locked in 2026-10-06)
   Every stat group (number + label) gets the same 2px teal top rule as the proof strip
   (.hs-about-proof__item): the outcome figures (35/86/67) and the LiMA supporting stats (light
   teal on navy; replaces the old single hairline). Numbered text items (Why PeerVoice) keep their
   neutral gray rule on purpose — teal means "metric".
   ============================================================ */
.hs-about-outcomes__item { padding-top: var(--size-space-400); border-top: 2px solid var(--color-teal-700-primary-brand); }
.hs-about-lima__stats { border-top: 0; padding-top: 0; }
.hs-about-lima__stat { padding-top: var(--size-space-400); border-top: 2px solid var(--color-teal-400); }

/* ============================================================
   ABOUT — "evidence to practice" background dots in the pinned How-we-deliver block.
   Decorative <canvas> (aria-hidden), pinned layout only. Scattered, slightly varied dots settle into an
   ordered grid as you scroll through the sequence (drawn by initAboutSteps()). It overshoots the pin box
   so it also fills the margins above/below, and a radial mask keeps the middle (where the content sits)
   clear, so it is quiet on any monitor size and never sits behind body text.
   ============================================================ */
.hs-about-dots { display: none; }
/* clip the overshooting canvas to this section (overflow:clip, unlike hidden, keeps position:sticky working) */
.hs-about-deliver { overflow: clip; }
.hs-about-deliver.is-pinned .hs-about-deliver__pin { isolation: isolate; }
.hs-about-deliver.is-pinned .hs-about-deliver__pin > .container { position: relative; z-index: 1; }
.hs-about-deliver.is-pinned .hs-about-dots {
  display: block; position: absolute; z-index: 0; left: 0; right: 0; top: -140px; width: 100%; height: calc(100% + 280px);
  pointer-events: none;
  -webkit-mask-image: radial-gradient(ellipse 58% 62% at 50% 50%, transparent 40%, #000 100%);
  mask-image: radial-gradient(ellipse 58% 62% at 50% 50%, transparent 40%, #000 100%);
}

/* ============================================================
   ABOUT — LiMA honeycomb background (2026-10-06)
   A faint hexagon lattice (own geometry, 56px hexes) in the light teal, masked so it shows only in the
   top-right and bottom-left corners and fades out before the number and body copy. Static on phones;
   on larger screens it drifts slowly against the scroll (--hs-hex-y, set by initLimaHex()).
   ============================================================ */
.hs-about-lima::before {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48.5' height='84' viewBox='0 0 48.5 84'%3E%3Cg fill='none' stroke='%2398DBD6' stroke-opacity='0.2' stroke-width='1'%3E%3Cpath d='M0 14 L24.25 0 L48.5 14 M0 14 V42 M48.5 14 V42 M0 42 L24.25 56 L48.5 42 M24.25 56 V84'/%3E%3C/g%3E%3C/svg%3E");
  background-size: 48.5px 84px;
  background-position: 0 var(--hs-hex-y, 0px);
  -webkit-mask-image: radial-gradient(ellipse 55% 90% at 100% 0%, #000 0%, transparent 100%), radial-gradient(ellipse 45% 70% at 0% 100%, rgba(0,0,0,0.7) 0%, transparent 100%);
  mask-image: radial-gradient(ellipse 55% 90% at 100% 0%, #000 0%, transparent 100%), radial-gradient(ellipse 45% 70% at 0% 100%, rgba(0,0,0,0.7) 0%, transparent 100%);
}

/* About — partner band network: animated SVG unless the visitor prefers reduced motion (then the static one). */
.hs-about-contact__network--animated { display: none; }
@media (prefers-reduced-motion: no-preference) {
  .hs-about-contact__network--static { display: none; }
  .hs-about-contact__network--animated { display: block; }
}

/* ---- "Coming Soon" cards (activities, events) — non-interactive, no play/
   register pill, bold label in place of the date. Same rules as Hub/
   Curriculum's .edu-card--coming-soon. Kept last so these beat the base
   :hover rules at equal specificity. ---- */
.hs-card--coming-soon,
.hs-event-card--coming-soon,
.hs-live-card--coming-soon { cursor: default; }
.hs-card--coming-soon:hover .hs-card__thumb-img,
.hs-live-card--coming-soon:hover .hs-live-card__thumb-img { transform: none; }
.hs-event-card--coming-soon:hover { box-shadow: none; }
.hs-event-card--coming-soon:hover .hs-event-card__bg { transform: none; }
.hs-card--coming-soon .hs-card__title,
.hs-card--coming-soon:hover .hs-card__title,
.hs-live-card--coming-soon .hs-live-card__title,
.hs-live-card--coming-soon:hover .hs-live-card__title { color: var(--color-black-1000); }
.hs-event-card--coming-soon .hs-event-card__title,
.hs-event-card--coming-soon:hover .hs-event-card__title { color: var(--color-white-1000); }
.hs-card__date--coming-soon,
.hs-live-card__date--coming-soon { font-weight: var(--typography-weight-bold); color: var(--color-black-1000); }
.hs-event-card__date--coming-soon { color: var(--color-white-1000); }

/* ============================================================
   >>> HIDE HERO CAROUSEL BELOW 1024px — added 2026-10-20 <<<
   On the homepage and the 17 specialty pages, devices narrower than 1024px
   no longer show the hero carousel (.hs-hero__body) and the header's 200px
   "runway" padding (which only exists to host the overlapping card) is zeroed.
   Scoped to .hs-hero:not(.hs-hero--plain): plain pages never had a carousel
   and keep their own spacing. Breakpoint matches the site's existing 1023px.
   TO REVERT to the previous behaviour (carousel on every screen size):
   delete this whole block, from the first marker to the END marker.
   Nothing else was changed — no HTML or JS edits were needed.
   ============================================================ */
@media (max-width: 1023px) {
  .hs-hero:not(.hs-hero--plain) .hs-hero__body { display: none; }
  .hs-hero:not(.hs-hero--plain) .hs-hero__header { padding-bottom: 0; }
}
/* >>> END HIDE HERO CAROUSEL BELOW 1024px <<< */

/* iOS Safari inflates text in wide/overflowing blocks (carousel cards rendered
   ~2x on iPhone). Pin it to the authored sizes. */
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }

/* Mobile: let carousels run off the right edge of the screen (peek of the next
   card) by cancelling the container's right padding. Left edge stays aligned
   with the heading. Matches Hub/Curriculum's bleed (32px, 24px on small phones). */
@media (max-width: 767px) {
  .hs-carousel { margin-right: -32px; }
}
@media (max-width: 479px) {
  .hs-carousel { margin-right: -24px; }
}
