/* ==========================================================================
   Unrivaled Base — Foundation Stylesheet

   Scope: tokens, reset, font faces, type scale, chrome (header / nav / mobile
   menu / footer), and the shared primitives every block builds on.

   NOT in scope: block styling. Each block owns `inc/blocks/<name>/style.css`
   and that file is enqueued only when the block renders. A block is therefore
   a self-contained folder — render.php + block.php + style.css — which is what
   makes promoting one from a child theme to core a file move and nothing else.

   Cascade order is declared, never inferred: this file loads first, block
   stylesheets after it, both via wp_enqueue_style dependencies.
   ========================================================================== */

/* --- Reset --- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; }
body { min-height: 100vh; }
img, video { display: block; max-width: 100%; height: auto; }
a { color: inherit; text-decoration: none; }
button { cursor: pointer; font: inherit; border: none; background: none; }
ul, ol { list-style: none; }

/* --- Font Faces ---
   Commercial Type "Review" + "Neue Plak". Licence is Commercial Type — confirm
   it covers self-hosting on each new property domain before launch.
   `Neue Plak Text` is currently aliased to Neue Plak; the real Text optical cut
   is a separate face if the brand team has it. --- */
@font-face { font-family: "Review"; src: url("../fonts/review-bold-webfont.woff2") format("woff2"), url("../fonts/review-bold-webfont.woff") format("woff"); font-weight: 700; font-style: normal; font-display: swap; }
@font-face { font-family: "Review"; src: url("../fonts/review-heavy-webfont.woff2") format("woff2"), url("../fonts/review-heavy-webfont.woff") format("woff"); font-weight: 800; font-style: normal; font-display: swap; }
@font-face { font-family: "Review Poster"; src: url("../fonts/reviewposter-heavy-webfont.woff2") format("woff2"), url("../fonts/reviewposter-heavy-webfont.woff") format("woff"); font-weight: 800; font-style: normal; font-display: swap; }
@font-face { font-family: "Neue Plak"; src: url("../fonts/neue_plak_regular-webfont.woff2") format("woff2"), url("../fonts/neue_plak_regular-webfont.woff") format("woff"); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: "Neue Plak"; src: url("../fonts/neue_plak_bold-webfont.woff2") format("woff2"), url("../fonts/neue_plak_bold-webfont.woff") format("woff"); font-weight: 700; font-style: normal; font-display: swap; }

/* ==========================================================================
   DESIGN TOKENS

   Everything below is a default. Property Settings re-declares a small subset
   in a second `:root` block printed later in <head> (see inc/tokens.php), so
   a property overrides by *setting an option*, never by editing CSS.

   What a property may change:  the three sport-colour slots, the logo, the
   footer ground, and the fonts.
   What it may not:             navy, red, gold, neutrals, spacing, type scale.

   That split is the brand guardrail expressed structurally. "Reserve red for
   the logo" holds because red is not a slot a property can reach.
   ========================================================================== */
/* ---------------------------------------------------------------------------
   The `hidden` attribute has to win.

   The browser's own rule for it is `[hidden] { display: none }`, which carries
   the specificity of a bare attribute selector, so ANY class rule that sets a
   display beats it. The element keeps its hidden attribute, assistive tech and
   scripts treat it as hidden, and it stays on the screen.

   This had bitten twice before it was found, both times in a way that looked
   like a JavaScript fault rather than a CSS one:

     .pevents__empty    display:flex  ->  "No events match these filters"
                                          sat under a full grid of 19 events
     .carousel__controls display:flex ->  arrows showed on a carousel with
                                          nothing to scroll

   In both cases the script was correct and had set the attribute. Putting the
   rule here, once, means the next component to toggle `hidden` cannot inherit
   the same bug. !important because the whole point is to outrank a later,
   more specific class.
--------------------------------------------------------------------------- */
[hidden] { display: none !important; }

:root {
  /* --- Locked Unrivaled palette — identical on every property --- */
  --color-navy: #1D2468;
  --color-red: #FF0000;
  --color-dark-red: #BB0101;
  --color-gold: #C1A556;
  --color-black: #000000;
  --color-white: #FFFFFF;
  --color-white-smoke: #F2F2F2;

  --gray-50:  #fafafa;
  --gray-100: #f4f4f4;
  --gray-200: #ededed;
  --gray-300: #d4d4d4;
  --gray-400: #aaaaaa;
  --gray-500: #777777;
  --gray-600: #555555;

  /* --- SPORT COLOUR SLOTS — the property's own 2–3 colours ---
     Defaults are locked-palette values, so a theme installed and never
     configured is monochrome and legible rather than broken or half-branded.
     Baseball would set sport-1 #49D9FF / sport-2 #0064FF.
     Flag sets sport-1 #3FE8A8 / sport-2 #0D8A72 / sport-3 #C9C9C9. */
  --color-sport-1: var(--color-gold);
  --color-sport-2: var(--color-navy);
  --color-sport-3: var(--gray-400);

  /* --- Accent roles ---
     Components reference the ROLE, never the slot, so a property that supplies
     one colour instead of three still renders correctly.
       --accent       bright/decorative; assume it sits on a dark ground
       --accent-deep  must stay legible as text on white
       --accent-muted supporting neutral */
  --accent: var(--color-sport-1);
  --accent-deep: var(--color-sport-2);
  --accent-muted: var(--color-sport-3);

  /* --- Decorative accent ---------------------------------------------
     Where the accent is ORNAMENT rather than an action: eyebrows, hairlines,
     dots, bars. Split out from --accent so a property can quiet its ornament
     without also draining the colour out of its buttons, which is the one
     place the accent is doing a job.

     Two of them because a single value cannot serve both grounds: navy
     ornament disappears on a navy section, and a light one disappears on
     cream. `-on-dark` is the same role inside .tone--navy, a hero, or any
     other dark panel.

     Both default to --accent, so a theme that never sets them renders exactly
     as it did before they existed. */
  --accent-decor: var(--accent);
  --accent-decor-on-dark: var(--accent);

  /* --- Button roles on a dark ground -----------------------------------
     A filled button inverts on hover, and the inversion was hard-coded to
     navy. On a navy section that turns the button INTO the background: it
     does not darken, it disappears. The outline variant was worse — navy
     text inside a navy rule is invisible before you even hover it.

     So the inverted pair and the rule colour are roles, flipped once per
     dark container below. On light ground these resolve to exactly what was
     hard-coded before, so nothing that works today changes. */
  /* --- Status badge --------------------------------------------------
     A filled chip over photography: it needs a fill AND an ink that cannot
     resolve to the same colour. It was pointed at --accent-decor, which is
     correct for ornament and wrong for this — on a property whose decorative
     accent is navy the badge became navy text on a navy fill. Defaults keep
     the look every property has today. */
  --badge-bg: var(--accent);
  --badge-fg: var(--color-navy);

  --btn-invert-bg: var(--color-navy);
  --btn-invert-fg: var(--color-white);
  --btn-line:      var(--color-navy);
  --btn-line-fg:   var(--color-navy);

  /* --- Accent slots for numbered card sets ---
     Baseball colour-codes four pillars; Flag retired per-pillar colour and
     points all five at one accent. Both are expressible here, so a property
     with no pillar system needs no CSS change — just leave these alone. */
  --pillar-1: var(--accent-decor);
  --pillar-2: var(--accent-decor);
  --pillar-3: var(--accent-decor);
  --pillar-4: var(--accent-decor);
  --pillar-5: var(--accent-decor);

  /* --- Semantic text + rule roles ---
     The mechanism behind "inherit colour, never set it". A block that needs
     de-emphasised text uses var(--text-muted) rather than var(--gray-600);
     the tone modifier then re-points the token once instead of correcting
     every block by name. This is what keeps the tone block at the end of this
     file from growing a line per block, the way Flag's did. */
  --section-bg: var(--color-white);
  --text-muted: var(--gray-600);
  --text-subtle: var(--gray-500);
  --rule: var(--gray-200);

  /* --- Chrome roles ---
     Named so a property can restyle the footer ground from Property Settings
     without a chrome CSS override. Navy default is legible against any
     sport colour a property might pick. */
  --header-bg: var(--color-white);
  --header-fg: var(--color-navy);
  /* Header logo height. A token rather than a number in two rules, so a
     property that needs a different lockup can re-point it from its own
     stylesheet instead of overriding header CSS by selector.
     Raised from 44px to 53px (+20%) at Las Vegas's request; see Pastel #12,
     where the mark was reported as compressed and hard to read. */
  --header-logo-height: 53px;
  /* Derived, not measured: the logo is the tallest thing in the bar, so the
     height follows it plus the row's 14px padding and the hairline under it.
     Anything that has to clear the header (a sticky column, a scroll-margin)
     reads this, so a property that resizes its logo moves those with it. */
  --header-height: calc(var(--header-logo-height) + 29px);
  --footer-bg: var(--color-navy);
  --footer-fg: var(--color-white);

  /* --- Type families --- */
  --font-display: "Review", "Arial Black", sans-serif;
  --font-display-poster: "Review Poster", "Review", "Arial Black", sans-serif;
  --font-display-condensed: "Review Condensed", "Review", "Arial Black", sans-serif;
  --font-ui: "Neue Plak", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --font-body: "Neue Plak", "Helvetica Neue", Helvetica, Arial, sans-serif;

  --weight-regular: 400;
  --weight-medium: 500;
  --weight-semibold: 600;
  --weight-bold: 700;
  --weight-poster-heavy: 800;

  /* Neue Plak's em box is not symmetrical: measured at 1000px, it reports 1.154em
     of ascent against 0.241em of descent, while a capital reaches only 0.724em
     above the baseline and almost nothing below it. Centring the line box
     therefore centres mostly empty space, and an all-caps label in a fixed
     height pill lands about a fifth of an em LOW - 3.4px in a 48px button,
     which is what Pastel #134, #135 and #137 all report.

     The fix is to take that lean back off the bottom of the box: with
     align-items:center, extra bottom padding moves the label up by half of it.
     Expressed in em, so one value serves every size the label is set at, and
     measured rather than guessed - it is (ascent - descent) - (cap - descender
     ink), the exact amount the em box leans.

     Any component that centres a line of this font inside a box it does not
     own the height of needs this. Watch for it in a padding SHORTHAND: a later
     `padding: 0 26px` silently takes it off again. */
  --cap-shift: .207em;

  /* --- Type scale — canonical, not property-configurable --- */
  --fs-hero: 40px;
  --fs-display: 28px;
  --fs-h1: 26px;
  --fs-h2: 22px;
  --fs-section-headline: clamp(36px, 5vw, 56px);
  --fs-h3: 18px;
  --fs-body: 15px;
  --fs-body-sm: 13px;
  --fs-meta: 12px;
  --fs-eyebrow: 10px;

  /* --- Layout --- */
  --page-max-width: 1720px;
  --content-max-width: 1600px;
  --margin-desktop: 40px;
  --margin-mobile: 20px;

  --space-section-y-mobile: 56px;
  --space-section-y-desktop: 80px;
  --space-block-y: 48px;
  --space-card-pad: 24px;
  --space-card-gap: 14px;

  --radius-card: 8px;

  --transition-fast: .15s ease;
  --transition-base: .25s ease;
  --transition-slow: .4s ease;
  --ease-out: cubic-bezier(.25, .1, .25, 1);

  --focus-ring-width: 2px;
  --focus-ring-color: var(--accent-deep);
  --focus-ring-offset: 2px;

  /* --- Responsive aliases ---
     Declared once here so a block never restates a breakpoint. Sections read
     --margin and --space-section-y; the media query below is the only place
     the mobile values exist. */
  --margin: var(--margin-desktop);
  --space-section-y: var(--space-section-y-desktop);
}

