/* PJL Web 1.1 — Wireframe base styles
   Wireframe-fidelity only: structure and hierarchy, not final visual design. */

/* Brand fonts (assets/fonts/, sourced from ../pjl-brand/) — used by the
   main nav, page-title bars, "Latest News", and .page-title: PJL Display
   Bold Italic for top-level labels/headings, PJL Display Bold (upright,
   ported from Web 2.0 specifically for .page-title — the family's other
   cut is italic-only, and CSS can't de-italicize a font that has no
   upright glyphs of its own) for .page-title itself, PJL Sans (Bold and
   Regular, both registered under one family so font-weight picks the
   right cut) for dropdown submenu text and the Home Breaking News bar.
   Everything else on the site keeps the system-font stack (--font-sans). */
@font-face {
  font-family: "PJL Display";
  src: url("assets/fonts/PJLDisplay-BoldItalic.otf") format("opentype");
  font-weight: 700;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "PJL Display";
  src: url("assets/fonts/PJLDisplay-Bold.otf") format("opentype");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "PJL Sans";
  src: url("assets/fonts/PJLSans-Bold.otf") format("opentype");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "PJL Sans";
  src: url("assets/fonts/PJLSans-Regular.otf") format("opentype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

:root {
  --surface-0: #f8f9fa;      /* grey-50 */
  --surface-1: #ffffff;      /* ab-white */
  --border: #dee2e6;         /* grey-300 */
  --border-strong: #ced4da;  /* grey-400 */
  --text-primary: #1f1e1c;   /* grey-900 */
  --text-secondary: #5c5a54; /* grey-700 */
  --text-muted: #94918a;     /* grey-600 */
  /* Web 2.0's "Upcoming" event-state hue (Sand) — ported 2026-09-03 for
     Tour's event cards, replacing the neutral "generic" 4th state that
     used to fill this role (that state's other two prior usages, Home's
     Breaking News bar and Tour's Ticket Waitlist promo, had already
     moved to their own dedicated treatments by this point, leaving
     .module-emphasized/--generic-* fully unused — removed rather than
     kept as dead code). --upcoming-border reuses --brand-sand directly
     rather than duplicating its hex value. */
  --upcoming-bg: #FFF5D8;    /* sand-25 */
  --upcoming-border: var(--brand-sand); /* sand-500 */
  --upcoming-text: var(--text-primary); /* grey-900 */

  /* Badge base — Cobalt */
  --badge-bg: #F0F5FF;     /* cobalt-25 */
  --badge-border: #155EEF; /* cobalt-500 */
  --badge-text: #0037A5;   /* cobalt-700 */
  --radius: 0;
  --font-sans: -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;

  /* Sitewide nav brand colors — from ../pjl-brand/pjl-color-palette.md
     Navy ramp (color.brand.primary), "solid" treatment (dark filled bar),
     used by the main nav. Footer keeps its own fixed solid values (below)
     so it's unaffected if this mapping changes. */
  --nav-solid-bg: #0C2237;          /* navy-500 */
  --nav-solid-text: #EEF6FF;        /* navy-25 */
  --nav-solid-text-muted: #B6D1ED;  /* navy-50 */
  --nav-solid-divider: #4A627B;     /* navy-300 */
  --nav-solid-hover: #B6D1ED;       /* navy-50 */

  /* Brand primaries — from ../pjl-brand/brand.md, used by .page-title-bar */
  --brand-orange: #FF4800;  /* orange-500 */
  --brand-navy: #0C2237;    /* navy-500 */
  --brand-white: #E2E2E8;   /* white-500 */
  --brand-sand: #CABD98;    /* sand-500 */
  --brand-brown: #522311;   /* brown-500 */

  /* Borrowed narrowly from Web 2.0's outline-nav color family — the
     values .nav-sheet-item and .submenu need to match Web 2.0's own
     sheet/dropdown styling. Not a full outline-nav treatment (1.1 has
     no eyebrow nav). */
  --nav-outline-text: #02162A;      /* navy-700 */
  --nav-outline-hover-bg: #B6D1ED;  /* navy-50 */
  --nav-outline-border: #0C2237;    /* navy-500 */
  --nav-outline-divider: #6C859F;   /* navy-200 */
}

* { box-sizing: border-box; }

/* Sticky-footer layout: body is a full-viewport-height flex column, and
   .page (flex:1) grows to absorb any leftover space, pushing the footer
   down to the true bottom of the view on short-content pages. On tall
   pages .page's own content already exceeds 100vh, so this has no
   effect — the footer scrolls below it normally, same as before. */
/* Navy-500 is the DEFAULT body fill (2026-09-09) — most pages end up
   dark (Home, Ambassadors, Teams were each opted in individually first;
   flipped to a dark default once that pattern was clearly the majority,
   not the exception). .light-page is the opt-out for the pages that
   still need the sitewide off-white background instead — add that
   class rather than adding a new bespoke `body.<page>-page` rule per
   future light page. A page with `.pjl-rail-compact`/`.page-title-dark`/
   `.tab-nav-dark` (this page's own dark header components) but NOT
   `.light-page` continues that dark palette straight into the page
   behind it; `.module`/`.ambassador-card`/`.team-tile` etc. all keep
   their own light --surface-1 fill regardless, so card content stays
   legible either way. */
body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--brand-navy);
  color: var(--text-primary);
  font-family: var(--font-sans);
}
body.light-page {
  background: var(--surface-0);
}

/* Single source of truth for the site's outer content column (.page's
   own max-width) and the content bounds inside it — i.e. where .page's
   modules actually render, after .page's own 32px left/right padding is
   subtracted (16px top/bottom, unchanged — only the horizontal value
   feeds this column-width math). .main-nav-inner/.footer-row-inner size
   themselves to --content-bounds (not --page-max-width), the same width
   every .module already renders at, then apply --content-edge (below)
   on top of it, so nav/footer items land exactly where a module's own
   content sits. Fluid, not breakpoint-gated: fills the viewport from
   1080px up to a 1600px ceiling, with no jump at any specific
   breakpoint. Matched to Web 2.0's own values exactly (2026-09-03) —
   was 100% / -32px, which silently drifted out of sync with .page's own
   padding once that padding grew from 16px to 32px; 100vw is also more
   robust than 100% regardless of where the var is consumed from. */
:root {
  --page-max-width: clamp(1080px, 100vw, 1600px);
  --content-bounds: calc(var(--page-max-width) - 64px);
  /* Where a module's own OUTER edge (its border) sits — full-bleed bars
     (main nav, page-title-bar, tab-nav, breaking-bar) use this directly
     as their own inset. The 32px floor matches .page's own left/right
     padding above — without it, this would silently collapse to 0 below
     the 1080px viewport floor. */
  --content-edge: max(32px, calc((100vw - var(--content-bounds)) / 2));
  /* A module's own INNER text position instead — --content-edge plus
     the module's own +16px padding. .page-title-bar's own left inset
     uses this (see its own comment). */
  --title-bar-inset: calc(var(--content-edge) + 16px);
}

.page {
  max-width: var(--page-max-width);
  margin: 0 auto;
  padding: 16px 32px;
  flex: 1 0 auto;
  width: 100%;
}
/* Below sm, keep the outer left/right margin at its original 16px
   rather than the 32px used above that breakpoint — top/bottom stay
   16px at every width, unchanged. */
@media (max-width: 639.98px) {
  .page {
    padding-left: 16px;
    padding-right: 16px;
  }
}

/* Content area floor — wraps a page's main content (everything between
   main-nav and footer) so sparser pages still occupy a substantial
   height rather than looking short/empty above the footer. Matches
   Competition Format's own .module-placeholder floor (600px) so all of
   these pages read at a consistent minimum size. */
.content-area {
  min-height: 600px;
}

/* Typography */
.th { font-size: 14px; font-weight: 500; margin: 0 0 4px; }
.ts { font-size: 14px; color: var(--text-secondary); margin: 0; }
.ts-muted { font-size: 14px; color: var(--text-muted); margin: 0; }

/* Universal section/page title bar — solid PJL-orange fill, bold
   uppercase PJL-navy text. Flex layout (rather than plain block) leaves
   room for a paired second item via .bar-divider (e.g. a back-link
   chip). Ported from Web 2.0's current treatment (2026-09-03): fixed
   height, sticky under the main nav, full-bleed, PJL Sans instead of
   PJL Display italic. Values adapted to Web 1.1's own tokens/
   measurements, not copied verbatim — --content-edge/--title-bar-inset
   above, and a top offset matching Web 1.1's own .main-nav height
   (64px, 2026-09-09; was 55.5px, when it happened to match Web 2.0's
   own main-nav exactly — no longer the case since main-nav's own
   height changed and this wasn't ported back).
   No border-bottom (removed 2026-09-09) — Web 2.0's own version never
   had one; the stray `border-bottom: 1px solid var(--brand-white)` here
   was left over from before this rule was actually reconciled against
   Web 2.0's source, same class of leftover as .main-nav's own (see that
   rule's own history).
   margin-bottom:0 (also 2026-09-09, unconditional, no longer a
   `:has(+ .tab-nav)` special case) — per Web 2.0's own .page-title
   rollout (that rule's own comment, below), this bar no longer carries
   any visible title text on any page; the "default gap before whatever
   comes next" role has moved to .page-title's own margin-bottom
   instead, since .page-title now always sits directly after this bar. */
.page-title-bar {
  height: 32px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  background: var(--brand-orange);
  color: var(--brand-navy);
  font-family: "PJL Sans", -apple-system, sans-serif;
  font-size: 18px;
  font-style: normal;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  position: sticky;
  top: 64px;
  z-index: 29;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: var(--content-edge);
  padding-right: var(--content-edge);
  margin-bottom: 0;
}
/* Right-side content (e.g. a paired .bar-divider item, pushed to the
   bar's far end by justify-content:space-between) gets the same 16px
   the label itself gets — scoped to the item, not the bar's own
   padding-right, so a bar with only one child (no right-side content)
   doesn't carry unused padding on that side. */
.page-title-bar > *:last-child:not(:only-child) {
  padding-right: 16px;
}
/* Closes the gap above the bar when it's the page's first piece of
   content: pulls the bar up over .page's own 16px top padding so it
   sits flush against main-nav, matching main-nav's own sticky top:0.
   Needs BOTH selectors below, not just one: News/News Item/Ambassadors/Teams
   wrap .page-title-bar in .content-area, but Competition Format, all
   five About PJL pages, and Team Ownership/Lease do not — there
   .page-title-bar is a direct child of .page itself. A page where
   something else legitimately comes first (e.g. Tour's Ticket Waitlist
   promo) correctly keeps its normal gap, since neither selector matches
   a non-first-child bar. */
.content-area > .page-title-bar:first-child,
.page > .page-title-bar:first-child {
  margin-top: -16px;
}
/* Two-tone back-link chip — the standard way a page-title-bar carries a
   contextual back-link (currently just News Item's "Latest news"). A
   distinct navy-outlined chip on the bar's own orange fill reads as a
   clearly separate affordance from the label without needing a divider
   between them. Ported from Web 2.0's .page-title-bar-back, replacing
   Web 1.1's own former .page-title-bar-chip (background-less, no own
   border) now that the bar's base look has changed to match. */
