/*
 * Reusable components: layout primitives, buttons, header, cards, footer.
 * Everything is composed from tokens.css.
 */

/* ---------------------------------------------------------------
 * Layout primitives
 * --------------------------------------------------------------- */

.container {
  width: 100%;
  max-width: calc(var(--container) + var(--gutter) * 2);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section {
  padding-block: var(--section-y);
}

.section--tight {
  padding-block: var(--section-y-tight);
}

.section--flush {
  padding-block: 0;
}

.section--dark {
  background: var(--color-bg-dark);
  color: var(--color-text-invert);
}

/*
 * Three-up grid. Collapses to two then one rather than squeezing three
 * columns down to unreadable widths, which is the state the design never drew.
 */
.grid-3 {
  display: grid;
  gap: var(--grid-gap);
  grid-template-columns: repeat(3, 1fr);
}

@media (max-width: 900px) {
  .grid-3 {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 600px) {
  .grid-3 {
    grid-template-columns: 1fr;
  }
}

/*
 * Backdrop: a full-bleed photo behind content, with a scrim.
 * The scrim is not decoration. White type over an arbitrary client-uploaded
 * photo is a contrast failure waiting to happen; this makes it deterministic.
 */
.backdrop {
  position: absolute;
  inset: 0;
  overflow: hidden;
  z-index: 0;
}

.backdrop__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.has-backdrop {
  position: relative;
  isolation: isolate;
}

.has-backdrop > .container,
.has-backdrop > .backdrop-content {
  position: relative;
  /* Above the scrim at 1 and the contour pattern at 2. */
  z-index: 3;
}

.has-backdrop::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: var(--scrim-band);
  pointer-events: none;
}

.has-backdrop--hero::after {
  background: var(--scrim-hero);
}

/*
 * The last three bands of the page, weighted so they step down rather than
 * merge: testimonial lightest, "why choose" a step darker, footer darkest.
 */
.testimonial.has-backdrop::after {
  background: var(--scrim-band-light);
}

.why.has-backdrop::after {
  background: var(--scrim-band-mid);
}

/* ---------------------------------------------------------------
 * Type helpers
 * --------------------------------------------------------------- */

.eyebrow {
  margin: 0 0 var(--space-3);
  color: var(--color-accent);
  font-size: var(--fs-h3);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caps);
  line-height: var(--lh-tight);
  text-transform: uppercase;
}

.section-title {
  font-size: var(--fs-h2);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
}

.section-title--accent {
  color: var(--color-accent);
}

.lead {
  font-size: var(--fs-body-lg);
  line-height: var(--lh-body);
}

/* ---------------------------------------------------------------
 * Buttons
 * --------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--btn-py) var(--btn-px);
  border: var(--border-w) solid transparent;
  border-radius: var(--radius);
  font-size: var(--fs-btn);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caps);
  line-height: 1;
  text-decoration: none;
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color var(--dur) var(--ease),
              color var(--dur) var(--ease),
              border-color var(--dur) var(--ease);
}

.btn--solid {
  background: var(--color-accent);
  border-color: var(--color-accent);
  color: var(--color-text-invert);
}

.btn--solid:hover,
.btn--solid:focus-visible {
  background: var(--sgh-charcoal);
  border-color: var(--sgh-charcoal);
}

/* On light backgrounds */
.btn--outline {
  background: transparent;
  border-color: var(--color-accent);
  color: var(--color-text);
}

.btn--outline:hover,
.btn--outline:focus-visible {
  background: var(--color-accent);
  color: var(--color-text-invert);
}

/* On dark backgrounds */
.btn--outline-light {
  background: transparent;
  border-color: var(--color-accent);
  color: var(--color-text-invert);
}

.btn--outline-light:hover,
.btn--outline-light:focus-visible {
  background: var(--color-accent);
}

/* Text link with an arrow, as used on the cards and the membership panel */
.btn--inline {
  padding: 0;
  border: 0;
  background: none;
  color: var(--color-accent);
  letter-spacing: var(--ls-caps-tight);
  text-transform: none;
}

.btn--inline .btn__arrow {
  transition: transform var(--dur) var(--ease);
}

.btn--inline:hover .btn__arrow,
.btn--inline:focus-visible .btn__arrow {
  transform: translateX(0.25em);
}