@media (max-width: 767px) {
  :root {
    --margin: var(--margin-mobile);
    --space-section-y: var(--space-section-y-mobile);
  }
}

/* ==========================================================================
   ELEMENTS + TYPE
   ========================================================================== */
body {
  font-family: var(--font-body);
  font-size: var(--fs-body);
  font-weight: var(--weight-regular);
  line-height: 1.4;
  color: var(--color-black);
  background: var(--color-white);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

h1, h2 {
  font-family: var(--font-display-poster);
  text-transform: uppercase;
  font-weight: var(--weight-poster-heavy);
  line-height: .9;
  letter-spacing: -.02em;
}
h3, h4, h5, h6 {
  font-family: var(--font-display);
  text-transform: uppercase;
  font-weight: var(--weight-poster-heavy);
  line-height: 1.1;
}
h1 { font-size: var(--fs-hero); }
h2 { font-size: var(--fs-section-headline); }
h3 { font-size: var(--fs-display); }
h4 { font-size: var(--fs-h1); }
h5 { font-size: var(--fs-h2); }
h6 { font-size: var(--fs-h3); }

:where(a, button, [tabindex]):focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
}

/* Text utilities. None of them set a colour — they inherit, so the same class
   reads correctly on white, navy and accent grounds with no per-section
   override. That is why a `tone` switch can recolour a whole section from one
   class at the end of this file. */
.text-hero {
  font-family: var(--font-display-poster);
  font-weight: var(--weight-poster-heavy);
  font-size: var(--fs-hero);
  line-height: 1;
  letter-spacing: -.01em;
  text-transform: uppercase;
}
.text-large {
  font-family: var(--font-display);
  font-weight: var(--weight-bold);
  font-size: var(--fs-body);
  line-height: 1.5;
}
.text-eyebrow {
  font-family: var(--font-body);
  font-weight: var(--weight-bold);
  font-size: var(--fs-eyebrow);
  line-height: 1.3;
  letter-spacing: .12em;
  text-transform: uppercase;
}
.text-body    { font-family: var(--font-body); font-weight: var(--weight-regular); font-size: var(--fs-body); line-height: 1.5; }
.text-body-sm { font-family: var(--font-body); font-weight: var(--weight-regular); font-size: var(--fs-body-sm); line-height: 1.45; }
.text-meta    { font-family: var(--font-body); font-size: var(--fs-meta); }

.screen-reader-text {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* --- Layout --- */
.container {
  max-width: var(--content-max-width);
  margin: 0 auto;
  padding: 0 var(--margin);
}

/* ==========================================================================
   SHARED PRIMITIVES

   The vocabulary every block composes from. Deliberately neutral: nothing here
   names a block. A block's markup adds the primitive class alongside its own
   (`class="card xcard"`), so base owns the shared behaviour and the block
   stylesheet owns only what is genuinely its own.

   This is what keeps the tone modifier at the end of this file short. Flag's
   equivalent runs 70 lines because every block child hardcodes a light-ground
   colour and each one needs correcting by name.

   RULE FOR BLOCK CSS: inherit colour, never hardcode it. A block that sets
   `color: var(--color-navy)` on its own text breaks on every dark ground and
   buys itself a line in the tone block forever.
   ========================================================================== */

/* --- Section primitive ---
   A block sets its ground with `--section-bg`, never with `background`. That
   is what lets the tone modifier re-point one token instead of fighting each
   block's own background rule — see the tone block at the end of this file. */
.sec { background: var(--section-bg); }

.sec__inner {
  max-width: var(--content-max-width);
  margin: 0 auto;
  padding: var(--space-section-y) var(--margin);
}
.sec__eyebrow  { margin: 0 0 10px; color: var(--text-subtle); }
/* The standfirst under a section headline. Lives here rather than in each
   block so the four that gained one late match the ones that always had it. */
.sec__intro { color: var(--text-muted); max-width: 60ch; margin: 0 0 32px; }
.sec__headline {
  font-family: var(--font-display-condensed);
  font-weight: var(--weight-poster-heavy);
  text-transform: uppercase;
  line-height: .95;
  margin: 0 0 24px;
  font-size: var(--fs-section-headline);
  color: var(--color-navy);
  text-wrap: balance;
  letter-spacing: .01em;
}

/* --- Card primitive — ONE card, used everywhere ---
   Accent colour appears in small doses inside a card (meta line, badge, arrow)
   and never as the card ground. The solid-colour card was retired on Baseball
   in favour of the white card; it does not come forward. */
.card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--color-white);
  border: 1px solid var(--gray-200);
  border-radius: var(--radius-card);
  overflow: hidden;
  color: var(--color-navy);
  text-decoration: none;
  transition: transform var(--transition-fast), border-color var(--transition-fast);
}
/* Only linked cards lift — an unlinked card that moves on hover promises a
   click that never happens. */
a.card:hover { transform: translateY(-4px); border-color: var(--gray-300); }

.card__photo { background: var(--gray-200) center / cover no-repeat; aspect-ratio: 16 / 10; }
.card__body  { display: flex; flex-direction: column; flex: 1; gap: var(--space-card-gap); padding: var(--space-card-pad); }
.card__tag   { color: var(--text-subtle); }
.card__name  { font-family: var(--font-display); font-weight: var(--weight-poster-heavy); text-transform: uppercase; font-size: var(--fs-h3); line-height: 1.05; margin: 0; }
.card__meta  { color: var(--text-muted); font-size: var(--fs-body-sm); line-height: 1.5; margin: 0; }
.card__arrow { position: absolute; right: var(--space-card-pad); bottom: var(--space-card-pad); }