.page-title-bar:has(.page-title-bar-back) {
  justify-content: flex-start;
  padding-left: var(--title-bar-inset);
}
.page-title-bar-back {
  display: flex;
  align-items: center;
  gap: 6px;
  align-self: stretch;
  flex: 0 0 auto;
  background: var(--brand-orange);
  color: var(--brand-navy);
  font-family: var(--font-sans);
  font-size: 13px;
  font-style: normal;
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: normal;
  text-decoration: none;
  white-space: nowrap;
  margin-top: -4px;
  margin-bottom: -4px;
  margin-left: -16px;
  padding: 0 15px;
  border-left: 1px solid var(--brand-navy);
  border-right: 1px solid var(--brand-navy);
}
.page-title-bar-back svg {
  flex: 0 0 auto;
}
.page-title-bar-back:hover {
  background: var(--brand-navy);
  color: var(--nav-solid-text);
  border-color: transparent;
}

/* .page-title — pulled from Web 2.0 (2026-09-09), where .page-title-bar
   no longer carries the page's actual heading text. Originally paired
   with .page-title-bar directly above it; as of 2026-09-09 every page
   that has one now uses .pjl-rail-compact instead (see that rule's own
   comment) — .page-title-bar itself is kept only for News Item's
   back-link chip, which has no .page-title of its own to pair with, so
   this rule's own top offset below is tuned for the rail, not the bar.
   Applied to every Web 1.1 page that has a page title: Ambassador
   Directory, News ("Latest News"), Tour Calendar, and each of the Teams/
   Competition/About PJL tabbed pages (title = that section's name, e.g.
   "Teams"). NOT added to News Item (no plain title text to move — its
   bar only ever carried a back-link chip, matching Web 2.0's own News
   Item Detail precedent of dropping .page-title entirely there) or Home
   (uses the Breaking News bar instead, no title bar of any kind).
   Sticky — top:80px is .main-nav's 64px + .pjl-rail-compact's own
   16px, so it picks up immediately where that (also sticky) bar ends
   (was 71.5px when main-nav was 55.5px tall, before 2026-09-09).
   Fill (var(--surface-0), Web 1.1's own page background) covers the
   whole box via padding, not margin, so the 16px/8px of breathing room
   above/below the text is PAINTED, not empty space a scrolling page
   behind it could show through — same reasoning as every other sticky
   bar's own fill. margin:0 is explicit and load-bearing (this is a
   <p>; without zeroing it, the browser's own default <p> margin would
   silently reapply on top of the padding).
   Web 1.1 has no .filter-row/.status-row (Web 2.0-only, out of scope
   per Content-IA's exclusions) — so the "what comes next" condition
   below only ever needs to check for .tab-nav, not Web 2.0's fuller
   :not(:has(+ .filter-row)):not(:has(+ .status-row)) chain. */
.page-title {
  position: sticky;
  top: 80px;
  z-index: 28;
  margin: 0;
  background: var(--surface-0);
  width: 100vw;
  margin-left: calc(50% - 50vw);
  padding-left: var(--content-edge);
  padding-right: var(--content-edge);
  padding-top: 16px;
  padding-bottom: 8px;
  font-family: "PJL Display", -apple-system, sans-serif;
  font-weight: 700;
  font-style: normal;
  font-size: 36px;
  line-height: 1.1;
  text-transform: uppercase;
  color: var(--brand-navy);
}
/* Bottom-rule variant — .tab-nav already carries its own
   border-bottom:0.5px solid var(--border-strong) (its own base rule),
   so a page-title-to-tab-nav transition already gets a dividing line
   for free. Everywhere else (plain content following .page-title — e.g.
   Ambassador Directory, News, Tour Calendar), there's no such line at
   all; this gives .page-title the same rule for exactly those cases, so
   the title area reads consistently closed-off either way. */
.page-title:not(:has(+ .tab-nav)) {
  margin-bottom: 16px;
}
.page-title:not(:has(+ .tab-nav))::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  border-bottom: 0.5px solid var(--border-strong);
}
@media (max-width: 639.98px) {
  .page-title {
    font-size: 32px;
  }
}

/* Dark variant — navy-500 fill, white-500 text (this project's
   --brand-navy/--brand-white — same hex values as Web 2.0's --navy-500/
   --white-500, just this project's own existing token names, not new
   ones), replacing the light --surface-0 fill/navy text default above.
   Used on Ambassadors, paired with .pjl-rail-compact (below) above it —
   that bar is itself navy/orange/sand, so the dark title continues the
   same darker palette instead of switching back to the page's light
   background directly underneath it. */
.page-title.page-title-dark {
  background: var(--brand-navy);
  color: var(--brand-white);
}
/* Bottom rule restored for the dark variant (2026-09-09) when nothing
   sticky follows .page-title (i.e. no .tab-nav after it — every page
   is navy-500 by default now, so this fires on most pages, not just a
   handful) — color matched to .tab-nav-dark's own border-bottom-color
   (--nav-solid-divider, navy-300) rather than the light variant's
   --border-strong, so a page WITH a tab bar and a page WITHOUT one read
   as the same divider treatment, just relocated (this rule for the
   no-tab-nav case, .tab-nav-dark's own border for the has-tab-nav
   case). Briefly removed entirely in an earlier pass (reasoned through
   for Ambassadors specifically, back when only a few pages were
   navy-500 by default and most were still light) — restored now that
   "most pages are navy" is the norm rather than the exception; a
   consistent divider across every page reads better than a rule that
   only sometimes applies. Same specificity as the base
   .page-title:not(:has(+ .tab-nav))::after rule above (one class + :not
   + ::after each) — wins by appearing later in source order. */
.page-title-dark:not(:has(+ .tab-nav))::after {
  border-bottom: 0.5px solid var(--nav-solid-divider);
}

/* --rail-x/--logo-clear/--logo-h promoted to :root (rather than staying
   local to .pjl-rail-compact, where Web 2.0's own source defines them)
   so .main-nav-logo, below, can share the exact same --rail-x value for
   its own width — the two components live in unrelated DOM subtrees
   (main-nav is a sibling of .page, not a descendant of anything
   .pjl-rail-compact is inside), so a var scoped to one component's own
   selector wouldn't be visible to the other; :root is the lowest common
   ancestor both can actually inherit from. See .pjl-rail-compact's own
   comment (below) for what this math means. */
:root {
  --logo-clear: 4px;
  --logo-h: calc(40px - 2 * var(--logo-clear));
  --rail-x: calc((var(--logo-h) * 150 / 46) + (2 * var(--logo-clear)));
}

/* PJL Rail (compact) — pulled from Web 2.0's .pjl-rail-compact (that
   project's own pages/pjl-rail-demo.html — not yet wired into any live
   page there either). Only the compact (20px) variant is ported; Web 1.1
   has no use for the full 40px .pjl-rail variant. --rail-x/--logo-clear/
   --logo-h math and the slot layout (x | Flex | x | 0.25x | x) are Web
   2.0's own spec, copied verbatim: a fixed-width lead slot with the navy
   PJL mark (clear-space inset per the mark's own descender width — see
   Web 2.0's own comment on this math for the full derivation), a
   flexible neutral gap, two more fixed slots, and one slot at a quarter
   of the lead slot's own width. Slot colors match Web 2.0's own
   original scheme: orange-500 on the lead/fixed slots (.pjl-rail-slot/
   .pjl-rail-logo), sand-500 on the quarter slot (.pjl-rail-slot--sm).
   (Briefly swapped to sand-500 lead/fixed + white-500 quarter-slot on
   2026-09-09, reset back to this original scheme the same day.) The
   logo graphic doesn't fit a 20px bar at full scale — the spec drops it
   rather than rescaling (.pjl-rail-compact .pjl-rail-logo img {
   display:none }), leaving the logo's own orange block in place with no
   image inside.
   Sticky/full-bleed/z-index treatment is NOT part of Web 2.0's own rule
   (its demo page has no nav to stack under) — added here since this bar
   is replacing .page-title-bar's structural role on Ambassadors: same
   slot in the page (directly under main-nav, .page-title directly
   after), so it picks up the exact same sticky-under-main-nav treatment
   .page-title-bar itself uses (top:64px, z-index:29 — was 55.5px until
   main-nav's own height changed on 2026-09-09). Because this
   bar is 16px tall (2026-09-09; was 20px), not .page-title-bar's 32px,
   .page-title's own sticky top offset is tuned to this bar's actual
   height instead of reusing .page-title-bar's — see .page-title's own
   comment for the current math.
   Bleed fill (this rule's own `background` below — the true-viewport-
   edge bleed outside content-bounds) is navy-500 here, NOT Web 2.0's own
   white-500 — a deliberate deviation for this page specifically,
   matching Ambassadors' own dark page fill (body's own default
   background as of 2026-09-09) and .page-title-dark so the bar's own
   edges read as a continuous navy surface with the page around it. This
   is independent of
   .pjl-rail-slot--flex's OWN fill (the center gap between the fixed
   blocks) — that slot carries its own explicit white-500 background
   (see its own rule below) and stays white-500 regardless of the bleed
   color, matching Web 2.0's source exactly for that one slot. In Web
   2.0's original, both fills happen to be the same single --white-500
   value inherited from one shared `background` declaration (no fill of
   its own on .pjl-rail-slot--flex, the bar's own background just shows
   through) — here they're deliberately split into two separately-set
   values instead, since this page's bleed fill diverges from source. */
.pjl-rail-compact {
  position: sticky;
  top: 64px;
  z-index: 29;
  height: 16px;
  background: var(--brand-navy);
  width: 100vw;
  margin-left: calc(50% - 50vw);
  display: flex;
  align-items: center;
  padding-left: var(--content-edge);
  padding-right: var(--content-edge);
}
.pjl-rail-compact .pjl-rail-logo img {
  display: none;
}
.pjl-rail-slot,
.pjl-rail-slot--flex,
.pjl-rail-slot--sm {
  height: 100%;
}
.pjl-rail-slot {
  flex: 0 0 var(--rail-x);
  background: var(--brand-orange);
}
.pjl-rail-slot--flex {
  flex: 1 1 auto;
  /* Own explicit fill, independent of .pjl-rail-compact's own bleed
     background above — always white-500 regardless of the bar's own
     bleed color (navy-500 on Ambassadors), matching Web 2.0's source
     exactly for this one slot even though this project's bleed fill
     itself now deviates from Web 2.0's. */
  background: var(--brand-white);
}
.pjl-rail-slot--sm {
  flex: 0 0 calc(var(--rail-x) * 0.25);
  background: var(--brand-sand);
}
.pjl-rail-logo {
  flex: 0 0 var(--rail-x);
  box-sizing: border-box;
  height: 100%;
  padding: var(--logo-clear);
  background: var(--brand-orange);
  display: flex;
}
.pjl-rail-logo img {
  display: block;
  width: 100%;
  height: 100%;
}
/* Same flush-under-main-nav treatment .page-title-bar's own first-child
   rule gives it — pulls this bar up over .page's 16px top padding when
   it's the page's first piece of content. */
.content-area > .pjl-rail-compact:first-child,
.page > .pjl-rail-compact:first-child {
  margin-top: -16px;
}
/* Pipe-style divider between two page-title-bar items sharing one side,
   rather than pushed to opposite ends via the bar's own
   justify-content: space-between. currentColor so it matches whichever
   bar it's placed in without a dedicated color token. */
.bar-divider {
  padding-left: 12px;
  margin-left: 12px;
  border-left: 1px solid currentColor;
}