/*
 * Inline links are orange, which measures 5.85:1 on charcoal and 3.37:1 on
 * white. Every use until the CONNECT member cards was on a dark band, so this
 * variant exists for the light ones: charcoal for the label, which is where the
 * meaning is, and the accent kept on the arrow, which is decorative and
 * aria-hidden. There is no orange that clears 4.5:1 on white and still reads as
 * the brand orange, so the label has to give way rather than the colour.
 */
.btn--inline-dark {
  color: var(--color-text);
}

.btn--inline-dark .btn__arrow {
  color: var(--color-accent);
}

.btn--inline-dark:hover,
.btn--inline-dark:focus-visible {
  color: var(--color-accent);
}

/* ---------------------------------------------------------------
 * Site header
 * --------------------------------------------------------------- */

/*
 * Fixed, so it stays with you down the page. It starts transparent over a hero
 * and picks up its charcoal once you have scrolled past the top, which is what
 * keeps it readable over whatever the photograph happens to be doing.
 */
.site-header {
  position: fixed;
  inset-inline: 0;
  top: 0;
  z-index: var(--z-header);
  padding-block: var(--space-5);
  transition: background-color var(--dur) var(--ease),
              padding var(--dur) var(--ease);
}

.site-header.is-scrolled {
  padding-block: var(--space-4);
  background: var(--color-bg-dark);
  box-shadow: 0 1px 0 var(--color-rule-invert);
}

/*
 * Templates that do not open with a hero have nothing for the header to sit
 * over, so the page starts below it instead.
 */
body:not(.page-type-home):not(.page-type-event):not(.page-type-package) {
  padding-top: var(--header-h);
}

/*
 * Anything an in-page link can target has to clear the fixed header, or the
 * heading you jumped to ends up underneath it. #packages is the one in use.
 */
[id] {
  scroll-margin-top: calc(var(--header-h) + var(--space-4));
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: clamp(var(--space-4), 2vw, var(--space-6));
  /*
   * Without this the row can grow past the container and push the button off
   * the right edge instead of the nav tightening up.
   */
  flex-wrap: nowrap;
  min-width: 0;
}

.site-header__logo {
  flex: 0 0 auto;
  display: block;
  line-height: 0;
}

/*
 * Sized so the logo, six nav items and the button all fit inside the 1248px
 * container. The design uses the stacked secondary lockup, which is roughly a
 * third of this width; until that asset arrives the horizontal primary has to
 * be held to a height that leaves the nav its room.
 */
.site-header__logo img {
  width: auto;
  max-height: 2rem;
}

/*
 * The header type is white everywhere: over a hero photograph on the templates
 * that open with one, over a solid charcoal bar on the rest.
 */
.site-header,
.site-header a {
  color: var(--color-text-invert);
}

/*
 * Templates that open with a full-bleed hero carry the header over the
 * photograph, as both designs draw it. Everything else gets the solid bar,
 * because a transparent header over white would be invisible.
 */
/* Pages with no hero start with the bar already solid rather than fading in. */
body:not(.page-type-home):not(.page-type-event):not(.page-type-package) .site-header {
  background: var(--color-bg-dark);
}

/*
 * The gap is the only slack in this row, and the row is at its limit: swapping
 * "Events" for "Corporate Events" put 9px of real overflow on every page until
 * this came down. Any further nav item will need the breakpoint raising rather
 * than this squeezing again.
 */
.primary-nav__list {
  display: flex;
  align-items: center;
  gap: clamp(var(--space-3), 1.9vw, var(--space-6));
  margin: 0;
  padding: 0;
  list-style: none;
}

.primary-nav__list a {
  display: inline-block;
  padding-block: var(--space-2);
  font-size: var(--fs-nav);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-caps);
  text-decoration: none;
  text-transform: uppercase;
  white-space: nowrap;
}

.primary-nav__list a:hover,
.primary-nav__list .current-menu-item > a {
  color: var(--color-accent);
}

.site-header__cta {
  flex: 0 0 auto;
}

/* Mobile navigation toggle */
.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
}