/* --- Card grid ---
   Defaults to 3-up. With exactly two cards a 3-column track leaves a dangling
   empty cell, so it becomes 2-up and the extra width buys larger type. Keyed
   off the card count with :has(), so an editor gets the right layout without
   choosing a variant. */
.grid--cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 20px;
}
/* A grid of one. auto-fit collapses the empty tracks, so a lone card stretches
   to the full measure and the grid reads as a list — which is exactly what it
   looked like on a schedule grouped by month with one event per month. Hold it
   at card width instead. Specificity (0,2,0) sits under the two-card rule
   below, and :only-child cannot be true when that one matches. */
.grid--cards:has(> :only-child) {
  grid-template-columns: minmax(0, 420px);
}

.grid--cards:has(> :last-child:nth-child(2)) {
  grid-template-columns: repeat(2, 1fr);
  gap: 24px;
  /* Uncapped, two cards in a 1600px container run ~790px wide and their 16:10
     photos ~490px tall, which swamps the page. */
  max-width: 1240px;
}
.grid--cards:has(> :last-child:nth-child(2)) .card__name { font-size: clamp(24px, 2.4vw, 34px); line-height: 1.05; }
.grid--cards:has(> :last-child:nth-child(2)) .card__meta { font-size: var(--fs-body); line-height: 1.55; }
.grid--cards:has(> :last-child:nth-child(2)) .card__body { padding: 28px 28px 56px; gap: 10px; }

@media (max-width: 767px) {
  .grid--cards,
  .grid--cards:has(> :last-child:nth-child(2)) { grid-template-columns: 1fr; }
}

/* --- Link + arrow primitives --- */
.us-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-ui);
  font-weight: var(--weight-bold);
  font-size: 14px;
  line-height: .85;
  letter-spacing: .84px;
  text-transform: uppercase;
  color: inherit;
  text-decoration: none;
  border: 0;
  padding: 0;
  transition: opacity var(--transition-fast);
}
.us-link:hover { opacity: .72; }
.us-link--inline { margin-top: 20px; align-self: flex-start; }
.us-link__arrow {
  width: 23px;
  aspect-ratio: 23 / 13;
  flex-shrink: 0;
  background: var(--accent-decor);
  clip-path: polygon(0 0, 100% 50%, 0 100%);
  transition: transform var(--transition-base);
}
.us-link:hover .us-link__arrow { transform: translate(3px); }

.brand-arrow {
  display: inline-block;
  width: 14px;
  aspect-ratio: 23 / 13;
  background: var(--accent-decor);
  clip-path: polygon(0 0, 100% 50%, 0 100%);
  flex-shrink: 0;
  vertical-align: middle;
}

/* --- Pillar dot — the numbered-set accent marker --- */
.pillar-dot {
  display: inline-block;
  width: 14px;
  aspect-ratio: 23 / 13;
  clip-path: polygon(0 0, 100% 50%, 0 100%);
  flex-shrink: 0;
  background: var(--pillar, var(--accent-decor));
}
.pillar-dot[data-pillar="1"] { --pillar: var(--pillar-1); }
.pillar-dot[data-pillar="2"] { --pillar: var(--pillar-2); }
.pillar-dot[data-pillar="3"] { --pillar: var(--pillar-3); }
.pillar-dot[data-pillar="4"] { --pillar: var(--pillar-4); }
.pillar-dot[data-pillar="5"] { --pillar: var(--pillar-5); }

/* --- News ticker ---
   A band pinned to the foot of a hero: fixed label, one scrolling line, fixed
   link. Shared by both heroes, so it lives here rather than in either one.

   The track holds the text twice and translates by half its width, which loops
   without a seam at any text length. Duration comes from the render as
   --ticker-duration so a long announcement does not race past. */
.ticker {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 0 var(--margin);
  min-height: 52px;
  background: #ffffff1a;
  -webkit-backdrop-filter: blur(6px);
          backdrop-filter: blur(6px);
  border-top: 1px solid #ffffff2e;
  color: var(--color-white);
}
.ticker__label { flex: 0 0 auto; color: var(--color-white); opacity: .85; }
.ticker__cta {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--color-white);
  white-space: nowrap;
  transition: gap var(--transition-fast);
}
.ticker__cta:hover { gap: 13px; }

.ticker__viewport { flex: 1 1 auto; overflow: hidden; min-width: 0; }
.ticker__track {
  display: flex;
  width: max-content;
  animation: ticker-scroll var(--ticker-duration, 30s) linear infinite;
}
.ticker__pass { display: flex; flex: 0 0 auto; }
.ticker:hover .ticker__track { animation-play-state: paused; }
.ticker__item {
  padding-right: 4rem;
  white-space: nowrap;
  font-size: var(--fs-body-sm);
  color: #ffffffe0;
}
/* Travels one pass, not half the belt. With two passes those are the same
   number, which is why 50% is the fallback: it is exactly what this did before
   and what it still does if ticker.js never runs. Once the script has measured
   a pass and repeated it enough to cover the bar, --ticker-distance carries the
   real width in px and half the belt would be the wrong distance. */
@keyframes ticker-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(calc(-1 * var(--ticker-distance, 50%))); }
}

/* No motion: the line sits still and scrolls by hand instead. The duplicate is
   hidden so the same sentence does not appear twice. */
@media (prefers-reduced-motion: reduce) {
  .ticker__track { animation: none; width: 100%; }
  .ticker__item[aria-hidden="true"] { display: none; }
  .ticker__viewport { overflow-x: auto; }
}

@media (max-width: 767px) {
  .ticker { flex-wrap: wrap; gap: 8px 14px; padding-top: 10px; padding-bottom: 12px; }
  .ticker__viewport { order: 3; flex-basis: 100%; }
}

/* --- Buttons ---
   ONE button language. Flag's rebuild consolidated two competing sets into
   this; do not add a third. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 44px;
  padding: 0 26px var(--cap-shift);
  border-radius: 999px;
  font-family: var(--font-ui);
  font-weight: var(--weight-bold);
  font-size: 13px;
  letter-spacing: .08em;
  text-transform: uppercase;
  transition: background var(--transition-fast), color var(--transition-fast), box-shadow var(--transition-fast);
}
.btn--primary       { background: var(--accent); color: var(--color-navy); }
.btn--primary:hover { background: var(--btn-invert-bg); color: var(--btn-invert-fg); }
.btn--accent        { background: var(--color-red); color: var(--color-white); }
.btn--accent:hover  { background: var(--color-dark-red); }
.btn--outline       { background: transparent; color: var(--btn-line-fg); box-shadow: inset 0 0 0 2px var(--btn-line); }
.btn--outline:hover { background: var(--btn-invert-bg); color: var(--btn-invert-fg); }
.btn--outline-light       { background: transparent; color: var(--color-white); box-shadow: inset 0 0 0 2px rgba(255,255,255,.7); }
.btn--outline-light:hover { background: var(--color-white); color: var(--color-navy); }

/* --- Progressive reveal ---
   The hidden state MUST be gated on .ub-js, set by an inline script in <head>
   before first paint. Without the gate, a JS failure leaves every section on
   the page permanently invisible. */
.ub-js [data-reveal] {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity .6s var(--ease-out), transform .6s var(--ease-out);
}
.ub-js [data-reveal].is-revealed { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .ub-js [data-reveal] { opacity: 1; transform: none; transition: none; }
  * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ==========================================================================
   CHROME — header / nav / mobile menu / footer

   Ported from Flag's authored chrome, with every property-specific colour
   replaced by a role token. Two properties of this chrome matter for the tool:

   1. Nav and footer columns come from WP menu locations, so a new property is
      editable from Appearance → Menus with no custom fields to configure.
   2. The logo is two <img> tags toggled by CSS off <body> data attributes — no
      scroll listener, no src swapping, correct on first paint.

   Logo selection:
     default                                    → dark lockup on the solid bar
     body[data-transparent-nav]                 → dark lockup over a light hero
     body[data-transparent-nav][data-hero=dark] → light lockup over a dark hero
   ========================================================================== */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--header-bg);
  border-bottom: 1px solid var(--gray-200);
}
.site-header__inner {
  max-width: var(--page-max-width);
  margin: 0 auto;
  padding: 14px var(--margin-mobile);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}
/* The two actions are one group, right-aligned together. As separate flex
   children of a space-between header they were pushed to opposite ends of the
   leftover room, which read as two unrelated things rather than a pair. */
.site-header__ctas { display: flex; align-items: center; gap: 12px; }

.site-header__logo { flex-shrink: 0; display: inline-flex; align-items: center; height: var(--header-logo-height); }
.site-header__logo-img { height: var(--header-logo-height); width: auto; display: block; }
/* No logo uploaded yet — the site title stands in, so a fresh install has a
   usable header instead of a broken image. */