/* Placeholder-sized module — for a page with a single content block
   standing in for not-yet-designed content. Matches Home's placeholder
   size/centering so single-block pages read consistently across the
   site. Combine with .module (e.g. class="module module-placeholder").
   .module-placeholder-60 is a shorter variant (60% height) for a second
   placeholder stacked below a full-size one, e.g. Home's Hero + Home
   Content 1. */
.module.module-placeholder,
.module.module-placeholder-60 {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
.module.module-placeholder {
  min-height: 600px;
}
.module.module-placeholder-60 {
  min-height: 360px;
}
/* Home hero — full-bleed (2026-09-09; was a normal in-flow .module
   before, nested inside .page). Moved to a direct child of <body>,
   sibling to .page, positioned right after .breaking-bar (same
   reasoning as .brand-banner's own placement earlier: .page has its
   own 16px top/bottom padding that a width:100vw breakout doesn't
   escape, so "no gap to main-nav or breaking news bar" needed this
   OUTSIDE .page, not just full-bleed CSS on an element still nested
   inside it). No longer combined with .module/.module-placeholder
   (that combo's own border/padding/margin-bottom/flex-centering would
   all fight a true edge-to-edge full-bleed treatment) — a standalone
   class instead, matching .news-hero/.brand-banner's own pattern.
   margin:0 handles "no gap" on both sides at once: above, whatever
   precedes it (.breaking-bar, or .main-nav directly on a day with no
   breaking story) is flush since neither carries its own trailing
   margin either; below, .page (this element's very next sibling)
   has no top margin of its own (just padding, which starts its OWN
   box, not a gap before it). */
.home-hero {
  min-height: 60vh;
  width: 100vw;
  margin: 0;
  margin-left: calc(50% - 50vw);
  background-image: url("assets/hero_sample.jpg");
  background-size: cover;
  background-position: center;
}

/* Home Content blocks — replaces the old "Home Content 1"
   .module-placeholder-60 stand-in (2026-09-09) with real image
   containers, 1350×780 (2026-09-09, 2nd follow-up — was 1350×1012.5/
   4:3 the round before; aspect-ratio expressed as the exact 1350/780
   pair rather than a reduced fraction, since it doesn't simplify to a
   clean ratio like 4:3 did). Responsive now too ("make these
   responsive" — the earlier fixed width:1350px was flagged as a risk
   on any viewport narrower than that, and now actually fixed): width:
   100% up to a max-width:1350px cap, so it scales down proportionally
   (aspect-ratio keeps recomputing height to match) below that,
   instead of overflowing a narrow page. The <img> inside still fills
   the box via object-fit:cover regardless of the container's own
   current rendered size. Centered in .page via margin:0 auto since
   nothing was specified about alignment.
   Gap between blocks: 400px originally ("set the padding between
   these items to 400px"), then made responsive (2026-09-09 follow-up
   — a fixed 400px stayed full-size even once the block's own width
   started scaling down below 1350px, so on a narrow page the gap
   could end up TALLER than the image itself). `margin-bottom: 29.63%`
   instead — a CSS quirk turned into the actual mechanism here:
   percentage margins always resolve against the containing block's
   WIDTH, never height, so this scales down at the same rate the
   block's own width does, keeping the gap-to-image-width ratio
   constant (400/1350 = 0.2963) rather than needing a media query or
   JS to recompute it. Only diverges from a literal 400px right at the
   very top of the width range, above 1350px content width, where the
   image itself is capped by max-width but the containing block (up to
   --page-max-width's own 1600px) keeps growing — the percentage still
   resolves against that wider box, so the gap grows slightly past
   400px there instead of staying capped too; not fixed, since nothing
   asked for a matching cap on the gap specifically and the block's
   own width is what was asked to cap. */
.home-content-block {
  width: 100%;
  max-width: 1350px;
  aspect-ratio: 1350 / 780;
  margin: 0 auto;
  margin-bottom: 29.63%;
  overflow: hidden;
}
.home-content-block img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Standard content module */
.module {
  border: 0.5px solid var(--border-strong);
  border-radius: 0;
  padding: 16px;
  background: var(--surface-1);
  min-height: 70px;
  margin-bottom: 12px;
}

/* "Upcoming" event-state module — white card, thin neutral border, 4px
   solid sand left-accent stripe (see --upcoming-* above). Text uses
   --upcoming-text rather than the module's default so it stays legible
   against the white fill. Ported from Web 2.0's Tour Calendar
   (2026-09-03) — Web 2.0 layers this over its own Complete/Current
   state classes too, but Web 1.1 has no status field on event cards
   (Content-IA §4.2 / FS §17.5), so this is the only state class ported;
   every Tour event card uses it uniformly, same as the generic state it
   replaces did. */
.module-upcoming {
  position: relative;
  border-radius: 0;
  padding: 20px;
  background: var(--surface-1);
  border: 0.5px solid var(--border-strong);
  border-left: 4px solid var(--upcoming-border);
  color: var(--upcoming-text);
  margin-bottom: 12px;
}
/* Full-width schedule event card — event identity in its own fixed-width
   column beside the venue/location/date details. Ported from Web 2.0's
   own .event-card (2026-09-03), minus its .event-card-state label and
   .event-card-actions button column — no status field and no
   link/action affordance on Tour Schedule cards in Web 1.1 (Content-IA
   §4.2 / FS §8.1 Card-Based List Terminal Rule). Text classes below
   (name/venue/location/date) are ported verbatim from Web 2.0 too,
   replacing an earlier pass that reused Web 1.1's own .th/.ts/.ts-muted
   here — venue and location are two separate lines in Web 2.0, not one
   combined "Venue · Location" line, so this needed its own classes
   rather than reusing the sitewide ones. None of them set an explicit
   font-size (matching Web 2.0's own rules exactly) — both sites leave
   body at the browser default, so this inherits it unchanged. */
.event-card {
  display: flex;
  align-items: flex-start;
  gap: 20px;
}
.event-card-info {
  flex: 0 0 auto;
  width: 160px;
}
.event-card-name {
  margin: 0;
  font-family: "PJL Sans", -apple-system, sans-serif;
  font-weight: 700;
  text-transform: uppercase;
  color: inherit;
}
.event-card-details {
  flex: 1 1 auto;
  min-width: 0;
}
.event-card-venue {
  margin: 0 0 2px;
  font-weight: 700;
  color: inherit;
}
.event-card-location,
.event-card-date {
  margin: 0;
  color: inherit;
}
.event-card-date {
  font-weight: 700;
}
/* Venue description — optional (2026-09-09): most events have no copy
   yet (source doc: /Users/Thad.Carr/Projects/pjl-docs/Venue Blurbs
   V1.docx marks them "requested"/"chasing"), so this is only present
   on some cards. Each .event-card is its own full-width stacked row
   (.module-upcoming, not a grid), so a card with a description is
   simply taller than one without — no shared-row height to clamp
   against, unlike the News grid's .news-card teasers. */
.event-card-description {
  margin: 8px 0 0;
  color: inherit;
}

/* Schedule leg divider — pulled from Web 2.0's own .leg-divider (that
   project's tour.html), which segments its full schedule into 3 legs:
   Americas/Regular Season/Spring (before Event 01), Europe/Regular
   Season/Summer (before Event 05), Middle East/Playoff & Final/Autumn
   (before Playoff) — same 3-way split as this project's own source doc
   (PJL_2027_Events_Schedule.md's own Americas/Europe/Middle East
   section headers). Layout/fixed-width end-cap sizing (.leg-divider-
   name 131px, .leg-divider-time 94px — both sized to their own widest
   label, "Middle East"/"Summer") are copied as-is; end-cap COLORS
   deliberately deviate from Web 2.0's own navy fill/white text —
   orange-500/navy-500 instead (2026-09-09), this project's own primary-
   emphasis accent (matching .pjl-rail-slot's own orange, not Web 2.0's
   choice here).
   Normal-flow, not sticky (2026-09-09 — "let's just remove all
   stickyness from the leg-dividers and tickets"; was sticky earlier the
   same day, with .leg-divider-1/2/3 each carrying their own `top` offset
   recomputed every time the Ticket Waitlist promo's own height/margin/
   sticky-state changed — see this file's own memory log for that whole
   back-and-forth). No `position`/`z-index`/per-instance `top` needed
   any more now that nothing here is pinned; .leg-divider-1/2/3 exist
   only to size their own fixed-width end caps consistently, not for any
   positioning role.
   This element's own `background` is brand-navy, matching Tour
   Calendar's own page fill (navy-500, this page has no .light-page
   class) the same way .pjl-rail-compact's own bleed fill matches ITS
   page's fill — kept even though it's no longer masking a sticky-stack
   bleed-through problem (nothing here is stuck any more), since it
   still reads correctly as the page's own background showing through
   the padding-bottom gap. */
.leg-divider {
  height: 45px;
  background: var(--brand-navy);
  display: flex;
  align-items: stretch;
  padding-bottom: 12px;
}
.leg-divider-part {
  display: flex;
  align-items: center;
  padding: 4px 12px;
  font-size: 15px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  white-space: nowrap;
}
.leg-divider-name {
  flex: 0 0 131px;
  justify-content: flex-start;
  background: var(--brand-orange);
  color: var(--brand-navy);
}
.leg-divider-season {
  flex: 1 1 auto;
  justify-content: flex-start;
  background: var(--brand-sand);
  color: var(--brand-navy);
}
.leg-divider-time {
  flex: 0 0 94px;
  justify-content: flex-end;
  background: var(--brand-orange);
  color: var(--brand-navy);
}

/* Status badge (e.g. Live — a temporary sub-state layered on a label).
   Base color is Cobalt; a state variant (e.g. .badge-live) can override
   background/border/color here if it ever needs a distinct color. */
.badge {
  display: inline-block;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  padding: 4px 8px;
  border-radius: 0;
  margin-left: 8px;
  vertical-align: middle;
  background: var(--badge-bg);
  border: 0.5px solid var(--badge-border);
  color: var(--badge-text);
}
/* A badge leading its own card/line (nothing to its left to separate
   from) shouldn't carry the inline margin-left meant to space it from
   preceding text. */
.badge:first-child {
  margin-left: 0;
}

/* Two/three-column grid layout */
.grid-2 {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 12px;
  margin-bottom: 12px;
}
/* Stack to 1 column below sm (2026-09-09) — same binary collapse
   .grid-3/.grid-4 already use; .grid-2 had no mobile override at all
   until now (its own 2 usages, News's article grid and Team
   Directory's .team-tile grid, both need it: a 240px-wide .team-tile
   or a bled-thumbnail .news-card.image-left squeezed into a narrow
   phone-width half-column reads as cramped, not just "denser"). */
@media (max-width: 639.98px) {
  .grid-2 {
    grid-template-columns: 1fr;
  }
}
.grid-3 {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr);
  gap: 12px;
  margin-bottom: 12px;
}
/* 3 columns leaves too little room for a card-with-headshot's fixed
   96px thumbnail below sm — stack to 1 column. */
@media (max-width: 639.98px) {
  .grid-3 {
    grid-template-columns: 1fr;
  }
}
/* Ambassador Directory — 4 columns at full width (its own .ambassador-card
   is a narrow portrait tile, not a wide card-with-headshot row, so it
   doesn't need .grid-3's 96px-thumbnail headroom below sm). Same binary
   collapse-to-1-column convention as .grid-2/.grid-3, no intermediate
   tablet tier — 1.1's sitewide nav/grid breakpoint model is binary, not
   progressive (see Functional Architecture §2.1). */