.nav-toggle__bar {
  display: block;
  width: 1.75rem;
  height: 2px;
  background: currentColor;
  transition: transform var(--dur) var(--ease), opacity var(--dur) var(--ease);
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(2) {
  opacity: 0;
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

/*
 * The nav has six items plus a button. Measured, that row needs about 1310px,
 * and the container only reaches that from roughly 1400px up. Below it the nav
 * becomes a panel rather than wrapping into a shape the design never drew or
 * quietly pushing the button off the right edge, which is what it did before
 * this was measured.
 */
@media (max-width: 1400px) {
  .nav-toggle {
    display: flex;
  }

  .site-header__nav {
    position: fixed;
    inset: 0;
    z-index: var(--z-mobile-nav);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-6);
    padding: var(--space-9) var(--gutter);
    background: var(--color-bg-dark);
    overflow-y: auto;
    /*
     * Slides down, not in from the side. A panel parked at translateX(100%)
     * sits beyond the right edge and counts towards documentElement.scrollWidth,
     * which is real horizontal overflow on every page even while the menu is
     * shut. Vertically there is nothing to overflow.
     */
    transform: translateY(-100%);
    visibility: hidden;
    transition: transform var(--dur-slow) var(--ease), visibility var(--dur-slow);
  }

  .site-header__nav[data-open="true"] {
    transform: translateY(0);
    visibility: visible;
  }

  .primary-nav__list {
    flex-direction: column;
    gap: var(--space-5);
    text-align: center;
  }

  .primary-nav__list a {
    font-size: var(--fs-h3);
  }

  .site-header__cta--desktop {
    display: none;
  }
}

@media (min-width: 1401px) {
  .site-header__cta--mobile {
    display: none;
  }
}

/* ---------------------------------------------------------------
 * Event card
 * --------------------------------------------------------------- */

.event-card {
  display: flex;
  flex-direction: column;
  background: var(--color-bg-dark);
  color: var(--color-text-invert);
  text-decoration: none;
}

.event-card__media {
  position: relative;
  aspect-ratio: 1000 / 1042;
  overflow: hidden;
}

.event-card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur-slow) var(--ease);
}

.event-card:hover .event-card__media img,
.event-card:focus-visible .event-card__media img {
  transform: scale(1.04);
}

/* Placeholder for an event with no image yet, so the grid never collapses. */
.event-card__media--empty {
  background: var(--sgh-slate);
}

.event-card__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  /*
   * margin-top:auto keeps the bars aligned across a row when one title wraps
   * to two lines and its neighbours do not.
   */
  margin-top: auto;
  padding: var(--space-5);
}

.event-card__title {
  font-size: var(--fs-card-title);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
}

.event-card__cue {
  flex: 0 0 auto;
  color: var(--color-accent);
  font-size: var(--fs-btn);
}

.event-card__cue .btn__arrow {
  display: inline-block;
  transition: transform var(--dur) var(--ease);
}

.event-card:hover .event-card__cue .btn__arrow {
  transform: translateX(0.25em);
}

.event-card__date {
  display: block;
  margin-top: var(--space-1);
  color: var(--sgh-stone);
  font-size: var(--fs-label);
  font-weight: var(--fw-regular);
  letter-spacing: var(--ls-body);
  text-transform: none;
}

/* ---------------------------------------------------------------
 * Site footer
 * --------------------------------------------------------------- */

.site-footer {
  background: var(--color-bg-dark);
  color: var(--color-text-invert);
  padding-block: var(--section-y) var(--space-6);
}

.site-footer__top {
  display: grid;
  gap: var(--space-8);
  grid-template-columns: minmax(0, 1.2fr) repeat(2, minmax(0, 1fr));
  padding-bottom: var(--space-8);
  border-bottom: 1px solid var(--color-rule-invert);
}

@media (max-width: 800px) {
  .site-footer__top {
    grid-template-columns: 1fr;
  }
}

.site-footer__logo img {
  width: auto;
  max-height: 4.5rem;
  margin-bottom: var(--space-5);
}

.site-footer__tagline {
  color: var(--sgh-stone);
  font-size: var(--fs-label);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
}

.site-footer__heading {
  margin-bottom: var(--space-4);
  color: var(--color-accent);
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
}

.site-footer__list {
  margin: 0;
  padding: 0;
  list-style: none;
}

/*
 * Size on the item, not the link. The contact list mixes links with plain
 * text: the phone and email are anchors, the address is not, so hanging the
 * size on `a` left the address at the inherited 18px against 15px for the two
 * above it. Nothing intended that, it was just the rule landing on the wrong
 * element.
 */
.site-footer__list li {
  font-size: var(--fs-label);
}

.site-footer__list li + li {
  margin-top: var(--space-3);
}

.site-footer__list a {
  text-decoration: none;
}