.site-header__wordmark { color: var(--header-fg); text-transform: uppercase; letter-spacing: .04em; }
.site-header__logo-img--light { display: none; }

/* Transparent nav: header floats over the hero instead of sitting above it. */
body[data-transparent-nav] .site-header {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  background: transparent;
  border-bottom-color: transparent;
}
/* Over a dark hero the header keeps a hairline rule, as on Baseball, so the
   nav still reads as a bar rather than floating text on the photo. */
body[data-transparent-nav][data-hero="dark"] .site-header {
  border-bottom: 1px solid rgba(255, 255, 255, .15);
}

/* --- The pinned header.  Pastel #123, "back up scroll sticky nav". ----------

   position:absolute above takes the header out of flow so the hero runs under
   it, and the cost is that it scrolls away and never comes back: on a long
   page the only route to the nav was back to the top. Every page of both
   properties sets data-transparent-nav, so this was not one page misbehaving.

   The fix is the pattern the comment describes. Past the hero the header
   becomes a fixed, solid bar that hides on the way down and returns on the way
   up. Fixed rather than sticky deliberately — sticky would put the header back
   into flow and shove the whole page down by its height at the moment it
   engaged.

   Pinned means solid, so everything the transparent treatment changed has to
   change back: the dark-hero rules below swap the lockup and relight the nav
   text, and each carries the same two attributes as the rule it overrides plus
   .is-pinned, so it wins on specificity rather than on source order. */
body[data-transparent-nav] .site-header.is-pinned {
  position: fixed;
  background: var(--header-bg);
  border-bottom: 1px solid var(--gray-200);
  transform: translateY(-100%);
  transition: transform .28s ease, background-color .22s ease;
}
body[data-transparent-nav] .site-header.is-pinned.is-visible { transform: translateY(0); }

/* Someone who asked not to be moved gets the bar without the slide. */
@media (prefers-reduced-motion: reduce) {
  body[data-transparent-nav] .site-header.is-pinned { transition: none; }
}

body[data-transparent-nav][data-hero="dark"] .site-header.is-pinned {
  border-bottom: 1px solid var(--gray-200);
}
body[data-transparent-nav][data-hero="dark"] .site-header.is-pinned .site-header__logo-img--light { display: none; }
body[data-transparent-nav][data-hero="dark"] .site-header.is-pinned .site-header__logo-img--dark  { display: block; }
body[data-transparent-nav][data-hero="dark"] .site-header.is-pinned .site-header__wordmark { color: var(--header-fg); }
body[data-transparent-nav][data-hero="dark"] .site-header.is-pinned .nav-link,
body[data-transparent-nav][data-hero="dark"] .site-header.is-pinned .nav-cta { color: var(--header-fg); }
body[data-transparent-nav][data-hero="dark"] .site-header.is-pinned .nav-link:hover { color: var(--accent-deep); }
body[data-transparent-nav][data-hero="dark"] .site-header.is-pinned .site-header__burger span { background: var(--header-fg); }
body[data-transparent-nav] .site-header__logo-img--light { display: none; }
body[data-transparent-nav] .site-header__logo-img--dark { display: block; }
body[data-transparent-nav][data-hero="dark"] .site-header__logo-img--dark { display: none; }
body[data-transparent-nav][data-hero="dark"] .site-header__logo-img--light { display: block; }
/* The two <img> lockups swap above. The text fallback — what a property sees
   before it uploads a logo — needs the same treatment, or the site title sits
   navy-on-navy over a dark hero and reads as a rendering fault. */
body[data-transparent-nav][data-hero="dark"] .site-header__wordmark { color: var(--color-white); }
body[data-transparent-nav][data-hero="dark"] .nav-link,
body[data-transparent-nav][data-hero="dark"] .nav-cta { color: var(--color-white); }
body[data-transparent-nav][data-hero="dark"] .site-header__burger span { background: var(--color-white); }
/* Teal has too little contrast on a photo — use the brighter accent instead. */
body[data-transparent-nav][data-hero="dark"] .nav-link:hover { color: var(--accent); }
body[data-transparent-nav][data-hero="dark"] .nav-link.is-active { border-bottom-color: var(--accent); }

/* --- Mega panel open: the header joins the panel ---------------------------
   The mega drops out of the bottom of the header, so the two want to read as
   one surface. On a page with a solid bar they already do - --header-bg and the
   panel are both --color-white. The case that needs work is a transparent nav
   over a dark hero, where the chrome is dressed for a photograph: white logo,
   white nav, white burger, no ground. Drop a white panel under that and every
   one of those elements is white on white.

   So the whole dark-hero treatment above is undone for as long as the panel is
   open, and the header takes the panel's own colour.

   Driven by :has() rather than a class toggled in JS, because the panel itself
   opens on :hover / :focus-within - a JS flag would be a second source of truth
   for "is it open", free to disagree with the CSS that actually opens it. The
   :is() keeps the hover and keyboard cases in one selector instead of doubling
   every rule below. */
.site-header { transition: background-color .22s ease, border-color .22s ease; }

.site-header:has(.nav-dropdown--mega:is(:hover, :focus-within)) {
  background: var(--color-white);
  /* The bar and the panel are one surface; a rule between them cuts it in two. */
  border-bottom-color: transparent;
}

body[data-transparent-nav][data-hero="dark"] .site-header:has(.nav-dropdown--mega:is(:hover, :focus-within)) {
  background: var(--color-white);
  border-bottom-color: transparent;
}
/* The logo is two <img>s toggled by CSS, so the swap is the same mechanism the
   hero treatment uses - just driven by the panel instead of the hero. */
body[data-transparent-nav][data-hero="dark"] .site-header:has(.nav-dropdown--mega:is(:hover, :focus-within)) .site-header__logo-img--light { display: none; }
body[data-transparent-nav][data-hero="dark"] .site-header:has(.nav-dropdown--mega:is(:hover, :focus-within)) .site-header__logo-img--dark  { display: block; }
/* The text fallback, for a property that has not uploaded a logo yet. */
body[data-transparent-nav][data-hero="dark"] .site-header:has(.nav-dropdown--mega:is(:hover, :focus-within)) .site-header__wordmark { color: var(--header-fg); }

body[data-transparent-nav][data-hero="dark"] .site-header:has(.nav-dropdown--mega:is(:hover, :focus-within)) .nav-link { color: var(--header-fg); }
body[data-transparent-nav][data-hero="dark"] .site-header:has(.nav-dropdown--mega:is(:hover, :focus-within)) .nav-link:hover { color: var(--accent-deep); }
body[data-transparent-nav][data-hero="dark"] .site-header:has(.nav-dropdown--mega:is(:hover, :focus-within)) .nav-link.is-active { border-bottom-color: var(--accent-deep); }

body[data-transparent-nav][data-hero="dark"] .site-header:has(.nav-dropdown--mega:is(:hover, :focus-within)) .nav-cta--outline { color: var(--header-fg); }
body[data-transparent-nav][data-hero="dark"] .site-header:has(.nav-dropdown--mega:is(:hover, :focus-within)) .nav-cta--outline:hover { background: var(--header-fg); color: var(--header-bg); }
body[data-transparent-nav][data-hero="dark"] .site-header:has(.nav-dropdown--mega:is(:hover, :focus-within)) .nav-cta--button:hover { background: var(--color-navy); color: var(--color-white); }

body[data-transparent-nav][data-hero="dark"] .site-header:has(.nav-dropdown--mega:is(:hover, :focus-within)) .site-header__burger span { background: var(--color-navy); }

.site-header__nav { display: none; }
.site-header__menu { display: flex; gap: 32px; align-items: center; list-style: none; margin: 0; padding: 0; }
.site-header__menu > li { display: inline-flex; }