.grid-4 {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px;
  margin-bottom: 12px;
}
@media (max-width: 639.98px) {
  .grid-4 {
    grid-template-columns: 1fr;
  }
}
/* Grid items keep their own margin-bottom for when a .module is used
   standalone — inside a grid row, that margin would stack with the
   row's own margin-bottom and double the gap below the row, so zero it
   out here. */
.grid-2 > *,
.grid-3 > *,
.grid-4 > * {
  margin-bottom: 0;
}

/* Card / module layout with a placeholder image beside the text —
   headshot (ambassador) or logo (team), same box treatment either way.
   Ported from Web 2.0 (News/Ambassadors/Teams layouts). */
.card-with-headshot {
  display: flex;
  align-items: center;
  gap: 12px;
}
/* Text column shrinks instead of overflowing the card at narrow column
   widths (e.g. Home's 3-column News teaser) — flex items default to
   min-width: auto, which holds them at their content's natural width
   and pushes them outside the card when the row is too narrow. */
.card-with-headshot > div:last-child {
  min-width: 0;
}

/* Horizontal directory row: Headshot | Name | Team | Country, each its
   own column — used by the Ambassador Directory (kept terminal in 1.1,
   so a plain .module rather than a real link). */
.ambassador-row {
  display: flex;
  align-items: center;
  gap: 16px;
}
.ambassador-row > *:not(.headshot-placeholder) {
  flex: 1;
  min-width: 0;
}
.headshot-placeholder,
.logo-placeholder {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  border: 0.5px solid var(--border-strong);
  background: var(--surface-1);
}
/* Larger variant for a more prominent card (e.g. Team/Ambassador
   Directory's own enlarged cards), vs. the small size used elsewhere. */
.headshot-placeholder.lg,
.logo-placeholder.lg {
  width: 96px;
  height: 96px;
}

/* Button-styled call-to-action inside a card (e.g. "Join Waitlist" on
   the Ticket Waitlist promo) — margin-left: auto pushes it to the
   card's lower-right corner while staying in normal flow. */
.card-cta {
  display: block;
  width: fit-content;
  margin-top: 8px;
  margin-left: auto;
  padding: 8px 16px;
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  text-decoration: none;
  background: var(--nav-solid-bg);
  color: var(--nav-solid-text);
  border: none;
  font-family: inherit;
  cursor: pointer;
}

/* Generic placeholder swatch for an image (e.g. a News lead story). */
.image-placeholder {
  width: 100%;
  aspect-ratio: 4 / 3;
  border: 0.5px solid var(--border-strong);
  background: var(--surface-1);
  margin-bottom: 8px;
}

/* Ambassador/Team Directory cards: image beside text at normal widths,
   but stacked (image on top, details below) below sm — scoped so
   Home's own card-with-headshot usage (small 96px thumbnail, already
   comfortable in a 3-column grid) is unaffected. (.directory-card has
   no live usage sitewide any more — Ambassador Directory moved to
   .ambassador-card, Team Directory to .team-tile — kept here rather
   than deleted since removing it isn't part of this change; flagged
   separately for its own cleanup pass.) */
@media (max-width: 639.98px) {
  .directory-card .card-with-headshot {
    flex-direction: column;
    align-items: flex-start;
  }
}

/* News card link-reset — News's cards are real links (to the shared
   sample News Item, since per-story pages aren't built in 1.1); Ambassador/
   Team Directory cards stay plain .module (no link, per 1.1's "card-
   based list views are terminal" rule), so no ambassador-card/team-card
   classes are used on those pages. The border:none/background:none
   override that cancels .module/.cat-editorial's own bordered-card fill
   lives further down, right after .cat-editorial's own rule (2026-09-09
   — see that rule's own comment for why source order, not just
   specificity, matters here).
   Hover — NAME COLLISION caught by simulating actual :hover on Web 2.0's
   own live page and reading getComputedStyle, not just its CSS source
   text (2026-09-09): Web 2.0's own `.news-card:hover` rule also reads
   `background: var(--nav-outline-hover-bg)`, so an earlier pass here
   just copied that property value verbatim — but Web 2.0's OWN
   `--nav-outline-hover-bg` is `rgba(12, 34, 55, 0.04)` — a translucent
   navy wash (navy-500 @ 4% opacity), a completely different color from
   THIS project's own `--nav-outline-hover-bg` (#B6D1ED, navy-50, solid
   light blue — used here for nav dropdown/sheet item hover, a different
   UI context). Same variable NAME, different VALUE, in each project —
   reusing 1.1's own token gave the wrong color even though the rule
   text looked identical. Fixed by hardcoding the literal rgba value
   Web 2.0 actually uses (matching this project's own --brand-navy hex,
   #0C2237 = rgb(12,34,55), just expressed as a translucent rgba here)
   rather than reusing either project's --nav-outline-hover-bg name.
   (Web 2.0's computed `transition` on hover is real but inert —
   transitionDuration measured 0s, i.e. just the CSS-wide initial value
   getComputedStyle always reports, not an actual animation — so no
   transition was added here either.) */
.news-card {
  display: block;
  text-decoration: none;
}
.news-card:hover {
  background: rgba(12, 34, 55, 0.04);
  cursor: pointer;
}

/* Full-bleed hero banner above News's own content — NOT the same thing
   as .hero-story-overlay (removed 2026-09-09 along with the featured
   article's own special styling; that article is now a plain
   .news-card.image-left, same as every other story). This is a
   standalone brand-statement banner, not tied to any one story's own
   content — image and text are both fixed, not story-driven. Full-bleed
   the same way .page-title-bar/.tab-nav/.pjl-rail-compact are
   (width:100vw + margin-left:calc(50% - 50vw) breakout). 40vh height
   per spec (2026-09-09 — was 40vh originally, reduced to 35vh per
   earlier feedback back when only News used this component, now back
   to 40vh; this class is shared across News/Leadership/Contact/FAQ by
   now, so the change applies to all of them), not content-driven
   (unlike .module's own min-height:70px floor) — flex centering (both
   axes) keeps the tagline centered regardless of that fixed height. */
.news-hero {
  height: 40vh;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-bottom: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}
.news-hero-text {
  margin: 0;
  /* max-width: 80% of --content-bounds, NOT 80% of this element's own
     .news-hero container (2026-09-09; corrected same day — a plain
     `max-width: 80%` resolves against .news-hero's own full-bleed
     100vw box, which is WIDER than the site's actual content width
     everywhere else on the page, so it wasn't really "80% of available
     CONTENT width" as intended). --content-bounds (defined near :root,
     above) is the same effective content width every non-full-bleed
     module already renders at (--page-max-width minus .page's own 32px
     ×2 padding) — computing 80% of THAT instead ties this to the same
     content measure the rest of the page uses, independent of this
     one element's own full-bleed box. 70% as of 2026-09-09 (was 80%). */
  max-width: calc(var(--content-bounds) * 0.7);
  padding: 0 24px;
  font-family: "PJL Display", -apple-system, sans-serif;
  font-style: italic;
  font-weight: 700;
  font-size: 80px;
  line-height: 0.9;
  text-align: center;
  color: var(--brand-white);
}
@media (max-width: 639.98px) {
  .news-hero-text {
    font-size: 72px;
  }
}
/* No gap between .page-title and this banner (per spec) — overrides the
   base rule's own 16px margin-bottom (.page-title:not(:has(+
   .tab-nav)), above) for this one case. Same specificity (one class +
   one :has() pseudo-class each) — wins by appearing later in source. */
.page-title:has(+ .news-hero) {
  margin-bottom: 0;
}
/* Same, for a tab-nav immediately followed by this banner (Leadership,
   2026-09-09) — overrides .tab-nav's own base 16px margin-bottom
   (above) so the hero sits flush against the tab row, same "no gap"
   treatment .page-title gets when the hero follows it directly instead. */
.tab-nav:has(+ .news-hero) {
  margin-bottom: 0;
}

/* Brand banner — full-bleed SOLID-COLOR statement module (2026-09-09),
   .news-hero's sibling component: same brand-statement role and same
   text treatment, but no background image and no fixed viewport-
   height (that 40vh existed to give an image room to crop into; a
   flat color needs no such box, so height is content-driven — padding
   below, not a vh value). Colors are NOT baked into the base class —
   pair it with exactly one of the 3 named variants below (fill, then
   text color, in that order, matching how they were specified):
     .brand-banner-white-navy   — white-500 fill, navy-500 text
     .brand-banner-navy-white   — navy-500 fill, white-500 text
     .brand-banner-navy-orange  — navy-500 fill, orange-500 text
   margin-top/bottom:0 is built into the base class itself (not a
   `:has()` companion rule like .news-hero needed) — "no spacing top or
   bottom wherever it is placed" is this module's own always-on
   property, not a per-page override. The two `:has()` rules below
   still exist for the OTHER side of that gap though: whatever precedes
   this module (.page-title/.tab-nav) still carries its own margin-
   bottom unless zeroed, same mechanism .news-hero already uses. */
.brand-banner {
  width: 100vw;
  margin-top: 0;
  margin-bottom: 0;
  margin-left: calc(50% - 50vw);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 32px;
  padding: 64px 24px;
}
.brand-banner-white-navy {
  background: var(--brand-white);
  color: var(--brand-navy);
}
.brand-banner-navy-white {
  background: var(--brand-navy);
  color: var(--brand-white);
}
.brand-banner-navy-orange {
  background: var(--brand-navy);
  color: var(--brand-orange);
}
/* Text — same font treatment as .news-hero-text (PJL Display italic,
   0.9 line-height), width capped at 90% of --content-bounds (not this
   element's own full-bleed .brand-banner container — same correction
   .news-hero-text's own comment explains). color is deliberately NOT
   set here — inherits from whichever .brand-banner-* variant class is
   on the parent, so this one class works with all 3 variants without
   its own color logic. */
.brand-banner-text {
  margin: 0;
  max-width: calc(var(--content-bounds) * 0.9);
  font-family: "PJL Display", -apple-system, sans-serif;
  font-style: italic;
  font-weight: 700;
  font-size: 80px;
  line-height: 0.9;
  text-align: center;
}
@media (max-width: 639.98px) {
  .brand-banner-text {
    font-size: 72px;
  }
}
/* FAQ-context CTA button (2026-09-09) — for a .brand-banner that
   teases/links to FAQ content specifically ("SEE FAQS"); not a
   general-purpose button for every .brand-banner variant, hence the
   `--faq` modifier rather than a plain `.brand-banner-cta`. Colors are
   fixed (orange fill/navy text, sand fill on hover) rather than
   inheriting from whichever .brand-banner-* variant it's placed in —
   the reference button is a single fixed style regardless of the
   banner's own fill/text color pairing. */
.brand-banner-cta--faq {
  display: inline-block;
  padding: 24px 48px;
  background: var(--brand-orange);
  color: var(--brand-navy);
  font-family: "PJL Sans", -apple-system, sans-serif;
  font-size: 18px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  text-decoration: none;
  border: none;
  border-radius: var(--radius);
}
.brand-banner-cta--faq:hover {
  background: var(--brand-sand);
  color: var(--brand-navy);
}
.page-title:has(+ .brand-banner) {
  margin-bottom: 0;
}
.tab-nav:has(+ .brand-banner) {
  margin-bottom: 0;
}
/* .brand-banner placed AFTER .page closes (a body-level sibling, e.g.
   "above the footer" — see .page's own comment). Two separate gap
   sources stack between the last content and the banner here: .page's
   own 16px bottom PADDING, and that last child's own margin-bottom
   (e.g. .module's own 12px) — together they read as a "double" gap
   (2026-09-09: first zeroed both entirely, then corrected again the
   same day — "there must be a gap between the content area and the
   brand-banner": a single standard gap is wanted here, not zero and
   not both stacked). Keeps .page's own normal 16px bottom padding
   (the same page-to-footer spacing every other page already uses,
   .brand-banner or not) as that one gap, and zeroes only the
   REDUNDANT second source — the last child's own margin-bottom, which
   would otherwise stack on top of the padding that already provides
   clearance. */