.site-footer__list a:hover {
  color: var(--color-accent);
  text-decoration: underline;
}

.site-footer__bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding-top: var(--space-6);
  color: var(--sgh-stone);
  font-size: 0.8125rem;
}

.site-footer__legal {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-5);
  margin: 0;
  padding: 0;
  list-style: none;
}

.site-footer__legal a {
  text-decoration: none;
}

.site-footer__legal a:hover {
  color: var(--color-accent);
  text-decoration: underline;
}

/*
 * Stone, not slate. Slate on charcoal measures 2.3:1, which fails WCAG AA and
 * is genuinely hard to read; small print still has to be readable print.
 */
.site-footer__registration {
  width: 100%;
  margin: 0;
  color: var(--sgh-stone);
  font-size: 0.75rem;
  line-height: var(--lh-body);
  opacity: 0.75;
}

/* ---------------------------------------------------------------
 * Shared page sections
 *
 * The testimonial and "why choose SGH" bands are identical on the
 * homepage and on every event page, so they live here rather than in
 * either page's stylesheet.
 * --------------------------------------------------------------- */

/* ---------------------------------------------------------------
 * Testimonial
 * --------------------------------------------------------------- */

.testimonial {
  position: relative;
  padding-block: var(--section-y);
  color: var(--color-text-invert);
  text-align: center;
}

.testimonial__inner {
  max-width: var(--container-narrow);
  margin-inline: auto;
}

.testimonial__heading {
  margin-bottom: var(--space-6);
  color: var(--color-accent);
  font-size: var(--fs-h2);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
}

.testimonial__quote {
  margin: 0;
  font-size: var(--fs-body-lg);
  line-height: var(--lh-body);
}

.testimonial__quote p:last-child {
  margin-bottom: 0;
}

.testimonial__attribution {
  margin-top: var(--space-6);
  font-size: var(--fs-body);
}

.testimonial__name {
  color: var(--color-accent);
  font-weight: var(--fw-semibold);
  font-style: normal;
}

.testimonial__role {
  font-style: normal;
}

/* ---------------------------------------------------------------
 * Why choose SGH
 * --------------------------------------------------------------- */

.why {
  position: relative;
  padding-block: var(--section-y);
  color: var(--color-text-invert);
  text-align: center;
}

.why__label {
  margin-bottom: var(--space-4);
  font-size: var(--fs-h3);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
}

.why__title {
  max-width: 22ch;
  margin: 0 auto var(--space-10);
  color: var(--color-accent);
  font-size: var(--fs-h2-lg);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caps-tight);
  line-height: var(--lh-display);
  text-transform: uppercase;
}

.why__list {
  display: grid;
  gap: var(--space-8) 0;
  grid-template-columns: repeat(4, 1fr);
  margin: 0;
  padding: 0;
  list-style: none;
}

/*
 * Hairline dividers between columns. Drawn with a border on the item rather
 * than a separate element so they cannot outlive their column when the grid
 * reflows.
 */
.why__item {
  padding-inline: var(--space-5);
}

.why__item + .why__item {
  border-left: 1px solid var(--color-rule-invert);
}

@media (max-width: 900px) {
  .why__list {
    grid-template-columns: repeat(2, 1fr);
  }

  .why__item + .why__item {
    border-left: 0;
  }
}

@media (max-width: 520px) {
  .why__list {
    grid-template-columns: 1fr;
  }
}

.why__icon {
  width: clamp(4.5rem, 8vw, 6.5rem);
  height: auto;
  margin: 0 auto var(--space-5);
  /*
   * The supplied icons are orange, which puts three oranges in one column: the
   * icon, the heading under it and the accent everywhere else on the band.
   * White separates the picture from the label and lets the heading carry the
   * accent on its own.
   *
   * Done in CSS rather than by re-exporting, because these came out of the
   * Figma PDF rather than from SGH and their licence is still the designer's
   * to confirm. brightness(0) flattens to black first, so invert lands on pure
   * white whatever the source colour is.
   */
  filter: brightness(0) invert(1);
}

.why__item-title {
  margin-bottom: var(--space-4);
  color: var(--color-accent);
  font-size: var(--fs-h4);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
}