.nav-link {
  font-family: var(--font-body);
  /* Pastel #30: 12px is too small for a desktop nav. Sized here rather than by
     raising --fs-meta, which card meta, filter controls and timestamps all read
     - the nav being under-sized is not a reason to grow all of those. */
  font-size: 14px;
  font-weight: var(--weight-bold);
  /* Title Case, not caps — Pastel #18/#19. "EXPLORE THE BALLPARK" and "PLAN
     YOUR VISIT" are long enough that all-caps costs real legibility in a nav.
     The wide letter-spacing went with the caps; Title Case needs far less. */
  letter-spacing: .02em;
  color: var(--color-navy);
  padding: 4px 0;
  border-bottom: 2px solid transparent;
  transition: color var(--transition-fast), border-color var(--transition-fast);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.nav-link:hover { color: var(--accent-deep); }
.nav-link.is-active { border-bottom-color: var(--accent-deep); }
/* A heading parent — a section that is not itself a page — is a <button>. Strip
   what a browser gives a button so it cannot be told apart from the links beside
   it. .nav-link.is-active still outranks this, so the underline survives. */
button.nav-link {
  appearance: none;
  -webkit-appearance: none;
  background: none;
  margin: 0;
  border-width: 0 0 2px;
  border-style: solid;
  border-color: transparent;
  line-height: inherit;
}

.nav-dropdown { position: relative; }
.nav-dropdown:after { content: ""; position: absolute; top: 100%; left: -8px; width: 340px; height: 16px; }
.nav-dropdown__menu {
  display: none;
  position: absolute;
  top: calc(100% + 12px);
  left: 0;
  min-width: 320px;
  background: var(--color-white);
  border: 1px solid var(--gray-200);
  box-shadow: 0 8px 24px #00000014;
  padding: 8px 0;
  z-index: 10;
}
.nav-dropdown:hover .nav-dropdown__menu,
.nav-dropdown:focus-within .nav-dropdown__menu,
.nav-dropdown__menu:hover { display: block; }
.nav-dropdown__item {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 12px 20px;
  font-size: var(--fs-body-sm);
  color: var(--color-navy);
  transition: background var(--transition-fast), color var(--transition-fast);
}
.nav-dropdown__item:hover { background: var(--gray-50); color: var(--accent-deep); }
.nav-dropdown__item .pillar-dot { margin-top: 6px; }
.nav-dropdown__item-content { display: flex; flex-direction: column; gap: 2px; }
.nav-dropdown__item-name { font-weight: var(--weight-semibold); }
.nav-dropdown__item-meta {
  font-size: var(--fs-meta);
  color: var(--gray-500);
  font-weight: var(--weight-regular);
  letter-spacing: .02em;
}

.nav-cta {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: transparent;
  color: var(--color-navy);
  font-family: var(--font-ui);
  font-size: var(--fs-meta);
  font-weight: var(--weight-bold);
  letter-spacing: .08em;
  line-height: .85;
  text-transform: uppercase;
  text-decoration: none;
  transition: opacity var(--transition-fast);
}
.nav-cta:hover { background: transparent; opacity: .72; }

.site-header__burger {
  display: inline-flex;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 40px;
  height: 40px;
  padding: 9px;
  background: none;
  border: none;
  cursor: pointer;
  flex-shrink: 0;
}
.site-header__burger span { display: block; height: 2px; width: 100%; background: var(--color-navy); }

@media (min-width: 1024px) {
  .site-header__inner { padding: 16px var(--margin-desktop); }
  .site-header__nav { display: flex; align-items: center; gap: 32px; }
  .site-header__burger { display: none; }
}
@media (max-width: 1023px) {
  .site-header__inner {
    display: grid;
    grid-template-columns: auto 1fr;
    grid-template-rows: auto auto;
    align-items: start;
    column-gap: 16px;
    row-gap: 2px;
  }
  .site-header__logo { grid-row: 1 / 3; }
  .site-header__burger { grid-column: 2; grid-row: 1; justify-self: end; }
  /* Pastel #29: these moved into the mobile menu, where they can be drawn at
     full width. In the bar they sat on a second row, and because the header is
     absolutely positioned over the hero that row landed on the photograph. The
     markup stays where it is so desktop is untouched; it is simply not shown
     at this width. */
  .site-header__ctas { display: none; }
}

/* The two actions, inside the mobile menu. Full width and stacked: there is
   room here, so they are drawn as the primary actions they are rather than
   squeezed to 9px as they were in the bar. Pastel #145 put them AFTER the nav,
   under the last link. The nav already closes on 28px of padding, so these
   carry no top margin of their own.

   Pastel #158: the 4px that used to sit under them was set when a gold block
   followed, which drew its own boundary. #146 made that line plain white text,
   so the only thing separating a filled button from the line beneath it was
   those 4px, and the pair read as one object. */
.mobile-menu__actions {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 0 0 20px;
  flex-shrink: 0;
}
.mobile-menu__actions .nav-cta {
  justify-content: center;
  width: 100%;
  padding: 14px 20px;
}

/* --- Mobile Menu --- */
/* The closed overlay sits at translate(100%), one full screen to the right.
   Nothing used to clip it, and that is the horizontal scroll on mobile: an
   unclipped box past the right edge widens the document, and a widened
   document is pannable.

   It also explains why the open panel looked shifted with its left edge cut
   off. A `position: fixed` box sizes to the LAYOUT viewport, which on mobile
   grows to the document width once anything overflows — so the menu was
   filling a 546px box on a 375px screen, and the close button sat off screen
   until you panned sideways to reach it.

   So: clip the parked panel, and take it out of the page entirely when closed.
   visibility also drops its sixteen links out of the tab order and out of the
   accessibility tree, which matters because focusable elements must never sit
   inside an aria-hidden region. The delay holds the slide-out until the
   transform has finished; opening flips it immediately. */
.mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 200;
  pointer-events: none;
  overflow: hidden;
  visibility: hidden;
  transition: visibility 0s linear .4s;
}
.mobile-menu[data-open="true"] { pointer-events: auto; visibility: visible; transition-delay: 0s; }
@media (min-width: 1024px) { .mobile-menu { display: none; } }
.mobile-menu__overlay {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  background: var(--color-navy);
  color: var(--color-white);
  padding: 22px 24px 32px;
  overflow-y: auto;
  transform: translate(100%);
  transition: transform .4s cubic-bezier(.42, 0, .58, 1);
}
.mobile-menu[data-open="true"] .mobile-menu__overlay { transform: translate(0); }
.mobile-menu__header { display: flex; justify-content: space-between; align-items: center; flex-shrink: 0; }
.mobile-menu__logo img { height: 34px; width: auto; display: block; }
.mobile-menu__close {
  width: 44px; height: 44px; background: none; border: none;
  cursor: pointer; position: relative; flex-shrink: 0;
}
.mobile-menu__close:before, .mobile-menu__close:after {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: 28px; height: 2px; background: var(--color-white);
}
.mobile-menu__close:before { transform: translate(-50%, -50%) rotate(45deg); }
.mobile-menu__close:after  { transform: translate(-50%, -50%) rotate(-45deg); }
.mobile-menu__nav { flex: 1; display: flex; flex-direction: column; padding: 40px 0 28px; }
.mobile-menu__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.mobile-menu__item, .mobile-menu__group-trigger {
  display: block;
  padding: 22px 0;
  border-top: 1px solid rgba(255, 255, 255, .18);
  font-family: var(--font-display-poster);
  font-weight: var(--weight-poster-heavy);
  font-size: clamp(44px, 12.5vw, 72px);
  line-height: .95;
  letter-spacing: .01em;
  text-transform: uppercase;
  color: var(--color-white);
  text-decoration: none;
  transition: color .15s ease;
}
.mobile-menu__list > li:last-child .mobile-menu__item { border-bottom: 1px solid rgba(255, 255, 255, .18); }
.mobile-menu__item:hover, .mobile-menu__item:focus-visible,
.mobile-menu__group-trigger:hover, .mobile-menu__group-trigger:focus-visible { color: var(--accent); }
.mobile-menu__group-trigger {
  background: transparent; border-left: 0; border-right: 0; border-bottom: 0;
  width: 100%; text-align: left; cursor: pointer;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
.mobile-menu__chevron { flex-shrink: 0; transition: transform .25s ease; }
.mobile-menu__group[data-expanded="true"] .mobile-menu__chevron { transform: rotate(180deg); }
.mobile-menu__sublist { overflow: hidden; max-height: 0; opacity: 0; transition: max-height .35s ease, opacity .2s ease; }
.mobile-menu__group[data-expanded="true"] .mobile-menu__sublist { max-height: 480px; opacity: 1; }
.mobile-menu__subitem {
  display: flex; align-items: flex-start; gap: 14px;
  padding: 16px 0 16px 8px;
  border-top: 1px solid rgba(255, 255, 255, .08);
  color: var(--color-white); text-decoration: none;
  transition: color .15s ease, padding-left .15s ease;
}
.mobile-menu__subitem:first-child { border-top: 0; }
.mobile-menu__subitem:hover, .mobile-menu__subitem:focus-visible { color: var(--accent); padding-left: 14px; }
.mobile-menu__subitem .pillar-dot { margin-top: 14px; }
.mobile-menu__subitem-text { display: flex; flex-direction: column; gap: 2px; }
.mobile-menu__subitem-name {
  font-family: var(--font-display-poster);
  font-weight: var(--weight-poster-heavy);
  font-size: clamp(24px, 6.5vw, 36px);
  line-height: 1; letter-spacing: .01em; text-transform: uppercase;
}
.mobile-menu__subitem-meta {
  font-family: var(--font-body); font-weight: var(--weight-regular);
  font-size: 12px; letter-spacing: .1em; text-transform: uppercase; color: #ffffff8c;
}
.mobile-menu[data-open="true"] .mobile-menu__group-trigger,
.mobile-menu[data-open="true"] .mobile-menu__item { animation: mobile-menu-item-in .4s cubic-bezier(.25, .1, .25, 1) both; }
.mobile-menu[data-open="true"] .mobile-menu__group-trigger { animation-delay: .1s; }
.mobile-menu[data-open="true"] .mobile-menu__item:nth-child(2) { animation-delay: .15s; }
.mobile-menu[data-open="true"] .mobile-menu__item:nth-child(3) { animation-delay: .2s; }
.mobile-menu[data-open="true"] .mobile-menu__item:nth-child(4) { animation-delay: .25s; }
.mobile-menu[data-open="true"] .mobile-menu__item:nth-child(5) { animation-delay: .3s; }
@keyframes mobile-menu-item-in { 0% { opacity: 0; transform: translate(28px); } to { opacity: 1; transform: translate(0); } }
.mobile-menu__group[data-expanded="true"] .mobile-menu__subitem { animation: mobile-menu-subitem-in .35s cubic-bezier(.25, .1, .25, 1) both; }
.mobile-menu__group[data-expanded="true"] .mobile-menu__subitem:nth-child(1) { animation-delay: 80ms; }
.mobile-menu__group[data-expanded="true"] .mobile-menu__subitem:nth-child(2) { animation-delay: .13s; }
.mobile-menu__group[data-expanded="true"] .mobile-menu__subitem:nth-child(3) { animation-delay: .18s; }
.mobile-menu__group[data-expanded="true"] .mobile-menu__subitem:nth-child(4) { animation-delay: .23s; }
@keyframes mobile-menu-subitem-in { 0% { opacity: 0; transform: translate(20px); } to { opacity: 1; transform: translate(0); } }
.mobile-menu__footer { display: flex; justify-content: space-between; align-items: flex-end; gap: 24px; flex-shrink: 0; flex-wrap: wrap; }
.mobile-menu__cta { background: var(--accent); color: var(--color-navy); }
.mobile-menu__cta:hover { background: var(--color-white); color: var(--color-navy); }
.mobile-menu__contact { display: flex; flex-direction: column; gap: 4px; text-align: right; }
.mobile-menu__contact-label {
  margin: 0; font-family: var(--font-body); font-weight: var(--weight-bold);
  font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: #ffffff8c;
}
.mobile-menu__contact-email { font-family: var(--font-body); font-size: 14px; color: var(--color-white); text-decoration: none; }
.mobile-menu__contact-email:hover { color: var(--accent); }
body.menu-open { overflow: hidden; }

/* --- Site Footer --- */
.site-footer { background: var(--footer-bg); color: var(--footer-fg); width: 100%; }
.site-footer__inner {
  max-width: var(--content-max-width);
  margin: 0 auto;
  padding: 56px var(--margin-mobile) 32px;
  display: flex;
  flex-direction: column;
  gap: 48px;
}
.site-footer__brand { flex: 1; max-width: 320px; }
.site-footer__logo { display: inline-block; margin-bottom: 16px; }
.site-footer__logo-img { height: 84px; width: auto; display: block; }
.site-footer__tag { opacity: .6; max-width: 240px; }
/* The count comes from the markup, because it depends on what the property has:
   two menus, or two menus and a Connect block. auto-fit was tried first and
   left a collapsed empty track on the end, which still costs a 32px gap and
   pulled the columns off the right edge. */
.site-footer__columns { display: grid; grid-template-columns: repeat(var(--footer-cols, 2), minmax(0, 1fr)); gap: 32px; flex: 2; }
/* Three narrow columns on a phone is four words per line, so they pair up.
   Connect takes the full width underneath: in half a row the email address
   breaks mid-word ("info@unrivaledsportspa / rkvegas.com"), and an address
   that cannot be read in one piece is not much of a contact detail. */
@media (max-width: 639px) {
  .site-footer__columns { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 28px 24px; }
  .site-footer__col--connect { grid-column: 1 / -1; }
}
.site-footer__heading { opacity: .5; margin-bottom: 14px; color: inherit; }
.site-footer__list { display: flex; flex-direction: column; gap: 8px; }
.site-footer__link {
  font-family: var(--font-body);
  font-size: var(--fs-meta);
  opacity: .85;
  transition: opacity var(--transition-fast), color var(--transition-fast);
}
.site-footer__link:hover { opacity: 1; }
.site-footer__base p, .site-footer__base .text-meta { color: inherit; }
.site-footer__base {
  border-top: 1px solid rgba(29, 36, 104, .15);
  padding: 20px var(--margin-mobile);
  text-align: center;
  color: #1d246899;
  max-width: var(--content-max-width);
  margin: 0 auto;
}
.site-footer__legal { display: flex; flex-wrap: wrap; gap: 8px 22px; justify-content: center; margin-top: 12px; }
.site-footer__legal-link {
  color: rgba(29, 36, 104, .7);
  text-decoration: none;
  font-size: var(--fs-meta);
  transition: color var(--transition-fast);
}
.site-footer__legal-link:hover { color: var(--color-navy); }
@media (min-width: 768px) {
  .site-footer__base { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 22px; text-align: left; }
  .site-footer__base p { margin: 0; }
  .site-footer__legal { margin-top: 0; justify-content: flex-end; }
}
@media (min-width: 1024px) {
  .site-footer__inner { padding: 64px var(--margin-desktop) 32px; flex-direction: row; align-items: flex-start; gap: 64px; }
  .site-footer__base { padding: 20px var(--margin-desktop); }
}


/* ==========================================================================
   404
   ========================================================================== */
.four-oh-four { min-height: 60vh; display: grid; place-items: center; text-align: center; padding: var(--space-section-y) var(--margin); }
.four-oh-four__eyebrow { color: var(--accent-decor); margin-bottom: 12px; }
.four-oh-four__headline { color: var(--color-navy); margin-bottom: 16px; }
.four-oh-four__body { color: var(--gray-600); margin-bottom: 28px; max-width: 46ch; }

/* ==========================================================================
   SECTION TONE — must stay last

   The `tone` field on core section blocks emits .tone--navy. Placed last so it
   wins on equal specificity against a block's own background.

   This block is short *because* the primitives above are neutral. Flag's
   equivalent runs 70 lines: every block child there hardcodes a light-ground
   colour, so each one needs correcting by name. Every line you are tempted to
   add here is really a block stylesheet that should have inherited its colour
   instead of setting one.
   ========================================================================== */
/* The doubled class is deliberate, not a typo. Block stylesheets load AFTER
   this file, so a single `.tone--navy` (0,1,0) would lose to a block's own
   `.wte` rule (also 0,1,0) on source order. Doubling it to (0,2,0) means a
   block can never accidentally out-rank the tone its editor selected — without
   !important, and without every block having to write its own
   `.block.tone--navy` override. */
/* gray-100, not gray-50. The .wte block hardcodes gray-50 as its own ground,
   so a tone that resolved to the same value put two identical bands against
   each other on the Las Vegas homepage - which is the fault this tone was
   introduced to fix, in a quieter colour. */
.tone--gray.tone--gray { --section-bg: var(--gray-100); }

.tone--navy.tone--navy {
  --section-bg: var(--color-navy);
  color: var(--color-white);

  /* Re-point the semantic roles. Every block that reads them is corrected by
     these three lines, which is the entire reason they exist. */
  --text-muted: #ffffffd1;
  --text-subtle: #ffffff8c;
  --rule: #ffffff2e;
}

/* Tone applies to any section element, whether or not it uses .sec. */
[class*="tone--"] { background: var(--section-bg); }

/* Section headlines drop their navy and inherit white; eyebrows take the
   accent. These two are the only by-name corrections in the file — everything
   else flows through the tokens above. */
.tone--navy .sec__headline { color: inherit; }
.tone--navy .sec__eyebrow  { color: var(--accent-decor-on-dark); }

/* Cards sit on the navy as translucent panels rather than white ones. */
.tone--navy .card {
  background: #ffffff14;
  border-color: var(--rule);
  color: var(--color-white);
}
.tone--navy .card__photo { background-color: #ffffff1f; }

/* ==========================================================================
   EDITOR-ONLY

   A block with nothing in it renders nothing, which is correct on the front end
   and unusable in the editor — a freshly inserted block would be a zero-height
   element with no way to click back into it. The placeholder is emitted only
   when ACF reports it is rendering a preview.
   ========================================================================== */
.ub-block-placeholder {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 28px var(--space-card-pad);
  border: 1px dashed var(--gray-300);
  border-radius: var(--radius-card);
  background: var(--gray-50);
  text-align: center;
  color: var(--gray-600);
}
.ub-block-placeholder__title {
  font-family: var(--font-display);
  font-weight: var(--weight-poster-heavy);
  text-transform: uppercase;
  font-size: var(--fs-h3);
  color: var(--color-navy);
}
.ub-block-placeholder__hint { font-size: var(--fs-body-sm); }
/* A section the editor has hidden. Distinct from an empty one, because the two
   need opposite responses: fill this one in, or switch it back on. Struck
   through rather than merely greyed, so the state reads at a glance down a long
   page of blocks. */
.ub-block-placeholder--hidden {
  border-style: solid;
  border-color: var(--gray-200);
  background: repeating-linear-gradient(
    135deg,
    var(--gray-50) 0 10px,
    transparent 10px 20px
  );
}
.ub-block-placeholder--hidden .ub-block-placeholder__title {
  color: var(--gray-500);
  text-decoration: line-through;
}

/* The header link, when a property has given it a job to do. */
.nav-cta--button {
  /* Height-neutral: the lean comes off the top and goes on the bottom, so
     the chip stays the size the header row was built around. */
  padding: calc(9px - var(--cap-shift) / 2) 18px calc(9px + var(--cap-shift) / 2);
  border-radius: 999px;
  background: var(--accent);
  color: var(--color-navy);
  transition: background var(--transition-fast), color var(--transition-fast);
}
.nav-cta--button:hover { background: var(--color-navy); color: var(--color-white); opacity: 1; }
/* Over a dark hero the header has no ground of its own, so the navy inversion
   above would dissolve the button into the photo. Mirrors the rule the outline
   CTA already carries for this case. */
body[data-transparent-nav][data-hero="dark"] .nav-cta--button:hover { background: var(--color-white); color: var(--color-navy); }
body[data-transparent-nav][data-hero="dark"] .nav-cta--button { color: var(--color-navy); }

/* --- Section layout: heading beside the cards ---
   The default is stacked. This variant puts the heading and intro in a column
   on the left and the cards to the right, which is what a narrative section
   wants when the copy is doing as much work as the cards.

   The heading is one grid cell (.sec__head) rather than three loose children.
   That matters: with the eyebrow, headline and intro each in their own row, a
   card grid spanning those rows inflates the first one to its own height and
   the headline drifts down the section. One cell each side, both starting in
   row 1, and the two columns simply align at the top.

   The doubled class is deliberate, exactly as in the tone block below. Block
   stylesheets load after this file and most card sections set their own
   `.wte .sec__inner { display: flex }` — same specificity, later in the
   cascade, so a single `.sec--aside` would lose and the option would silently
   do nothing. This is the second time that trap has come up; if a third
   modifier needs it, the section blocks should stop styling .sec__inner at all
   and let this file own it. */
.sec--aside.sec--aside .sec__inner {
  display: grid;
  grid-template-columns: minmax(260px, 5fr) 8fr;
  gap: clamp(28px, 4vw, 56px) clamp(32px, 5vw, 72px);
  align-items: start;
}
.sec--aside.sec--aside .sec__head {
  grid-column: 1;
  grid-row: 1;
  align-self: start;
}
.sec--aside.sec--aside .sec__headline { margin-bottom: 0; }
.sec--aside.sec--aside .sec__head > * + * { margin-top: 16px; }

.sec--aside.sec--aside .wte__grid,
.sec--aside.sec--aside .portfolio__grid,
.sec--aside.sec--aside .regions__grid,
.sec--aside.sec--aside .xsell__grid {
  grid-column: 2;
  grid-row: 1;
  min-width: 0;   /* grid items default to min-width:auto and would overflow */
}

/* Anything after the grid — a "see all" link — sits under the cards. */
.sec--aside.sec--aside .us-link--inline { grid-column: 2; margin-top: 0; }

/* Beside a heading the cards have less room, so the two-up rule that assumes a
   full-width row would leave them oversized. */
.sec--aside.sec--aside .grid--cards { grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); max-width: none; }

@media (max-width: 899px) {
  .sec--aside.sec--aside .sec__inner { grid-template-columns: 1fr; }
  .sec--aside.sec--aside .sec__head,
  .sec--aside.sec--aside .wte__grid,
  .sec--aside.sec--aside .portfolio__grid,
  .sec--aside.sec--aside .regions__grid,
  .sec--aside.sec--aside .xsell__grid,
  .sec--aside.sec--aside .us-link--inline { grid-column: 1; grid-row: auto; }
}

/* Homepage hero sub copy, matching the interior hero's. */
/* Pastel #38: 85% white over a photograph, which is where most of the
   sub-copy's contrast was going. Full strength; the reshaped scrim in
   inc/blocks/hero-home/style.css does the rest. Matches .hero__sub, which
   was taken to full for the same reason in #32 and #33. */
.hero-home__sub { color: var(--color-white); max-width: 52ch; margin: 0; font-size: clamp(16px, 1.5vw, 20px); line-height: 1.45; }

/* --- Header: the secondary action -------------------------------------------
   An outline against the solid primary. Two solid buttons side by side give a
   visitor no steer about which one the site wants them to take. */
.nav-cta--outline {
  padding: 9px 18px;
  border-radius: 999px;
  border: 1px solid currentColor;
  color: var(--header-fg);
  transition: background var(--transition-fast), color var(--transition-fast), opacity var(--transition-fast);
}
.nav-cta--outline:hover { background: var(--header-fg); color: var(--header-bg); opacity: 1; }
body[data-transparent-nav][data-hero="dark"] .nav-cta--outline { color: var(--color-white); }
body[data-transparent-nav][data-hero="dark"] .nav-cta--outline:hover { background: var(--color-white); color: var(--color-navy); }

/* --- Footer: social and the endorsement --- */
/* Pastel #156: the mark used to sit on its own under the logo, where Zach's
   note was that it "feels like it's just floating and random" - which it did,
   because an icon with no heading and nothing beside it is decoration. It now
   lives in a Connect column alongside Explore and Company, where a reader
   already looks for how to get in touch, with the address next to it. */
.site-footer__connect { display: flex; flex-direction: column; gap: 10px; }
.site-footer__connect-link {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-body);
  font-size: var(--fs-meta);
  opacity: .85;
  line-height: 1.3;
  transition: opacity var(--transition-fast);
  /* The row is the target, so it stays a comfortable height without the icon
     needing a 44px box of its own as it did when it stood alone. */
  min-height: 30px;
}
.site-footer__connect-link:hover { opacity: 1; text-decoration: underline; }
.site-footer__connect-link .social-icon { flex: 0 0 auto; opacity: .75; }
.site-footer__connect-link:hover .social-icon { opacity: 1; }
/* The address is the longest thing in the column and must not force it wider. */
.site-footer__connect-text { min-width: 0; overflow-wrap: anywhere; }