.page:has(+ .brand-banner) > *:last-child {
  margin-bottom: 0;
}

/* Secondary News cards (Top Stories' own picks, and the Latest News
   feed below them) — .news-card.image-left, ported from Web 2.0. That
   project bleeds the thumbnail flush to the OUTER card's own edges
   (past ALL FOUR of its sides — including its top/bottom padding, not
   just the left — the image's rendered height there is measured as
   exactly equal to the CARD's own full height, not just the inner
   .card-with-headshot row's height) via an absolutely-positioned image
   plus a JS helper (squareBleedImage, include.js) that measures the
   card's rendered height at runtime, sets the image's width to match
   (keeping data-bleed-ratio="4/3"), and sets the CARD's own
   padding-left to image-width + a gap, all computed fresh each time.
   Confirmed via getBoundingClientRect against Web 2.0's own live page
   (not just its source) — first port attempt anchored position:relative
   on .card-with-headshot instead of the outer .news-card.image-left
   card, which only bled the image to the ROW's own edge (already inset
   by the card's own 16px .module padding), not the card's TRUE edge —
   a real, measurable gap (imgRect.x came back 48 instead of Web 2.0's
   32, i.e. still sitting 16px short of the border) that a quick visual
   glance didn't catch but comparing exact numbers against the live
   Web 2.0 page did.
   This port keeps the position:absolute half of the technique (CSS-
   only, reliable: an absolutely positioned box with a definite
   block-size derives its own inline-size from aspect-ratio:4/3,
   already set on the base .image-placeholder rule) anchored on the
   OUTER card this time, and drops the JS half in favor of a fixed
   reserved padding-left instead of a dynamically-measured one — this
   row's height is deterministic by design (.th forced to one line,
   .ts clamped to exactly 2, so every card's text content converges on
   close to the same height regardless of copy length), so a flat value
   holds up without a script:
   card height = text row's own ~76px + .module's own 16px×2 padding =
   108px; image width at 4/3 = 108×4/3 = 144px; +12px gap (this file's
   own standard .card-with-headshot gap value) = 156px reserved. */
.news-card.image-left {
  position: relative;
  padding-left: 156px;
}
.news-card-image {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  width: auto;
  margin-bottom: 0;
}
/* Fixed line-clamping — Latest News rows sit stacked directly against
   each other with no card border between them (see .grid-2's own use
   here), so an uneven row height (a headline/teaser that runs long
   enough to wrap an extra line) would read as a visible seam/
   misalignment against the rows above and below, not just a taller
   card. Clamping both to a fixed line count keeps every row the same
   height regardless of copy length. */