.why__item-body {
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

/* ---------------------------------------------------------------
 * Page header
 *
 * The charcoal band that names an archive or an inner page. No design for
 * this exists yet, so it is deliberately plain: brand colour, brand type,
 * and the same container as everything else. It is easy to replace and it
 * commits to nothing that would have to be undone.
 * --------------------------------------------------------------- */

.page-header {
  padding-block: var(--space-9) var(--space-8);
  background: var(--color-bg-dark);
  color: var(--color-text-invert);
}

.page-header__title {
  font-size: var(--fs-h2-lg);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caps-tight);
  text-transform: uppercase;
}

.page-header__intro {
  max-width: 52ch;
  margin-top: var(--space-4);
  font-size: var(--fs-body-lg);
  line-height: var(--lh-body);
}

/* ---------------------------------------------------------------
 * Pagination
 * --------------------------------------------------------------- */

.pagination {
  margin-top: var(--space-9);
}

.pagination .nav-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
}

.pagination .page-numbers {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.75rem;
  min-height: 2.75rem;
  padding: 0 var(--space-3);
  border: var(--border-w) solid var(--color-rule);
  font-size: var(--fs-label);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-caps-tight);
  text-decoration: none;
}

.pagination .page-numbers:hover,
.pagination .page-numbers:focus-visible {
  border-color: var(--color-accent);
  color: var(--color-accent);
}

.pagination .page-numbers.current {
  background: var(--color-accent);
  border-color: var(--color-accent);
  /* Charcoal on orange measures 5.85:1; white would be 3.37:1 and fail. */
  color: var(--sgh-charcoal);
}

.pagination .page-numbers.dots {
  border-color: transparent;
}

/* ---------------------------------------------------------------
 * Brand patterns
 *
 * The guidelines give two: topographic contours taken from overhead views of
 * golf courses, and a dot grid. Contours are for "adding subtle texture and
 * elevating plain backgrounds", which is exactly what a flat charcoal band is.
 *
 * The supplied contour file is a raster inside an SVG wrapper, so the raster
 * itself is used and recoloured to pure white; the weight of it is controlled
 * by opacity here rather than baked into the asset.
 * --------------------------------------------------------------- */

.has-contours {
  position: relative;
  isolation: isolate;
}

.has-contours::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  background: url("../img/sgh-contours.png") no-repeat left top / auto 130%;
  /*
   * Measured, not chosen by eye. At 0.18 the pattern lifted the "why choose"
   * band enough to drop its orange column headings from 5.75:1 to 3.75:1
   * against a 4.5 requirement. White lines on a dark band are not free.
   */
  opacity: 0.1;
  pointer-events: none;
}

/* Mirrored, so two stacked dark bands do not repeat the same shape. */
.has-contours--right::before {
  background-position: right top;
  transform: scaleX(-1);
}

.has-contours--soft::before {
  opacity: 0.07;
}

/*
 * Content sits above the pattern. On a section that also carries a photograph
 * the order is: image, scrim, contours, content.
 *
 * The backdrop is excluded deliberately. It has to stay at the bottom of the
 * stack; lifting it with everything else would put the photograph over its own
 * scrim and over the pattern, which is the whole band inverted.
 */
.has-contours > *:not(.backdrop) {
  position: relative;
  z-index: 3;
}

@media print {
  .has-contours::before {
    display: none;
  }
}

/* ---------------------------------------------------------------
 * Navigation dropdowns
 *
 * Opened by hover and by focus-within, so tabbing through the header reveals
 * them exactly as pointing at them does. No JavaScript: a menu that only works
 * once a script has loaded is a menu that sometimes does not work.
 * --------------------------------------------------------------- */

.primary-nav__list > li {
  position: relative;
}

.primary-nav__list .sub-menu {
  position: absolute;
  top: 100%;
  left: 50%;
  z-index: 1;
  min-width: 15rem;
  margin: 0;
  padding: var(--space-3) 0;
  list-style: none;
  background: var(--color-bg-dark);
  border-top: var(--border-w) solid var(--color-accent);
  /*
   * Hidden with visibility rather than display so the open and close can be
   * eased, and so it stays out of the tab order while closed.
   */
  opacity: 0;
  visibility: hidden;
  transform: translate(-50%, 0.5rem);
  transition: opacity var(--dur) var(--ease),
              transform var(--dur) var(--ease),
              visibility var(--dur);
}

.primary-nav__list > li:hover > .sub-menu,
.primary-nav__list > li:focus-within > .sub-menu {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0);
}

/*
 * A gap between the trigger and the panel would close the menu as the pointer
 * crossed it. This bridges it without moving anything.
 */