.site-footer__social {
  list-style: none;
  margin: 16px 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}
.site-footer__social-link {
  color: var(--footer-fg);
  font-size: var(--fs-meta);
  text-decoration: none;
  opacity: .78;
  transition: opacity var(--transition-fast);
}
.site-footer__social-link:hover { opacity: 1; text-decoration: underline; }
/* As a mark rather than a word. A 44px target around a 22px glyph, because the
   glyph itself is well under the minimum touch size, with the negative margin
   taking the extra back off the layout so the footer row does not grow. */
.site-footer__social-link--icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin: -11px;
}
.site-footer__social-link--icon:hover { text-decoration: none; }
.site-footer__social-link--icon:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring-color);
  outline-offset: 2px;
  border-radius: 50%;
}

.site-footer__endorsement {
  display: inline-block;
  margin-top: 20px;
  color: var(--footer-fg);
  font-size: var(--fs-meta);
  letter-spacing: .08em;
  text-transform: uppercase;
  text-decoration: none;
  opacity: .62;
  transition: opacity var(--transition-fast);
}
.site-footer__endorsement:hover { opacity: 1; }

/* ---------------------------------------------------------------- super nav */
/* The full-width panel, ported from Cooperstown. Proportions are measured off
   the live one — 64x4 accent rule, two columns at 48px apart, rows 24px apart,
   12px on the panel's bottom corners — but every colour and face is a role
   token here, so each property brings its own.

   `.nav-dropdown` is relative, which would make it the panel's containing block
   and trap a full-width panel inside one nav item. Going static hands that job
   back to `.site-header`, which is sticky and therefore positioned, and spans
   the viewport. */