.news-card.image-left .th {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.news-card.image-left .ts {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  /* line-clamp only caps the max at 2 lines — a 1-line teaser still
     collapses to its own shorter height, so two rows in the same grid
     row (e.g. a 1-line teaser beside a 2-line one) render at different
     heights even though both are "default" cards. Reserving the full
     2-line height always (14px .ts renders at 16px for 1 line / 32px
     for 2) keeps every card the same height regardless of how much of
     the clamp an individual teaser actually uses. */
  min-height: 32px;
}
.news-card.image-left .th,
.news-card.image-left .ts {
  color: inherit;
}
.news-card.image-left .th {
  font-weight: 700;
  margin: 8px 0 4px;
}

/* Home's Breaking News bar — orange "Breaking" badge beside a light
   content panel (headline + arrow), 32px tall. Resynced from Web 2.0's
   current design (2026-09-09) — see that project's own equivalent
   comment for the full edge-bleed rationale. "Edge to edge fill" +
   "content stays within max content width": the badge and arrow are
   each their own solid-orange segment (not one bar-wide fill like
   .main-nav's own), each bleeding its OWN fill out to the true viewport
   edge via padding rather than the whole bar breaking out — badge's
   padding-left and arrow's padding-right both use --content-edge, so
   "BREAKING" and the arrow icon land at the normal content-bounds inset
   while their orange fill continues past that to the true edge,
   matching .page-title-bar's own edge treatment. */
.breaking-bar {
  /* Sticky, pinned directly under .main-nav (also sticky, top:0) —
     64px is .main-nav's own rendered height (was 55.5px before
     2026-09-09), same value/reasoning as .page-title-bar's own sticky
     top (the two never appear on the same page — this is Home-only,
     that's every other page — so sharing a z-index with it is safe). */
  position: sticky;
  top: 64px;
  z-index: 29;
  display: flex;
  align-items: stretch;
  height: 32px;
  /* No border, per Web 2.0's own feedback. Separation from .main-nav (a
     concern specifically on rollover, when the badge/arrow segments
     below swap fill color) is handled by that rollover fill itself
     (sand-500, not navy) staying visually distinct from .main-nav's own
     navy, rather than a border line. */
  text-decoration: none;
  overflow: hidden;
}
.breaking-bar-badge {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
  background: var(--brand-orange);
  color: var(--brand-navy);
  font-family: "PJL Sans", -apple-system, sans-serif;
  font-size: 24px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  line-height: 1;
  /* var(--content-edge) — lines "BREAKING" up with a module's own
     bounding-box edge, same as the main-nav logo (not a module's own
     +16px inner text position). */
  padding: 0 8px 0 var(--content-edge);
  white-space: nowrap;
}
.breaking-bar-content {
  display: flex;
  align-items: center;
  flex: 1 1 auto;
  min-width: 0;
  background: var(--surface-1);
  padding: 0 16px;
}
.breaking-bar-headline {
  color: var(--brand-navy);
  font-family: "PJL Sans", -apple-system, sans-serif;
  font-size: 18px;
  font-weight: 400;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.breaking-bar-arrow {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
  background: var(--brand-orange);
  color: var(--brand-navy);
  /* No left padding — the arrow-box (below) starts exactly where this
     segment's own orange fill starts, right at the content panel's
     edge, rather than leaving a gap of orange before it. Right padding
     matches .breaking-bar-badge's own left padding (var(--content-edge))
     exactly, so the bar's two edge-bleed margins are the same size on
     both sides. */
  padding: 0 var(--content-edge) 0 0;
}
/* The true edge-bleed padding above can't itself be part of a square
   (it scales with viewport width) — this inner box is the actual 1:1
   square instead, sized to the bar's own 32px height so it's as large
   as it can be without exceeding the bar. */
.breaking-bar-arrow-box {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 32px;
  height: 32px;
  background: var(--brand-orange);
}
.breaking-bar-arrow-box svg {
  flex: 0 0 auto;
  /* The icon's own path is already mathematically centered in its
     viewBox (verified: equal 6px gaps on all four sides of the 32px box
     at rest), but the arrowhead's converging lines concentrate visual
     "ink" on its right side versus the plain single-line shaft on its
     left — reads as off-center even though it geometrically isn't.
     Nudges it left to compensate, same optical-centering adjustment any
     directional/arrow glyph typically needs. */
  transform: translateX(-1.5px);
}
/* Rollover — scoped to just the two orange-filled segments (badge,
   arrow/arrow-box), not the whole bar: the light headline panel between
   them (.breaking-bar-content) has no fill of its own to invert, so it
   stays as-is rather than the hover picking up a color it was never
   given. Sand-500 fill, matching Web 2.0 — navy text stays the same
   color throughout, since it has good contrast against both orange and
   sand. */
.breaking-bar:hover .breaking-bar-badge,
.breaking-bar:hover .breaking-bar-arrow,
.breaking-bar:hover .breaking-bar-arrow-box {
  background: var(--brand-sand);
  color: var(--brand-navy);
}

/* News Item's article content drops the shared .module card look
   (solid border + white fill) — it's the page's own main content, not
   a card sitting on the page background. */
.module.article-body {
  border: none;
  background: none;
}
/* Ambassador/Team Directory cards drop the shared card look (solid border +
   cat-editorial fill) — keeps cat-editorial's navy text color, still
   inherited by their .th/.ts/.ts-muted children. Scoped to this
   modifier class, not .cat-editorial generally, since Home/News's own
   cat-editorial cards keep their fill/border. */
.cat-editorial.directory-card {
  border: none;
  background: none;
}
/* Home's Latest News teaser — was a single row of 3 compact cards with
   a table-style seam rule between them instead of a grid gap (no
   longer true: 2026-09-09, now 6 cards/2 rows of News's own
   .news-card.image-left bleed-thumbnail cards, "remove all vertical
   rules, we have lost the padding between rows" — the seam-rule
   treatment doesn't extend to a 2nd row (no bottom rule, no row-gap at
   all) and doesn't suit these taller bleed cards anyway). Removed
   entirely — .home-news-grid now just inherits .grid-3's own normal
   gap, same as every other grid on the site; .news-card's own
   border:none already comes from that class's own base rule
   (styles.css, `.news-card { border: none; background: none; }`), so
   no Home-specific override was needed for that part either. */
/* Ambassador/Team Directory grids — table-style rule treatment: cards
   touch (no grid gap, spacing comes from their own padding) and a thin
   rule marks the column/row seams instead of each card having its own
   border. Every card gets a bottom rule (including a lone last-row
   card, closing out the list) and left-column cards get a right rule
   that continues as a center rule even when a lone last-row card has no
   card beside it. (No live usage sitewide any more — see
   .directory-card's own comment a few rules up.) */
.directory-grid {
  gap: 0;
}
.directory-grid .directory-card {
  border-bottom: 0.5px solid var(--border-strong);
}
.directory-grid .directory-card:nth-child(odd) {
  border-right: 0.5px solid var(--border-strong);
}

/* Ambassador card — pulled from Web 2.0's .rider-tile (that project's
   pages/rider-card-sample.html), keeping only the photo + flag/name/
   country identity footer. Deliberately dropped from the source:
   .rider-tile-main's <a> wrapper and hover state, the "view profile"
   arrow chip, and the badge/stat-row variants (Top Rider/Leaderboard) —
   Ambassador Directory cards are terminal per the sitewide Card-Based
   List Terminal Rule (no Ambassador Profile destination exists in 1.1),
   and the badge/stat-row are tied to Standings/Leaderboard, entirely out
   of 1.1's scope (see Content-IA §8 Out of Scope). Photo aspect-ratio is
   2:3, not the source's 1:1 square — real ambassador headshots
   (assets/ambassadors/*-crop.jpg) are already cropped to 2:3, so the
   card follows the photo's own shape instead of force-cropping it
   further. Country replaces the source's "team" sub-line — ambassadors
   have no team affiliation in this content, just a home country. Bio
   blurb below the footer is new, not part of the source component —
   real copy from content_source/ambassadors/pjl-ambassadors.md, not a
   "Bio — placeholder..." field demonstration like the card this
   replaces. Plain fixed px sizing throughout (not Web 2.0's cqw
   container-query scaling) — 1.1 has no other container-query
   component, and 13 cards in a 3-column grid don't need that scaling
   system's column-count flexibility. */
.ambassador-card {
  display: flex;
  flex-direction: column;
  border: 0.5px solid var(--border-strong);
  background: var(--surface-1);
  overflow: hidden;
}
.ambassador-card-photo {
  aspect-ratio: 2 / 3;
  background-color: var(--nav-solid-bg);
  background-size: cover;
  background-position: center top;
}
/* No image yet (e.g. Cian O'Connor, Tom Wachman) — same solid-border/
   light-fill wireframe convention as .headshot-placeholder, just filling
   the full photo box instead of a small fixed square. Border on all 4
   sides (not just bottom) even though 3 of them coincide with
   .ambassador-card's own border — a single edge next to an otherwise-
   bordered white card read as too subtle to register as "placeholder"
   at a glance (same issue caught and fixed on .team-tile-photo
   .placeholder, below — applying the same fix here now rather than
   leaving it for a separate pass). Dashed → solid (2026-09-09) sitewide,
   including this rule — dashed borders don't match PJL brand
   guidelines. */
.ambassador-card-photo.placeholder {
  background-color: var(--surface-0);
  border: 0.5px solid var(--border-strong);
}
/* Height, border-bottom, and internal text layout all match Web 2.0's
   .rider-tile-footer exactly — two different reference points, each the
   right source for what it gives:
   - height:51px is .rider-tile-footer's own measured RENDERED height
     inside that project's actual live grid (15cqw of a ~343px-wide
     tile — see that project's .mini-row comment, styles.css), which is
     closer to this card's own real width than the isolated component-
     sample page is, so it's the better reference for this one property.
   - gap/padding/font-size/line-height/margin below instead use the
     documented ORIGINAL fixed-px values .rider-tile's own comments state
     the cqw versions were hand-converted FROM, at that sample page's
     280px reference width (e.g. "14px name / 280px = 5cqw", "3.93cqw
     (11px @280px)") — the closest thing to ground truth for text sizing,
     since a fixed-px approach (no cqw here — see .ambassador-card's own
     comment) has to pick one canonical size rather than scale
     continuously with card width the way the source does.
   border-bottom is the same rule .rider-tile-stat's border-top provides
   in the source (there, separating the footer from the stat row below
   it) — here separating it from the bio blurb instead, since that's
   what actually follows in this card. Horizontal-only padding (not
   vertical) so the explicit height, not padding, controls the row's
   size — same convention as .main-nav/.breaking-bar/.page-title-bar. */
.ambassador-card-footer {
  display: flex;
  align-items: center;
  gap: 10px;
  height: 51px;
  padding: 0 12px;
  border-bottom: 0.5px solid var(--border-strong);
}
.ambassador-card-flag {
  flex: 0 0 auto;
  width: 36px;
  height: 24px;
  object-fit: cover;
  border: 0.5px solid var(--border-strong);
}
.ambassador-card-name-group {
  flex: 1 1 auto;
  align-self: center;
  min-width: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.ambassador-card-name {
  flex: 0 0 auto;
  min-width: 0;
  margin: 0;
  font-family: "PJL Sans", -apple-system, sans-serif;
  font-size: 14px;
  font-weight: 700;
  line-height: 1;
  color: var(--brand-navy);
  text-transform: uppercase;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ambassador-card-country {
  flex: 0 0 auto;
  min-width: 0;
  margin: 1px 0 0;
  font-family: "PJL Sans", -apple-system, sans-serif;
  font-size: 11px;
  font-weight: 400;
  line-height: 1;
  color: var(--text-secondary);
  text-transform: uppercase;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ambassador-card-bio {
  margin: 0;
  padding: 12px;
  font-size: 13px;
  color: var(--text-secondary);
}

/* Team tile — based on .ambassador-card above, same component family
   (border/background, name/country text sizing) but a different shape
   for a different layout need: a horizontal card (image LEFT, name/
   country row + bio stacked in a column to its RIGHT) instead of
   .ambassador-card's vertical stack (photo on top, footer, bio below).
   Image is 2:3, same ratio as .ambassador-card-photo (matching real
   ambassador headshot crops there; kept here too even though no team
   photo exists yet, for visual consistency between the two directories'
   tiles).
   Width is a fixed 240px (2026-09-09, "much larger" per feedback — was
   previously sized via align-self:stretch + width:auto, matching
   whatever height the content column happened to need; that made the
   image only as big as a couple of short text lines allowed). Height
   still derives from aspect-ratio:2/3 off that fixed width (360px), not
   the other way around now — the row no longer needs align-items:
   stretch to make this work. Since this image is often taller than the
   row+bio text needs, .team-tile-content is explicitly
   justify-content:flex-start (top-aligned, per feedback — a brief
   justify-content:center pass was tried the same session and reverted)
   so the text sits flush at the top of the card next to the image's own
   top edge, with any leftover height below it rather than centered
   beside the image's vertical middle.
   No team has a real photo/logo asset yet except McCarthy (unlike
   Ambassadors, where 11 of 13 do) — every OTHER .team-tile-photo uses
   the .placeholder modifier; the non-placeholder path (an inline
   background-image style, same convention .ambassador-card-photo uses)
   is what McCarthy's own tile uses.
   Flag added (2026-09-09) — .team-tile-row is now a flex row (flag +
   name/country stack), same structure as .ambassador-card-footer's own
   flag+name-group row, not the plain 2-line-only stack it started as.
   McCarthy gets a real flag (USA); Teams 02-04 get
   .team-tile-flag.placeholder (a plain bordered box, no image — their
   country is genuinely TBC, unlike Ambassadors' Cian O'Connor/Tom
   Wachman, who ARE a known nationality just missing a photo asset).
   Name/country font-size/line-height/margin values are copied directly
   from .ambassador-card-name/.ambassador-card-country (14px/700/
   line-height:1 and 11px/400/line-height:1/margin-top:1px) — same
   tuning already verified against Web 2.0's own source there, no reason
   to re-derive it for what's visually the same identity-label pattern. */
.team-tile {
  display: flex;
  align-items: stretch;
  border: 0.5px solid var(--border-strong);
  background: var(--surface-1);
  overflow: hidden;
}
.team-tile-photo {
  flex: 0 0 auto;
  width: 240px;
  aspect-ratio: 2 / 3;
  background-color: var(--nav-solid-bg);
  background-size: cover;
  background-position: center;
}
/* Full border on all 4 sides (not just the inward-facing edge) even
   though 3 of them coincide with .team-tile's own solid outer border —
   a single edge next to an otherwise-bordered white fill read as too
   subtle to register as "placeholder" at a glance; the full outline
   matches this site's other placeholder boxes' own clear signature
   (.headshot-placeholder/.logo-placeholder) instead. Solid, not dashed
   (2026-09-09) — dashed borders don't match PJL brand guidelines,
   sitewide, not just this one rule. */
.team-tile-photo.placeholder {
  background-color: var(--surface-0);
  border: 0.5px solid var(--border-strong);
}
.team-tile-content {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
}
.team-tile-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px;
  border-bottom: 0.5px solid var(--border-strong);
}
/* Real flag (McCarthy's USA) is an <img>; a TBC team's flag is a plain
   <div> with this same class plus .placeholder — no country to show a
   real flag for, so a bordered empty box stands in instead, same
   solid-border wireframe convention as every other not-yet-available
   image on the site. */
.team-tile-flag {
  flex: 0 0 auto;
  width: 36px;
  height: 24px;
  object-fit: cover;
  border: 0.5px solid var(--border-strong);
}
.team-tile-flag.placeholder {
  background-color: var(--surface-0);
}
.team-tile-name-group {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
}
.team-tile-name {
  margin: 0;
  font-family: "PJL Sans", -apple-system, sans-serif;
  font-size: 14px;
  font-weight: 700;
  line-height: 1;
  color: var(--brand-navy);
  text-transform: uppercase;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.team-tile-country {
  margin: 1px 0 0;
  font-family: "PJL Sans", -apple-system, sans-serif;
  font-size: 11px;
  font-weight: 400;
  line-height: 1;
  color: var(--text-secondary);
  text-transform: uppercase;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.team-tile-bio {
  margin: 0;
  padding: 12px;
  font-size: 13px;
  color: var(--text-secondary);
}

/* Hero treatment — full content width (matching the article text below
   it, not floated/narrow), fixed 40vh height. All body content (title,
   byline, paragraphs) stacks below it in normal block flow rather than
   wrapping beside it. */
.article-image {
  width: 100%;
  height: 40vh;
  margin: 0 0 16px;
}

/* Plain text link — e.g. a "More News" link beside a section heading.
   Styled to match .main-nav's own .nav-item typography/color (both sit
   on the same brand-navy fill on Home); no button chrome (see .card-cta
   for the button-styled CTA variant). */
.text-link {
  font-size: 12px;
  color: var(--nav-solid-text);
  text-decoration: none;
}
.text-link:hover {
  color: var(--nav-solid-hover);
}

/* Row pairing a section heading with a trailing .text-link (e.g. Home's
   "Latest News" / "More News"). Restyled to match Web 2.0's own
   .module-label-bar exactly (2026-09-09) — that project's own reusable
   eyebrow-style section header (used there for "Latest News"/"Our
   Partners"/etc: PJL Sans bold uppercase, not PJL Display italic; 14px,
   not 16px; centered baseline via align-items:center, not
   text-baseline; 24px top / 8px bottom margin, its own deliberately
   larger section-break spacing, not the 12px this rule used before).
   Color is brand-navy directly on the base rule now (2.0's own
   .module-label-bar is written for a light surface already, no
   dark-page fallback needed the way this rule's own previous
   brand-white default did) — still fine since this row currently only
   ever appears inside .home-news-section's own white-500 band. */
/* 16px left/right padding, same rule as .main-nav-inner/.footer-row-inner:
   "Latest News"/"More News" sit directly on the page (no module box of
   their own), so they need this same extra inset beyond content bounds
   rather than sitting flush at a module-edge level. */
.section-heading-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 24px 0 8px;
  padding: 0 16px;
  font-family: "PJL Sans", -apple-system, sans-serif;
  font-size: 14px;
  font-weight: 700;
  color: var(--brand-navy);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
/* .th's own base rule (above) directly sets font-size/font-weight on
   itself, which wins over the ROW's own inherited values for those
   two specific properties (font-weight in particular isn't inherited
   at all when a descendant sets its own value) — re-asserted here so
   the label actually renders bold/14px like the rest of the row,
   not .th's own default 500/14px. */
.section-heading-row .th {
  font-size: 14px;
  font-weight: 700;
}
/* Matches .module-label-bar .section-label-bar-action in Web 2.0 —
   the parent row's own uppercase shouldn't apply to the trailing
   action link. */
.section-heading-row .text-link {
  text-transform: none;
}
/* Full-bleed white-500 band around "Latest News" (2026-09-09). Same
   width:100vw + negative-margin breakout as every other full-bleed bar
   on the site, with padding-left/right:var(--content-edge) instead of
   .section-heading-row's own 16px so its heading/grid still land at
   the normal content-bounds inset, not the true viewport edge.
   .section-heading-row's own base colors (--brand-white heading,
   --nav-solid-text link) assume the page's own dark navy fill showing
   directly behind them — inside this now-white band they'd be
   near-invisible, so both are overridden to dark navy here, scoped to
   only this wrapper (.section-heading-row has no other page using it
   yet, but scoping keeps this correct if that changes). */
.home-news-section {
  width: 100vw;
  margin-left: calc(50% - 50vw);
  padding: 24px var(--content-edge);
  /* --surface-0 (2026-09-09; was --brand-white) — "match the .page-
     light fill color" specifically, i.e. body.light-page's own
     background token, not just any similar-looking white/light shade. */
  background: var(--surface-0);
  /* 100px gap to the Home Content blocks below (2026-09-09) — scoped
     to this element specifically (not a margin-top on .home-content-
     block, which would also land BETWEEN each of those 5 stacked
     blocks, on top of their own 400px gap — not asked for). */
  margin-bottom: 100px;
}
.home-news-section .section-heading-row {
  padding: 0;
}
/* .section-heading-row's own base color (navy) already matches here —
   no Home-specific color override needed any more now that the base
   rule matches Web 2.0's .module-label-bar directly (a light-surface
   style already, not the old dark-page-first default). */
/* Matched to Web 2.0's own "See All News" link (that project's Home,
   .section-label-bar-action.link-orange — 2026-09-09): bold, orange-500
   default, navy-500 on hover, no underline/uppercase. Web 2.0's own
   comment on .link-orange calls this "the default (any plain page/
   module/card surface)" — i.e. orange-on-white is this site's own
   established convention already, not a new contrast risk, so no
   dark-navy fallback needed here the way the heading text above still
   uses one. */
.home-news-section .text-link {
  color: var(--brand-orange);
  font-weight: 700;
}
.home-news-section .text-link:hover {
  color: var(--brand-navy);
}

/* Generic horizontal rule between page sections (e.g. a News Item's
   headline and its byline/body). */
.divider {
  border: none;
  border-top: 0.5px solid var(--border-strong);
  margin: 16px 0;
}

/* Horizontal scrolling row (carousels) with edge fade.
   The fade overlays live on the outer (non-scrolling) .carousel wrapper —
   only .carousel-track scrolls — so `right/left: 0` stays pinned to the
   visible viewport edge instead of drifting with scroll position. */
.carousel {
  position: relative;
  border-radius: 0;
  margin-bottom: 12px;
}
.carousel-track {
  display: flex;
  align-items: center;
  gap: 12px;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
}
.carousel-track::-webkit-scrollbar {
  display: none;
}
.carousel-item {
  flex: 0 0 auto;
  min-width: 200px;
  scroll-snap-align: center;
}
.carousel-fade {
  position: absolute;
  top: 0;
  width: 36px;
  height: 100%;
  pointer-events: none;
}
.carousel-fade.left { left: 0; background: linear-gradient(to right, var(--surface-0), transparent); }
.carousel-fade.right { right: 0; background: linear-gradient(to left, var(--surface-0), transparent); }

/* Responsive breakpoints (Tailwind-aligned, mobile-first min-width):
   sm: 640px · md: 768px · lg: 1024px · xlg: 1280px */

/* Sitewide navigation — PJL Display Bold (upright), uppercase, spaced
   by .main-nav-items' own gap (no padding/dividers needed per item).
   Web 1.1 has no Eyebrow / Utility nav and no More overflow menu — all
   primary sections are direct, always-visible nav items. */
.nav-item,
.nav-item-toggle {
  font-family: "PJL Display", -apple-system, sans-serif;
  font-style: italic;
  font-weight: 700;
  font-size: 14px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  color: inherit;
  text-decoration: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* Main / Primary nav — solid treatment. Sticky: stays pinned to the top
   of the viewport on scroll. A direct child of <body> (not .page), so
   its fill is naturally full-bleed to the true viewport edges with no
   offset math needed. Bar container ported from Web 2.0's current
   main-nav (2026-09-03): explicit height (was logo-driven), a
   border-bottom, and --content-edge-based inset on .main-nav-inner
   instead of max-width+margin:auto (which silently stops centering
   below the 1080px content-bounds floor — see --content-edge's own
   comment). Nav CONTENT is intentionally NOT ported — Web 1.1 keeps its
   own 6 items and the Teams/Competition/About PJL click-to-open
   dropdowns with a caret (below), not Web 2.0's 5-items-plus-More
   pattern. */
.main-nav {
  height: 64px;
  border: 0.5px solid var(--nav-solid-bg);
  border-bottom: none;
  border-radius: var(--radius);
  background: var(--nav-solid-bg);
  position: sticky;
  top: 0;
  z-index: 30;
}
.main-nav-inner {
  height: 100%;
  padding: 0 var(--content-edge);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
/* Fixed height:38px, width:auto (2026-09-09, reverted back from a
   width:var(--rail-x)/height:auto approach tried earlier the same
   session) — matches Web 2.0's own .main-nav-logo exactly ("i want 1.1
   to match the 2.0 size"), rendering at the mark's native 150:46 ratio
   (~123.9px wide at 38px tall) rather than being sized off
   .pjl-rail-compact's own lead-slot width. .main-nav itself keeps its
   own explicit height unchanged by this ("no increase in main-nav
   height") — 64px now comfortably fits a 38px logo with room to spare,
   centered via .main-nav-inner's align-items:center. */
.main-nav-logo {
  display: block;
  height: 38px;
  width: auto;
}
.main-nav-items {
  display: flex;
  align-items: center;
  gap: 20px;
  color: var(--nav-solid-text);
  flex-wrap: wrap;
}
.main-nav .nav-item:hover,
.main-nav .nav-item-toggle:hover { color: var(--nav-solid-hover); }
.main-nav .nav-item svg,
.main-nav .nav-item-toggle svg { transform: skewX(-12deg); flex: 0 0 auto; }

/* Dropdown-capable nav item — Teams, Competition, About PJL each carry
   one, built from a hidden checkbox + label (":checked" shows the
   submenu) rather than a real link, since opening the submenu replaces
   direct navigation to that section's first tab. Mutual exclusion
   (opening one closes any other), click-outside-to-close, and click-
   again-to-close are enforced by main-nav.html's own <script> — CSS
   alone (including a pure radio-group version) did not reliably hold
   only-one-open in testing, so this needs the JS. Popup verified
   2026-09-09 against Web 2.0's ACTUAL RENDERED "More" menu (not just its
   source — the base `.dropdown-menu` rule's border-color is
   --border-strong, but a more specific `.main-nav .dropdown-menu` rule
   overrides it to --nav-outline-border for exactly this nav-nested
   case, which is what really renders; missed that override on the first
   pass). Now matches exactly: white surface, navy-outline border
   (--nav-outline-border), same shadow/200px min-width/z-index (40,
   above .main-nav's own 30), right-justified to the parent item, item
   text color (--nav-outline-text), and — since #more-menu's items are
   forced uppercase in Web 2.0's own CSS — item text is now uppercase at
   14px/0.04em letter-spacing too (inherited there from `.main-nav
   .nav-item`'s own font rule, since `.dropdown-menu-item` itself sets no
   font-size/letter-spacing of its own). The CARET TOGGLE ITSELF stays
   Web 1.1's own (kept deliberately, not Web 2.0's hamburger-style More
   button); `white-space: nowrap` also stays — Web 1.1's own child-page
   labels (e.g. "Team Ownership Info") are long enough, now uppercase and
   14px, that dropping nowrap risks an awkward wrap inside the 200px
   popup (the box just grows past 200px to fit instead, same as it would
   in Web 2.0's own More menu).

   TRYING: rollover (hover/focus) also opens the submenu, in addition to
   the click/checkbox mechanism above — mouse users get hover-to-open;
   the checkbox click-to-open/close still works underneath as a fallback
   for touch and keyboard. Hover's own mutual exclusion is automatic
   (the pointer can only be over one item at a time), independent of the
   click path's JS-enforced exclusivity. If this doesn't feel right,
   dropping the two :hover/:focus-within rules below reverts to
   click-only. */
.nav-item-wrap { position: relative; }
.submenu-toggle-checkbox {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}
.submenu {
  position: absolute;
  top: 100%;
  right: 0;
  margin-top: 8px;
  min-width: 200px;
  background: var(--surface-1);
  border: 0.5px solid var(--nav-outline-border);
  border-radius: var(--radius);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
  display: none;
  flex-direction: column;
  padding: 8px 0;
  z-index: 40;
  text-align: left;
}
/* Invisible hover-bridge over the 8px margin-top gap above — without
   this, moving the pointer from the nav item down into the submenu
   crosses a dead zone with nothing hovered, dropping :hover and hiding
   the menu before it can be reached. A pseudo-element still counts as
   part of .submenu for :hover purposes, so this keeps hover continuous
   across the gap without changing the visible layout. */
.submenu::before {
  content: "";
  position: absolute;
  top: -8px;
  left: 0;
  right: 0;
  height: 8px;
}
.submenu-toggle-checkbox:checked ~ .submenu,
.nav-item-wrap:hover .submenu,
.nav-item-wrap:focus-within .submenu {
  display: flex;
}
.submenu a {
  display: block;
  color: var(--nav-outline-text);
  font-family: "PJL Sans", -apple-system, sans-serif;
  font-style: normal;
  font-weight: 700;
  font-size: 14px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  text-decoration: none;
  white-space: nowrap;
  padding: 8px 16px;
}
.submenu a:hover {
  background: var(--nav-outline-hover-bg);
}
.submenu-toggle-checkbox:checked ~ .nav-item-toggle svg,
.nav-item-wrap:hover .nav-item-toggle svg,
.nav-item-wrap:focus-within .nav-item-toggle svg {
  transform: skewX(-12deg) rotate(180deg);
}

/* Hamburger trigger — hidden at sm (640px) and up, where .main-nav-items
   shows normally. Below sm, .main-nav-items is hidden and this is the
   only way to reach the nav (opens .nav-sheet below). */
.nav-hamburger {
  display: none;
  background: none;
  border: none;
  color: var(--nav-solid-text);
  padding: 8px;
  cursor: pointer;
}
@media (max-width: 639.98px) {
  .main-nav-items { display: none; }
  .nav-hamburger { display: flex; align-items: center; }
}

/* Full-screen nav sheet — styled to match Web 2.0's implementation.
   Flat list (no nested submenus) covering every destination the
   horizontal nav + its 3 dropdowns reach, since a mobile sheet flattens
   rather than nests. position: fixed anchors both to the true viewport
   regardless of .page's own max-width. */
.nav-sheet-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(2, 22, 42, 0.85);
  z-index: 1000;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.2s, visibility 0.2s;
}
.nav-sheet-backdrop.open {
  opacity: 1;
  visibility: visible;
}
.nav-sheet {
  position: fixed;
  inset: 0;
  z-index: 1001;
  background: var(--surface-1);
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  transform: translateX(100%);
  transition: transform 0.2s;
}
.nav-sheet.open {
  transform: translateX(0);
}
.nav-sheet-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex: 0 0 auto;
  padding: 16px;
  border-bottom: 0.5px solid var(--border-strong);
}
.nav-sheet-logo {
  display: block;
  height: 40px;
  width: auto;
}
.nav-sheet-close {
  font-size: 28px;
  line-height: 1;
  background: none;
  border: none;
  color: var(--brand-navy);
  cursor: pointer;
  padding: 0;
}
.nav-sheet-items {
  display: flex;
  flex-direction: column;
  padding: 8px 0;
}
.nav-sheet-item {
  display: block;
  padding: 14px 16px;
  font-size: 15px;
  color: var(--nav-outline-text);
  text-decoration: none;
}
.nav-sheet-item:hover {
  background: var(--nav-outline-hover-bg);
}
.nav-sheet-item-divider {
  border-top: 0.5px solid var(--border);
  margin-top: 8px;
  padding-top: 22px;
}

/* Contextual tab nav — sub-navigation for a main-nav item with multiple
   child pages (Teams, Competition, About PJL). Each is its own component
   (teams-tabs.html, competition-tabs.html, about-pjl-tabs.html) so the
   tab set is scoped to that section; the script in each highlights
   whichever tab matches the current page. */
/* Sticky + full-bleed. Base top:96px is Web 1.1's own .main-nav (64px,
   was 55.5px before 2026-09-09) plus .page-title-bar (32px) — the
   plain fallback for a tab bar with no .page-title before it, which no
   longer happens on any real page (every tabbed page now has
   .page-title between the bar and this), but kept as the base value
   the same way Web 2.0's own source does. z-index one below
   .page-title-bar's own 29. Full-bleed the same
   way .page-title-bar does (width:100vw breakout, padding reapplying
   --content-bounds-equivalent spacing) rather than a border-bottom that
   would otherwise get clipped by this row's own overflow-x:auto — a
   descendant border/pseudo-element can't paint past a scroll
   container's own box, only the box's own edge can. An explicit
   background is needed now that content scrolls underneath it. Ported
   from Web 2.0's companion change to its own .page-title-bar port. */
.tab-nav {
  position: sticky;
  top: 96px;
  z-index: 28;
  background: var(--surface-0);
  display: flex;
  flex-wrap: nowrap;
  gap: 4px;
  overflow-x: auto;
  scrollbar-width: none;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-bottom: 16px;
  padding-left: var(--content-edge);
  padding-right: var(--content-edge);
  border-bottom: 0.5px solid var(--border-strong);
}
/* Real sticky offset for every actual Teams/Competition/About PJL page:
   .page-title now always sits directly between .pjl-rail-compact and
   this — no padding-top compensation needed (.page-title's own 16px
   trailing space is PADDING, part of its own filled box; see that
   rule's own comment), just a taller top offset so this row picks up
   exactly where .page-title's own box ends. 143.6px = 80px (.main-nav
   + .pjl-rail-compact) + 63.6px (.page-title's own rendered height at
   36px font-size: 39.6px line box + 16px padding-top + 8px
   padding-bottom). 139.2px is the same sum at .page-title's mobile
   32px font-size (35.2px line box instead). (Was 151.1/146.7px when
   .page-title followed the taller 32px .page-title-bar instead, then
   139.1/134.7px while .pjl-rail-compact was still 20px tall, then
   135.1/130.7px once main-nav's own height changed to this rule's
   own reference point instead of the rail — this round shifted both
   up another 8.5px when main-nav itself grew from 55.5px to 64px on
   2026-09-09.) */
.page-title + .tab-nav {
  top: 143.6px;
}
@media (max-width: 639.98px) {
  .page-title + .tab-nav {
    top: 139.2px;
  }
}
.tab-nav::-webkit-scrollbar {
  display: none;
}
.tab-item {
  padding: 8px 16px;
  font-size: 12px;
  color: var(--text-secondary);
  text-decoration: none;
  text-transform: uppercase;
  white-space: nowrap;
  border-bottom: 2px solid transparent;
  margin-bottom: -0.5px;
}
.tab-item:hover { color: var(--text-primary); }
.tab-item.active {
  color: var(--text-primary);
  font-weight: 700;
  border-bottom-color: var(--nav-solid-bg);
}

/* Dark variant — pairs with .page-title-dark the same way the light
   .tab-nav pairs with .page-title's own light default, for a tabbed
   page whose whole header zone (rail + title + tabs) is dark. Reuses
   --nav-solid-* tokens (main-nav's own navy-background text-color
   family) rather than inventing new ones — .tab-item's inactive/hover/
   active states just need the same light-on-navy treatment main-nav's
   own items already use. Active state uses --brand-orange for the
   underline (not --nav-solid-text/near-white, which .tab-item.active
   already uses for its TEXT) — orange is this site's one consistent
   "primary emphasis" accent (page-title-bar's fill, .pjl-rail-compact's
   lead/trailing slots, the breaking bar's badge), so the active tab's
   own indicator reads as the same accent language rather than a plain
   light/dark inversion. */
.tab-nav.tab-nav-dark {
  background: var(--brand-navy);
  border-bottom-color: var(--nav-solid-divider);
}
.tab-nav-dark .tab-item {
  color: var(--nav-solid-text-muted);
}
.tab-nav-dark .tab-item:hover {
  color: var(--nav-solid-text);
}
.tab-nav-dark .tab-item.active {
  color: var(--nav-solid-text);
  border-bottom-color: var(--brand-orange);
}

/* Footer — two stacked full-bleed rows, each the height of the original
   single-row footer (same 12px/16px padding, same 11px font-size).
   Each row is its own direct child of <body> (not .page, and after it
   rather than inside it), so each independently fills to the true
   viewport edges with no offset math needed, and the bottom row sits
   flush at the true bottom edge with no gap below it. .footer-row-inner
   re-applies .page's own max-width/centering so the footer's content
   width is unchanged, on both rows. */
.footer-row {
  border-radius: var(--radius);
  font-size: 14px;
}
.footer-row-social {
  background: var(--brand-sand);
  color: var(--brand-navy);
  height: 200px;
}
/* Taller row (2026-09-09) keeps its existing content (icons + Privacy
   Policy link) justified to the bottom rather than re-centering it in
   the new 200px height — overrides .footer-row-inner's own base
   align-items:center for this row only; .footer-row-copyright's own
   (shorter, unchanged) row keeps the base centered behavior. */
.footer-row-social .footer-row-inner {
  align-items: flex-end;
  height: 100%;
}
.footer-row-copyright {
  background: var(--brand-white);
  color: var(--brand-navy);
}
.footer-row-inner {
  max-width: var(--content-bounds);
  margin: 0 auto;
  padding: 12px 16px;
  display: flex;
  align-items: center;
}
.footer-row .footer-row-item { flex: 1; }
.footer-row .footer-row-item.align-start { text-align: left; }
.footer-row .footer-row-item.align-center { text-align: center; }
.footer-row .footer-row-item.align-end { text-align: right; }
.footer-row-copyright .footer-row-inner { justify-content: center; }
/* Copyright line — constrained + bolded (2026-09-09). .footer-row-inner
   (above) already caps at --content-bounds and centers its child, so a
   plain 70% here resolves against that same real content width
   directly (no full-bleed ancestor in the way, unlike .news-hero-text's
   own similar case) — max-width alone would just left-align a
   multi-line wrap though, so text-align:center is added too, keeping
   wrapped lines centered under the single-line case's own already-
   centered position. */
.footer-copyright-text {
  max-width: 60%;
  font-weight: 700;
  text-align: center;
}
.footer-row-item a:hover,
.footer-row-item svg:hover { opacity: 0.7; }
/* Privacy Policy link and social icon links reset to plain footer text
   color (no default link blue/underline). */
.footer-row-item a {
  color: inherit;
  text-decoration: none;
}
/* Bolded (2026-09-09) — scoped to just the Privacy Policy link, not the
   social icon anchors that share .footer-row-item a's own base rule
   above (bolding an icon-only link with no visible text would be a
   no-op anyway, but this stays precise about what it targets). */
.footer-privacy-link {
  font-weight: 700;
}

/* Module categories — color-only overlays from ../pjl-brand/pjl-color-palette.md.
   Combine with .module / .module-upcoming (e.g.
   class="module cat-editorial") wherever a module needs a category color.
   Reusable sitewide, not Home-specific.
     Editorial / Content Aggregation (+ Core) -> Navy
     Commerce                                -> Emerald
     Partnerships                            -> Amber
   Promotional Cross-Links intentionally has no category class here — its
   color is contextual to each link's target, decided per instance.
   Child .th/.ts/.ts-muted text needs style="color:inherit" to pick up the
   category color, matching the existing .module-upcoming convention. */
:root {
  --cat-editorial-bg: #EEF6FF;         /* navy-25 */
  --cat-editorial-border: #0C2237;     /* navy-500 */
  --cat-editorial-text: #02162A;       /* navy-700 */

  --cat-commerce-bg: #DFFFE4;          /* emerald-25 */
  --cat-commerce-border: #15803D;      /* emerald-500 */
  --cat-commerce-text: #005222;        /* emerald-700 */

  --cat-partnerships-bg: #FFF2EC;      /* amber-25 */
  --cat-partnerships-border: #B45309;  /* amber-500 */
  --cat-partnerships-text: #753200;    /* amber-700 */
}
.cat-editorial {
  background: var(--cat-editorial-bg);
  border-color: var(--cat-editorial-border);
  color: var(--cat-editorial-text);
}
/* Cancels .cat-editorial's own navy-25 fill/border specifically for
   News cards (2026-09-09, ported from Web 2.0) — same single-class
   specificity as .cat-editorial's own rule above, so it has to come
   AFTER that rule in source order to actually win; placed here rather
   than back at .news-card's own earlier definition for exactly that
   reason (a same-specificity override declared BEFORE the rule it's
   meant to cancel silently loses — confirmed this was actually
   happening, not just a risk, when .news-card.image-left cards were
   still rendering with a visible navy-25 tint despite border/
   background:none being set on .news-card itself, just in the wrong
   place in the file). Web 2.0's own .news-card rule doesn't have this
   problem because its .news-card definition already comes after
   .cat-editorial's in that project's file. */
.news-card {
  border: none;
  background: none;
}
.cat-commerce {
  background: var(--cat-commerce-bg);
  border-color: var(--cat-commerce-border);
  color: var(--cat-commerce-text);
}

/* Compact variant of the Ticket Waitlist promo — row layout (text left,
   CTA right) at roughly half the height the plain stacked .cat-commerce
   promo runs at, keeping the CTA visible rather than clipping it. Used
   on Home and Tour/Calendar. Base .cat-commerce is untouched. */
.ticket-waitlist-compact {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 8px 16px;
  min-height: 0;
}
.ticket-waitlist-compact .card-cta {
  margin: 0;
  flex-shrink: 0;
}
/* Wrapper around the actual promo card (2026-09-09; outer/inner
   split), used identically on Tour Calendar AND Home now ("match
   tickets module to tickets module on calendar page - they should
   always match each other") — an OUTER box, page-fill-colored
   (--brand-navy, matching both pages' own body fill, neither has
   .light-page) and sized to include a 16px trailing gap; the INNER div
   (plain `.module.cat-commerce.ticket-waitlist-compact`, height set to
   80px via inline style since that shared class can't carry this
   height on its own) holds the actual green card content, filling
   exactly this box's own 80px content-height (border-box: 96px outer
   height − 16px padding-bottom = 80px).
   Not sticky (2026-09-09 — "let's just remove all stickyness from the
   leg-dividers and tickets"; was sticky earlier the same day, with the
   gap-masking padding-bottom+background trick built specifically to
   fix scroll bleed-through between this bar and a simultaneously-stuck
   .leg-divider-1). Kept the outer/inner split and the background fill
   even though nothing here is stuck any more — no harm in it (still
   just reads as the page's own navy showing through the gap), and it's
   simpler to leave than to unwind back to a single-tier card, given
   this is very likely to go sticky again. */
.ticket-waitlist-sticky {
  height: 96px;
  padding-bottom: 16px;
  background: var(--brand-navy);
}
.cat-partnerships {
  background: var(--cat-partnerships-bg);
  border-color: var(--cat-partnerships-border);
  color: var(--cat-partnerships-text);
}