.primary-nav__list > li:has(.sub-menu)::after {
  content: "";
  position: absolute;
  top: 100%;
  left: 0;
  width: 100%;
  height: var(--space-5);
}

.primary-nav__list .sub-menu a {
  display: block;
  padding: var(--space-3) var(--space-5);
  font-size: var(--fs-nav);
  font-weight: var(--fw-regular);
  letter-spacing: var(--ls-caps-tight);
  text-transform: none;
  white-space: nowrap;
}

.primary-nav__list .sub-menu a:hover,
.primary-nav__list .sub-menu .current-menu-item > a {
  background: rgba(255, 255, 255, 0.06);
  color: var(--color-accent);
}

/* Below the breakpoint the nav is a full panel, so the children simply sit
 * under their parent rather than hanging off it. */
@media (max-width: 1400px) {
  .primary-nav__list .sub-menu {
    position: static;
    min-width: 0;
    padding: var(--space-2) 0 var(--space-4);
    background: none;
    border-top: 0;
    opacity: 1;
    visibility: visible;
    transform: none;
  }

  .primary-nav__list .sub-menu a {
    padding: var(--space-2);
    font-size: var(--fs-body);
    color: var(--sgh-stone);
  }

  .primary-nav__list > li:has(.sub-menu)::after {
    display: none;
  }
}

/* ---------------------------------------------------------------
 * Video
 * --------------------------------------------------------------- */

.video-section {
  background: var(--color-bg-dark);
  color: var(--color-text-invert);
}

.video-section__heading {
  margin-bottom: var(--space-7);
  font-size: var(--fs-h2-md);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caps-tight);
  text-transform: uppercase;
}

/*
 * aspect-ratio rather than the old padding-top trick, and the iframe simply
 * fills it. Nothing here depends on knowing the video's dimensions.
 */
.video-section__frame {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--sgh-charcoal-light);
}

.video-section__frame iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* ---------------------------------------------------------------
 * Reveal on scroll
 *
 * Every rule here is behind `.js-motion`, which reveal.js adds to <html>.
 * Nothing is hidden by stylesheet alone, so a visitor with JavaScript off, a
 * crawler, or a failed script request all get the full page. Hiding content in
 * CSS and revealing it with script is how one broken request becomes a blank
 * site.
 *
 * reveal.js also stands down for `prefers-reduced-motion: reduce` and for
 * `?sgh-no-motion=1`, which the verification harness uses: transitions never
 * settle under a virtual time budget and every band screenshots blank.
 * --------------------------------------------------------------- */

.js-motion .will-reveal {
  opacity: 0;
  transform: translateY(1.75rem);
}

.js-motion .will-reveal.is-revealed {
  opacity: 1;
  transform: none;
  /*
   * Deliberately slow, and eased so almost all the movement happens early and
   * it drifts the last few pixels into place.
   *
   * A slow reveal only works if it starts early. reveal.js triggers a section
   * before it reaches the viewport for exactly this reason: at this duration,
   * waiting until a band is on screen would leave it still fading while it is
   * being read, which reads as a slow site rather than a considered one.
   *
   * Opacity and transform only: both are composited, so a band with a
   * photograph behind it does not repaint on every frame.
   */
  transition: opacity 1.4s cubic-bezier(0.16, 0.84, 0.44, 1),
              transform 1.4s cubic-bezier(0.16, 0.84, 0.44, 1);
}