/* Dark containers flip the decorative accent to its on-dark value. Doing it
   once, on the token, is why no block has to know which ground it is on — a
   section's tone is set per instance, so the block could not know anyway. */
.tone--navy,
.hero,
.hero-home,
.nextup,
.psho,
.ngallery,
.statement,
.mobile-menu,
.site-footer {
  --accent-decor: var(--accent-decor-on-dark);

  /* Light fill, navy text — the readable inversion on a dark ground, and
     the same treatment .btn--outline-light has always applied by hand. */
  --btn-invert-bg: var(--color-white);
  --btn-invert-fg: var(--color-navy);
  --btn-line:      #ffffffb3;
  --btn-line-fg:   var(--color-white);
}
/* NOT .site-header. The header carries no ornament of its own — its active
   underline and CTA are both on --accent — and the super nav panel is a DOM
   child of it. Flipping the token on the header handed the panel the on-dark
   value, and a cream rule on a cream panel is an invisible rule. */

.nav-dropdown--mega { position: static; }

.nav-mega {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 10;
  background: var(--color-white);
  border-bottom-left-radius: 12px;
  border-bottom-right-radius: 12px;
  box-shadow: 0 20px 25px -5px #0000001a, 0 8px 10px -6px #0000001a;

  /* A curtain, not a fade: it comes down from behind the header. display:none
     cannot be transitioned, so visibility carries the hiding and keeps the
     panel out of the accessibility tree and out of the tab order while shut. */
  visibility: hidden;
  opacity: 0;
  transform: translateY(-12px);
  transition: opacity .22s ease, transform .28s cubic-bezier(.4, 0, .2, 1), visibility 0s .28s;
}
.nav-dropdown--mega:hover .nav-mega,
.nav-dropdown--mega:focus-within .nav-mega {
  visibility: visible;
  opacity: 1;
  transform: translateY(0);
  transition: opacity .22s ease, transform .28s cubic-bezier(.4, 0, .2, 1), visibility 0s;
}

.nav-mega__inner {
  max-width: var(--page-max-width);
  margin: 0 auto;
  padding: 40px var(--margin-desktop) 44px;
  display: grid;
  grid-template-columns: 1fr 1px 1fr;
  gap: 0 40px;
  align-items: start;
}
/* Both halves are placed explicitly. The divider below is a ::before, which is
   the FIRST grid item in order, so leaving the halves to auto-placement walks
   them onto the wrong rows. */
.nav-mega__feature { grid-column: 1; }
.nav-mega__links   { grid-column: 3; }

/* Left: the featured card. */
.nav-mega__feature { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; align-items: center; }
.nav-mega__photo {
  display: block;
  aspect-ratio: 4 / 3;
  border-radius: var(--radius-card);
  background: var(--gray-100) center / cover no-repeat;
}
.nav-mega__feature-body { display: flex; flex-direction: column; align-items: flex-start; }
.nav-mega__feature-heading {
  margin: 0;
  font-family: var(--font-display-condensed);
  font-size: clamp(20px, 1.6vw, 24px);
  line-height: 1.1;
  color: var(--color-navy);
  text-wrap: balance;
}
.nav-mega__rule { display: block; width: 64px; height: 4px; margin: 14px 0 18px; background: var(--accent-decor); }
.nav-mega__feature-text { margin: 0 0 16px; font-size: var(--fs-body-sm); line-height: 1.5; color: var(--text-muted); }
.nav-mega__cta { display: inline-flex; align-items: center; gap: 7px; color: var(--color-navy); }
.nav-mega__cta:hover { color: var(--accent-deep); }

/* The divider is a grid track rather than a border, so it stretches to the
   taller of the two columns without either one owning it. */
/* --gray-300, not 200. The panel sits on --color-white, which on a warm brand
   is a cream rather than #fff, and at 200 a one-pixel rule over the full height
   of the panel disappears into it. The link rules below are short and stay at
   200, which is where Cooperstown has them. */
.nav-mega__inner::before { content: ""; grid-column: 2; align-self: stretch; background: var(--gray-300); }

/* Right: the links. */
.nav-mega__links-heading {
  margin: 0 0 20px;
  font-family: var(--font-display-condensed);
  font-size: clamp(20px, 1.6vw, 24px);
  line-height: 1.1;
  color: var(--color-navy);
}
.nav-mega__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 24px 48px; }
.nav-mega__link {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--gray-200);
  color: var(--color-navy);
  transition: color var(--transition-fast), border-color var(--transition-fast);
}
.nav-mega__link:hover { color: var(--accent-deep); border-bottom-color: var(--accent); }
.nav-mega__link-name { font-weight: var(--weight-semibold); font-size: var(--fs-body-sm); }
.nav-mega__link-meta { font-size: var(--fs-meta); color: var(--text-muted); letter-spacing: .02em; line-height: 1.35; }

/* Between the nav appearing and the panel having room for two columns beside a
   picture, the panel is just a list. The featured card is the part that needs
   the width, so it is the part that goes. */
@media (max-width: 1100px) {
  .nav-mega__inner { grid-template-columns: 1fr; padding: 28px var(--margin-desktop) 32px; }
  .nav-mega__inner::before { display: none; }
  .nav-mega__feature { display: none; }
  /* Column 3 no longer exists at this width; left set, it would have the
     browser invent two implicit columns to reach it. */
  .nav-mega__links { grid-column: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .nav-mega { transition: none; transform: none; }
  .nav-dropdown--mega:hover .nav-mega,
  .nav-dropdown--mega:focus-within .nav-mega { transition: none; transform: none; }
}

/* ---------------------------------------------------------------------------
   Privacy Policy acknowledgement modal. See inc/privacy-modal.php.

   Drawn with the theme's own tokens so each property renders it in its own
   brand. The corporate original hardcodes a blue button and Review type, which
   would be wrong on Rocker B.
--------------------------------------------------------------------------- */
.pmodal {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(0, 0, 0, .6);
}
/* The page behind must not scroll while this is up. Set on <html> rather than
   inline on <body> so nothing has to remember to put a style back. */
.pmodal-open, .pmodal-open body { overflow: hidden; }

.pmodal__panel {
  background: var(--color-white, #fff);
  color: var(--color-navy);
  border-radius: var(--radius-card, 12px);
  padding: 40px 36px 36px;
  max-width: 520px;
  width: 100%;
  text-align: center;
  box-shadow: 0 20px 60px rgba(0, 0, 0, .3);
}
.pmodal__text {
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: 1.6;
  color: inherit;
  margin: 0 0 28px;
}
.pmodal__link {
  color: var(--accent-deep, currentColor);
  font-weight: var(--weight-bold);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.pmodal__btn { border: 0; }

@media (max-width: 767px) {
  .pmodal__panel { padding: 32px 24px 28px; }
}

/* --- Age chips ---
   Pastel #78, #113, #130: "a more visually intuitive way to display the age
   brackets", asked four times. One chip per contiguous run of divisions, so
   the NUMBER of chips carries the structure: one means an unbroken span, two
   means there is a gap, and the gap is a real fact about who can register.

   Four pixel radius, deliberately not the 999px pill. The pill is doing action
   work on these cards already, and a label wearing the action shape gets
   clicked. This matches the status chip over the photo instead.

   The 8px horizontal gap is not a preference: inter-chip space has to beat the
   7px of padding inside a chip, or a row of them reads as one object. */
.ages { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; }
.agechip {
  display: inline-flex;
  align-items: center;
  height: 20px;
  padding: 0 7px;
  border-radius: 4px;
  background: var(--chip-bg, #f1f2f6);
  color: var(--chip-fg, var(--color-navy));
  font-family: var(--font-ui);
  font-weight: var(--weight-medium);
  font-size: 11px;
  letter-spacing: .02em;
  white-space: nowrap;
}
/* Dimensions and the like: a fact worth keeping, not an age. */
.ages__note { font-size: 10px; color: var(--text-muted); }

/* The degrade path. An unresolved string is shown exactly as typed - see
   unrivaled_base_event_ages_markup() for why guessing is the worse failure. */
.ages__raw { font-size: inherit; color: inherit; }
.ages__raw--long { font-size: var(--fs-body-sm); }

/* On navy the light chip ground would glare, so it inverts to a tint of the
   panel it sits on. */
.tone--navy .agechip { --chip-bg: #ffffff1f; --chip-fg: var(--color-white); }
.tone--navy .ages__note { color: var(--text-muted); }

/* In the table the column is already narrow and scrolls sideways, so the chips
   hold one line and the column carries its own floor. */
.pevents__table .ages { flex-wrap: nowrap; }
.pevents__table td:has(.ages) { min-width: 200px; }