@media (prefers-reduced-motion: reduce) {
  .js-motion .will-reveal,
  .js-motion .will-reveal.is-revealed {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/*
 * Printing does not scroll, so nothing would ever intersect and a printed page
 * would come out with the bands below the fold missing. Same reason the
 * harness opts out.
 */
@media print {
  .js-motion .will-reveal {
    opacity: 1;
    transform: none;
  }
}

/* ---------------------------------------------------------------
 * Lenis smooth scrolling
 *
 * Lenis adds these classes to <html> itself. `scroll-behavior: auto` is the
 * important one: native smooth scrolling and Lenis both try to animate the
 * same jump and the result stutters.
 * --------------------------------------------------------------- */

html.lenis,
html.lenis body {
  height: auto;
}

/*
 * Keyed to `.lenis` rather than `.lenis-smooth`, which Lenis only adds in some
 * states. Native smooth scrolling and Lenis both animating the same jump
 * stutters, so this has to be off whenever Lenis is running at all.
 */
html.lenis,
.lenis.lenis-smooth {
  scroll-behavior: auto !important;
}

/* Panels that scroll on their own, opted out with data-lenis-prevent. */
.lenis.lenis-smooth [data-lenis-prevent] {
  overscroll-behavior: contain;
}

.lenis.lenis-stopped {
  overflow: hidden;
}

/* ---------------------------------------------------------------
 * Custom cursor
 *
 * An orange ring with a dot, drawn as an SVG data URI and handed to the
 * `cursor` property rather than drawn as an element that chases the pointer.
 * A followed element is always a frame or two behind the real cursor, which is
 * the thing people notice and dislike; this one cannot lag because it is the
 * cursor.
 *
 * A dark halo sits under the orange so it stays legible on white, on the
 * charcoal bands and on the orange buttons, where the ring reads dark rather
 * than disappearing.
 *
 * Desktop only, gated on a device that has hover and a fine pointer. Touch
 * screens have no cursor to replace, and a phone reporting `pointer: coarse`
 * is exactly the case this must not apply to.
 * --------------------------------------------------------------- */

@media (hover: hover) and (pointer: fine) {
  body {
    cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'%3E %3Ccircle cx='16' cy='16' r='9' fill='none' stroke='%2307090B' stroke-opacity='.45' stroke-width='3.2'/%3E %3Ccircle cx='16' cy='16' r='9' fill='none' stroke='%23FF4A00' stroke-width='1.7'/%3E %3Ccircle cx='16' cy='16' r='3.1' fill='%2307090B' fill-opacity='.45'/%3E %3Ccircle cx='16' cy='16' r='2.1' fill='%23FF4A00'/%3E %3C/svg%3E") 16 16, auto;
  }

  /*
   * Interactive things get the larger ring, so the affordance the pointer
   * normally gives is not lost. The keyword after the comma is the fallback if
   * the image fails, and it keeps the correct semantics either way.
   */
  a,
  button,
  summary,
  label,
  [role="button"],
  [role="tab"],
  .btn,
  .faq__question {
    cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'%3E %3Ccircle cx='16' cy='16' r='12' fill='none' stroke='%2307090B' stroke-opacity='.45' stroke-width='3.2'/%3E %3Ccircle cx='16' cy='16' r='12' fill='none' stroke='%23FF4A00' stroke-width='1.7'/%3E %3Ccircle cx='16' cy='16' r='4' fill='%2307090B' fill-opacity='.45'/%3E %3Ccircle cx='16' cy='16' r='3' fill='%23FF4A00'/%3E %3C/svg%3E") 16 16, pointer;
  }

  /*
   * Text entry keeps the I-beam. Replacing it costs the reader the one cue
   * that says where typing will go, for no benefit.
   */
  input,
  textarea,
  select,
  [contenteditable="true"] {
    cursor: auto;
  }

  input[type="checkbox"],
  input[type="radio"],
  input[type="submit"],
  input[type="button"],
  select {
    cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'%3E %3Ccircle cx='16' cy='16' r='12' fill='none' stroke='%2307090B' stroke-opacity='.45' stroke-width='3.2'/%3E %3Ccircle cx='16' cy='16' r='12' fill='none' stroke='%23FF4A00' stroke-width='1.7'/%3E %3Ccircle cx='16' cy='16' r='4' fill='%2307090B' fill-opacity='.45'/%3E %3Ccircle cx='16' cy='16' r='3' fill='%23FF4A00'/%3E %3C/svg%3E") 16 16, pointer;
  }

  :disabled {
    cursor: not-allowed;
  }
}

/*
 * Testimonial band, lightened 10%.
 *
 * The obvious lever was the scrim, and it does nothing: at 0.22 opacity over a
 * photograph that is already close to black, taking 10% off the scrim moved
 * the band by 0.4 of 255. Measured, not assumed. What makes that section dark
 * is the picture, so that is what is lightened.
 *
 * 1.18 rather than 1.1, because the scrim composites on top of the brightened
 * image and is not itself affected: brightness(1.1) measured only +5.7% on the
 * finished band. This lands it at +10%.
 *
 * The scrim is left at its measured 0.22, which is what keeps this band a step
 * lighter than "why choose" beneath it and stops the last three bands reading
 * as one block.
 */
.testimonial .backdrop__img {
  filter: brightness(1.18);
}
