/* World Water Skiers — design shell (Stage 1 skeleton)
 * Brand values pulled directly from the live site's compiled
 * assets/css/desktop.css / main.css (header #00162b, accent #00a0df) so the
 * new Bootstrap 5 shell reads the same as the current Bootstrap 4 site.
 * Per-page/per-feature styling is ported alongside each feature in later stages.
 */

/* Defensive fallback for Bootstrap's .ratio-NxN utilities (the padding-top
   hack) — every child of .ratio is position:absolute, so if the jsdelivr CDN
   stylesheet is ever blocked/slow, these boxes collapse to 0 height and
   whatever's inside (often an iframe embed) renders as blank. Native
   aspect-ratio gives the same box even before/without Bootstrap's CSS. */
.ratio-1x1 { aspect-ratio: 1 / 1; }
.ratio-4x3 { aspect-ratio: 4 / 3; }
.ratio-16x9 { aspect-ratio: 16 / 9; }
.ratio-21x9 { aspect-ratio: 21 / 9; }

:root {
    --wws-navy: #00162b;
    --wws-blue: #00a0df;
    --wws-blue-rgb: 0, 160, 223;
    --wws-blue-hover: #0088be;  /* ~15% darker — Bootstrap's usual hover mix */
    --wws-blue-active: #0078a7; /* ~25% darker — Bootstrap's usual active mix */

    /* CARD SHADOW — the one look for every light/white card, taken from the Tournaments page: a wide, very
       faint halo on the light-grey page (#f8f8f8). Rule: a light or white card gets this shadow, no border,
       unless it sits on a dark background. Borders are for clickable things (buttons, chips, fields); rows in
       a list are separated by hairlines. Bootstrap's .shadow-sm (used on ~145 cards) is pointed at it below. */
    --wws-card-shadow: 0 4px 10px 4px rgba(0, 15, 30, .028);
    --wws-page-grey: #f8f8f8;
    /* Bootstrap's three shadow classes, re-pointed so the whole site follows one scale:
       .shadow-sm = the card shadow; .shadow = a stronger one for small raised things (logo tiles, toasts);
       .shadow-lg = the biggest, for sign-in cards and anything floating over the page. */
    --bs-box-shadow-sm: 0 4px 10px 4px rgba(0, 15, 30, .028);
    --bs-box-shadow: 0 4px 16px rgba(0, 15, 30, .10);
    --bs-box-shadow-lg: 0 16px 40px rgba(0, 15, 30, .14);
}
/* .shadow-sm on things that are NOT cards (sticky bars, full-width sections) keeps a slim shadow */
.wws-site-sticky-nav.shadow-sm, section.shadow-sm { box-shadow: 0 1px 4px rgba(0, 22, 43, .10) !important; }
.wws-pane-grey { background: var(--wws-page-grey); }

body {
    margin: 0;
    padding: 0;
    /* Dark navy shows through anywhere content doesn't cover it (e.g. behind
       the footer) — confirmed against the live site: footer itself has no
       background of its own, it just sits on this. */
    background: var(--wws-navy);
    color: #444;
    font-family: "Plus Jakarta Sans", sans-serif;
}

a {
    color: var(--wws-blue);
}

/* Form field labels — sitewide, same convention as wws-admin's own
   .form-label (admin.css), so a form looks the same whether it's in
   my-account or the admin portal. Overrides Bootstrap's stock .form-label
   (plain margin-bottom, no type styling). */
.form-label {
    font-size: .75rem;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: #64748b;
    margin-bottom: .3rem;
}

/* Placeholder text, sitewide — ported from clubs' app.css. Bootstrap's
   default placeholder color reads as normal body text at a glance; this
   dims it so a placeholder never looks like a real value. */
.form-control::placeholder,
.form-select::placeholder,
textarea::placeholder,
input::placeholder {
    color: #dee2e6;
    opacity: 1;
}

/* ── Repeater field (assets/js/repeater.js) ───────────────────────────────
   The canonical "add/remove row" component — every repeater field sitewide
   (Career Highlights, Sponsors' Other Sponsors, Coaching Clinics, Family
   Members, and any future one) uses this same markup contract + JS instead
   of hand-rolling its own add/remove logic and button styling per page,
   which is how this drifted before (see project memory on this):
     <div class="wws-repeater" data-max="N" data-min="1" data-next-index="<?= count($rows) ?>">
       <div class="wws-repeater-rows">
         <div class="wws-repeater-row">...page-specific fields, name="foo[<?=$i?>][bar]"...
           <button type="button" class="wws-repeater-remove"><i class="bi bi-trash3"></i></button>
         </div>
       </div>
       <button type="button" class="wws-repeater-add" data-template="rowTplId"><i class="bi bi-plus-lg"></i> Add</button>
     </div>
     <template id="rowTplId">...one blank row, name="foo[__INDEX__][bar]"...</template>
   Any row with more than one field needs that real/placeholder index — see
   assets/js/repeater.js's header for the exact bug this avoids (PHP does
   NOT correlate separate foo[][a]/foo[][b] occurrences into one row). A
   single-field row (Family Members) can use plain foo[] on its one field
   instead, no index needed.
   Only the fields INSIDE .wws-repeater-row are page-specific — that's the
   "tweakable for certain purposes" part; the add/remove mechanics and the
   button look are not supposed to be re-decided per page. An extra utility
   class alongside .wws-repeater-add/.wws-repeater-remove (e.g. for one-off
   layout spacing) is fine; overriding color/border isn't the intended
   extension point. */
.wws-repeater-add {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    background: transparent;
    border: 1px solid var(--wws-blue);
    color: var(--wws-blue);
    border-radius: .375rem;
    padding: .25rem .6rem;
    font-size: .82rem;
    font-weight: 500;
    line-height: 1.5;
    cursor: pointer;
    transition: background-color .15s, color .15s;
}
.wws-repeater-add:hover { background: var(--wws-blue); color: #fff; }

/* Plain icon button, no border/box — same bare-icon-button convention as
   wws-admin's .btn-edit/.btn-delete (admin.css), just red by default rather
   than only-on-hover since "remove this row" should read as available at a
   glance. Must never sit inside a Bootstrap .input-group (its child-styling
   stretches/re-borders anything inside it) — put it as a flex sibling of
   the row's fields instead, e.g. Family Members' row wraps its
   .input-group and this button in one d-flex align-items-center parent. */
.wws-repeater-remove {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    color: #dc3545;
    padding: .3rem .45rem;
    border-radius: 5px;
    line-height: 1;
    font-size: 1.1rem;
    flex-shrink: 0;
    cursor: pointer;
    transition: color .15s, background-color .15s;
}
.wws-repeater-remove:hover { color: #b02a37; background: rgba(220, 53, 69, .08); }

/* Text-sizing convention for this whole site: the old theme's own
   .font-size-Npx utility classes (assets/css/common.css on the live site),
   ported verbatim — same class names, same rem values, not a fresh
   Bootstrap-equivalent guess. The old theme's h1–h6 tags were picked for
   whatever size looked right in the page builder, not for a real semantic
   hierarchy, so matching "h2 to h2" between old and new pages is the wrong
   comparison — matching by which .font-size-Npx class wraps the text is the
   right one. Default to these over Bootstrap's fs-1..fs-6 or a bare heading
   tag's default size on every page, not just the ones already using them
   (Tournament, Pro Events, Tournaments-archive) — extend here as more
   pages get audited, never redefine one of these values per-feature again. */
.font-size-8px  { font-size: .6rem; }
.font-size-10px { font-size: .8rem; }
.font-size-11px { font-size: .9rem; }
.font-size-12px { font-size: 1rem; }
.font-size-14px { font-size: 1.2rem; }
.font-size-16px { font-size: 1.4rem; }
.font-size-18px { font-size: 1.5rem; }
.font-size-20px { font-size: 1.6rem; }
.font-size-22px { font-size: 1.8rem; }
.font-size-24px { font-size: 2rem; }
.font-size-26px { font-size: 2.2rem; }
.font-size-28px { font-size: 2.3rem; }
.font-size-30px { font-size: 2.45rem; }

/* Base h1–h4 size/weight — the old theme's OWN global default (its compiled
   desktop.css: `h1,.h1{font-size:$font-size-28px;font-weight:700}`,
   `h2,.h2{...22px...}`, `h3,.h3{...14px...}`, `h4,.h4{...12px...}` — same
   $font-size-Npx SCSS variables backing the .font-size-Npx classes above,
   confirmed via direct source read against athlete/tournament pages with no
   exception found), which this project's port never carried over — every
   bare <h1>-<h4> tag or .h1-.h4 utility class across the whole site has
   been silently falling back to Bootstrap's own (wrong) defaults instead.
   This is a DEFAULT, not an override: any element that already carries an
   explicit .font-size-Npx class (the per-instance audit convention noted
   above, since not every heading-shaped bit of text on the old site is
   literally wrapped in an h-tag) keeps winning via that class's own
   selector — this only fixes tags/utility-classes that were completely
   unstyled before. h5/h6 excluded — the old theme's own reset doesn't
   touch them either. */
h1, .h1 { font-size: var(--wws-h1, 2.3rem); font-weight: 700; }
h2, .h2 { font-size: var(--wws-h2, 1.8rem); font-weight: 700; }
h3, .h3 { font-size: var(--wws-h3, 1.2rem); font-weight: 700; }
h4, .h4 { font-size: 1rem; font-weight: 700; }

/* Phones — the old theme's mobile.scss sets its own, smaller heading scale
   (h1 22px / h2 16px / h3 12px vs desktop's 28/22/14), mapped to this
   project's rem scale (.font-size-22px = 1.8rem etc.). Done as CSS variables
   on <body> instead of a second set of h1/h2/h3 rules so every existing
   selector's specificity is untouched: component rules and explicit
   .font-size-Npx classes still win exactly as before. h4 left alone — live's
   mobile h4 is 8px, which is unreadable here. */
body.platform-mobile { --wws-h1: 1.8rem; --wws-h2: 1.4rem; --wws-h3: 1rem; }
/* One size for the title on every mobile hero (tournament / ski site / athlete). */
body.platform-mobile .wws-hero-title { font-size: 1.9rem; line-height: 2.1rem; }
/* Tournament tab section headings are .font-size-22px (1.8rem on this project's desktop scale) — on mobile
   they follow the shared h2 size so Shorts / Photos / Results / Schedule / Info headings all match. */
body.platform-mobile #t-tab-content .font-size-22px, body.platform-mobile #t-tab-content .h2 { font-size: 1.25rem; }
/* Small outlined pill used for Refresh on the Results tab (list + detail). */
.wws-refresh-btn { display:inline-flex; align-items:center; gap:.35rem; font-size:12px; font-weight:600; line-height:1; color:#5b6b7c; background:#f4f6f9; border:1px solid #dde3ea; border-radius:100px; padding:6px 12px; cursor:pointer; }
.wws-refresh-btn:hover, .wws-refresh-btn:active { color:#00a0df; border-color:#00a0df; background:#fff; }
.wws-refresh-btn i { font-size:13px; }

/* The old theme's own global override (assets/css/common.css:
   ".text-muted{color:#CCC !important}") — replaces Bootstrap's default
   .text-muted (rgba(33,37,41,.75), a dark charcoal at 75% opacity) with a
   flat, much lighter #ccc everywhere. Confirmed via live computed style on
   the tournament Results tab's "Pro Men"/"Pro Women" division headings
   (rgb(204,204,204) live vs rgba(33,37,41,.75) in this project before this
   fix) — site-wide, not page-specific, same category of miss as the
   .container max-width override found earlier: every already-built page
   using Bootstrap's stock .text-muted anywhere was rendering it too dark. */
.text-muted { color: #ccc !important; }

/* The old theme's own global override (assets/css/common.css:
   ".container{max-width:1400px}", repeated in an unconditional and an
   @media(min-width:1200px) rule) — it replaces Bootstrap's tiered container
   max-widths (540/720/960/1140/1320) with one flat 1400px cap. Confirmed via
   live getBoundingClientRect() measurement on a real tournament page: at a
   1280px viewport the old site's container runs edge-to-edge (1280 wide,
   just 15px side padding) while this project's stock-Bootstrap container was
   boxed to 1140px, throwing off every hero/content element positioned
   relative to the container's right/left edge (e.g. the date-box corner
   badge). Site-wide, not per-page — every already-built page inherits
   Bootstrap's default container sizing and needs this. */
.container { max-width: 1400px; }

/* Bootstrap's default .btn-primary/.text-primary are stock Bootstrap blue
   (#0d6efd) — override via the same --bs-btn-* custom-property pattern
   Bootstrap 5 itself uses, so every default-styled button/focus-ring across
   the whole site (not just hand-picked ones) picks up the brand blue instead.
   Ported from Clubs.worldwaterskiers.com/new-build's app.css. */
.btn-primary {
    --bs-btn-color: #fff;
    --bs-btn-bg: var(--wws-blue);
    --bs-btn-border-color: var(--wws-blue);
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: var(--wws-blue-hover);
    --bs-btn-hover-border-color: var(--wws-blue-hover);
    --bs-btn-focus-shadow-rgb: var(--wws-blue-rgb);
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: var(--wws-blue-active);
    --bs-btn-active-border-color: var(--wws-blue-active);
    --bs-btn-disabled-color: #fff;
    --bs-btn-disabled-bg: var(--wws-blue);
    --bs-btn-disabled-border-color: var(--wws-blue);
}
.text-primary { color: var(--wws-blue) !important; }

/* Same --bs-btn-* override pattern as .btn-primary above, for the outline
   variant — used sitewide (23 spots at last count) and was still rendering
   stock Bootstrap blue since only the solid .btn-primary was covered.
   Ported from Clubs.worldwaterskiers.com/new-build's app.css. */
.btn-outline-primary {
    --bs-btn-color: var(--wws-blue);
    --bs-btn-border-color: var(--wws-blue);
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: var(--wws-blue);
    --bs-btn-hover-border-color: var(--wws-blue);
    --bs-btn-focus-shadow-rgb: var(--wws-blue-rgb);
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: var(--wws-blue);
    --bs-btn-active-border-color: var(--wws-blue);
    --bs-btn-disabled-color: var(--wws-blue);
    --bs-btn-disabled-border-color: var(--wws-blue);
}

/* .bg-primary badges (plan/role/status badges across subscribe.php,
   my-account, wws-admin) and checked checkboxes/switches — both render
   Bootstrap's stock blue by default and aren't covered by the --bs-btn-*
   custom-property trick above (that only works for .btn variants). */
.bg-primary { background-color: var(--wws-blue) !important; }
.form-check-input:checked {
    background-color: var(--wws-blue);
    border-color: var(--wws-blue);
}
.form-check-input:focus {
    border-color: var(--wws-blue);
    box-shadow: 0 0 0 .25rem rgba(var(--wws-blue-rgb), .25);
}

/* .table-hover defaults to Bootstrap's stock grey (rgba(0,0,0,.075)) — this
   was already overridden to a pale brand blue in wws-admin's admin.css, but
   never ported here, so public-facing hoverable tables (claim-wws-id.php /
   subscribe.php's WWS ID lookup results, wws-widgets/sites-widget.php)
   still showed the old grey. Same pattern, same var, just this stylesheet's
   own --wws-blue-rgb name. */
.table-hover {
    --bs-table-hover-bg: rgba(var(--wws-blue-rgb), .08);
}

/* Light-blue Cancel-button style — ported verbatim from
   Clubs.worldwaterskiers.com/new-build's .btn-secondary rule. */
.btn-secondary {
    --bs-btn-color: #3366aa;
    --bs-btn-bg: #eef5ff;
    --bs-btn-border-color: #eef5ff;
    --bs-btn-hover-color: #2255aa;
    --bs-btn-hover-bg: #ddeeff;
    --bs-btn-hover-border-color: #ddeeff;
    --bs-btn-active-color: #2255aa;
    --bs-btn-active-bg: #ddeeff;
    --bs-btn-active-border-color: #ddeeff;
    --bs-btn-disabled-color: #3366aa;
    --bs-btn-disabled-bg: #eef5ff;
    --bs-btn-disabled-border-color: #eef5ff;
}

/* ── Header / nav ─────────────────────────────────────────────────────── */

/* Live site pins the desktop header to a 1200px-wide layout (mobile gets an
   entirely separate template via wws_platform(), not a responsive breakpoint
   here) — min-width matches includes/desktop/part-nav.php's inline style. */
header.header {
    width: 100%;
    height: 50px;
    z-index: 1030;
    position: fixed;
    top: 0;
    background: var(--wws-navy);
}

/* Bootstrap's .container-fluid carries its own 12px left/right padding
   independent of the row's gutter setting — confirmed 0 on the live site,
   which is why the logo sits flush against the header's left edge there. */
header.header .container-fluid {
    padding-left: 0;
    padding-right: 0;
}

header.header .row.menu {
    height: 50px;
}

/* Live site puts .logo and the MENU ul.nav-pills side by side via float:left
   on .logo; flex achieves the same result more predictably here. Bootstrap's
   default flex-basis:0% on .col lets this column get squeezed narrower than
   its content (logo + MENU) by its flex siblings, which forces MENU to wrap
   onto its own line at narrower window widths — flex-shrink:0 + an explicit
   min-width (logo's 136.8px + the MENU item's ~90px, rounded up) stops that
   without touching flex-grow, so it still shares any extra space as before. */
header.header .row.menu > .col:first-child {
    display: flex;
    flex-shrink: 0;
    min-width: 240px;
    align-items: center;
}

/* Mobile's header first column only ever holds an optional back-chevron
   (includes/mobile/part-nav.php), never the desktop logo+MENU pairing the
   240px min-width above was sized for — without this override that
   min-width bled into the mobile header too (same header.header class
   name, no platform scoping on the rule above) and pushed the centered
   logo well right of center. Equal flex-basis with the trailing column
   (also unconstrained) keeps the logo genuinely centered regardless of
   whether the back-chevron is present. */
body.platform-mobile header.header .row.menu > .col:first-child {
    min-width: 0;
    flex-shrink: 1;
}

header.header .logo {
    display: flex;
    align-items: center;
    height: 50px;
    padding: 0 15px;
    background: var(--wws-blue);
    flex-shrink: 0;
}

header.header .logo img {
    height: 30px;
}

/* container-fluid's padding-right:0 above (needed to flush the logo left)
   also flushed the trailing Login/Join-Up/account-dropdown column against the
   right edge — add it back just there, matching the logo's own 15px so both
   edges read symmetrically. */
header.header .row.menu > .col:last-child {
    padding-right: 15px;
}

/* 20px gap after the first item in each nav-pills group — the center nav
   (Athletes...) needs it after the logo+MENU column, and MENU itself needs
   the same gap after the logo. Scoped per-group rather than one blanket
   "li:first-child" rule, since the two groups sit in different columns and
   the wrap bug that made this feel unsafe earlier (see git history) turned
   out to be .container-fluid's own padding, not this margin. */
header.header .col-auto .nav-pills li.nav-item:first-child .nav-link,
header.header .row.menu > .col:first-child .nav-pills li.nav-item:first-child .nav-link {
    margin-left: 20px;
}

#main.site-main {
    padding-top: 50px; /* clear the fixed 50px header */
    min-height: 60vh;
    background: #f8f8f8;
}

header.header .nav-pills .nav-link {
    color: #fff !important;
    font-size: .8rem !important;
    white-space: nowrap;
    text-transform: uppercase;
    letter-spacing: 1.5px;
    line-height: 35px;
    height: 50px;
    font-weight: bold;
    border-radius: 0 !important;
    border: none;
    padding: .5rem;
    background-color: transparent !important;
}

header.header .nav-pills.settings .nav-link {
    font-size: .7rem;
}

/* The Tours/Rankings triggers are <button> (they only ever open a CSS :hover
   panel, they don't navigate) — strip the native button chrome so they read
   identically to the .nav-link anchors next to them. */
header.header button.nav-link {
    font-family: inherit;
    text-align: inherit;
    cursor: pointer;
}

/* Hover dropdown (CSS-only, no jQuery — replaces the BS4 hover-dropdown plugin) */
header.header li.hover-dropdown { position: relative; }
header.header li.hover-dropdown > .dropdown-menu {
    display: block;
    position: absolute;
    top: 50px;
    left: 50%;
    min-width: 230px;
    background: #fff;
    border: none;
    border-radius: 8px;
    box-shadow: rgba(0, 15, 30, .06) 0 16px 24px 0, rgba(0, 15, 30, .02) 0 4px 8px 0;
    padding: 10px 8px;
    margin: 0;
    z-index: 1031;
    text-transform: uppercase;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transform: translateX(-50%) translateY(-8px);
    transition: opacity .25s ease, transform .25s ease, visibility .25s;
}
header.header li.hover-dropdown:hover > .dropdown-menu,
header.header li.hover-dropdown:focus-within > .dropdown-menu {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: translateX(-50%) translateY(0);
}
header.header li.hover-dropdown .dropdown-item {
    color: #333;
    font-size: .75rem;
    letter-spacing: 1px;
    font-weight: 600;
    padding: 10px 12px;
}
header.header li.hover-dropdown .dropdown-item:hover {
    color: var(--wws-blue) !important;
    background: rgba(0, 160, 223, .06) !important;
}

/* Initials avatar — headshot placeholder until the profile photo upload
   pipeline exists (REBUILD-PLAN.md's media pipeline stage). */
.avatar-initials {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: var(--wws-blue);
    color: #fff;
    font-size: .65rem;
    font-weight: 700;
    letter-spacing: 0;
    text-transform: uppercase;
    vertical-align: middle;
    margin-right: .6rem;
}

header.header .account-trigger {
    display: inline-flex;
    align-items: center;
}

/* Account dropdown (logged-in state) — a real Bootstrap dropdown (click, not
   hover) since it holds account/settings actions, not a hover-dropdown's
   equal-weight nav links; matches the live site's toggles-icon menu. */
header.header .account-dropdown {
    min-width: 220px;
    border: none;
    border-radius: 8px;
    box-shadow: rgba(0, 15, 30, .12) 0 16px 24px 0, rgba(0, 15, 30, .04) 0 4px 8px 0;
    padding: .5rem 0;
}
header.header .account-dropdown .dropdown-header {
    font-size: .68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: #94a3b8;
    line-height: 1.6;
}
header.header .account-dropdown .dropdown-header strong {
    color: #1e293b;
    font-size: .85rem;
    text-transform: none;
    letter-spacing: normal;
}
header.header .account-dropdown .dropdown-item {
    font-size: .8rem;
    padding: .5rem 1rem;
}
header.header .account-dropdown .dropdown-item.disabled {
    color: #adb5bd;
}

/* ── Footer ───────────────────────────────────────────────────────────── */

.footer-bar {
    background: var(--wws-blue);
    padding: 15px;
}

.footer-bar span.cta-text {
    color: #fff;
    vertical-align: middle;
}

/* Live site's "Join Up Now" is a custom .btn-outline, not Bootstrap's
   .btn-outline-light — thicker border and bigger radius than the BS default. */
.footer-bar .btn-outline-light {
    border-width: 3px;
    border-radius: 8px;
}

.footer-bar .social-link {
    color: #fff;
    font-size: 20px;
    text-decoration: none;
}

footer.footer {
    /* No background of its own on the live site — sits directly on body's navy. */
    color: #fff;
    padding: 30px 0 100px;
}

/* Divider between the nav-menu row and the logo row — a plain .border-bottom
   utility renders the wrong (light-gray) color on a dark background, so the
   color is pinned explicitly to match. */
footer.footer .row.border-bottom {
    border-bottom-color: rgba(255, 255, 255, .2) !important;
}

footer.footer h3 {
    color: #fff;
    font-size: 1.2rem;
    font-weight: 700;
}

footer.footer .site-map li a {
    color: rgba(255, 255, 255, .6);
    text-decoration: none;
    font-size: .9rem;
    line-height: 1.5;
}

footer.footer .site-map li a:hover {
    color: #fff;
}

footer.footer small {
    font-size: .8rem;
    color: rgba(255, 255, 255, .6);
}

/* Privacy Policy / Terms & Conditions have no color class on the live site —
   they just inherit the muted <small> color around them rather than the
   global link blue or pure white. */
footer.footer small a {
    color: inherit;
    text-decoration: underline;
}

footer.footer small a:hover {
    color: #fff;
}

body.platform-mobile footer.footer small a { text-decoration: none; }

/* ── My Account sidebar ──────────────────────────────────────────────────
   Dark navy + icon rows, active item highlighted in the brand accent blue —
   matches the live site's my-account sidebar look, not a generic Bootstrap
   list-group. Shared by every /my-account/* page via includes/part-myaccount-nav.php. */

.myaccount-sidebar {
    background: var(--wws-navy);
    border-radius: .75rem;
    overflow: hidden;
    /* header.header is position:fixed at 50px tall (see app.css's header.header
       rule) — offset past it so the sticky sidebar doesn't tuck under it. */
    position: sticky;
    top: 70px;
}

.myaccount-sidebar .nav-link {
    display: flex;
    align-items: center;
    gap: .65rem;
    padding: .8rem 1.1rem;
    color: rgba(255, 255, 255, .65);
    font-weight: 600;
    font-size: .8rem;
    text-transform: uppercase;
    letter-spacing: .03em;
    border-radius: 0;
    transition: background .15s, color .15s;
}

.myaccount-sidebar .nav-link i {
    font-size: 1.1rem;
    width: 1.3rem;
    text-align: center;
    flex-shrink: 0;
}

.myaccount-sidebar .nav-link:hover {
    background: rgba(255, 255, 255, .07);
    color: #fff;
}

.myaccount-sidebar .nav-link.active {
    background: var(--wws-blue);
    color: #fff;
}

.myaccount-sidebar .nav-link.disabled {
    color: rgba(255, 255, 255, .3);
    pointer-events: none;
}

.myaccount-sidebar .nav-link .badge {
    margin-left: auto;
    font-size: .6rem;
}

.myaccount-sidebar hr {
    border-color: rgba(255, 255, 255, .1);
    margin: 0;
    opacity: 1;
}

.myaccount-sidebar .nav-link.logout {
    color: #ff9d9d;
}

.myaccount-sidebar .nav-link.logout:hover {
    background: rgba(220, 53, 69, .15);
    color: #ff9d9d;
}

/* Sub-nav (Athlete Profile's 7 sections) — indented, smaller, no icons. */
.myaccount-sub-nav {
    background: rgba(0, 0, 0, .15);
}

.myaccount-sub-nav .nav-sub-link {
    display: flex;
    align-items: center;
    gap: .4rem;
    padding: .55rem 1.1rem .55rem 2.6rem;
    color: rgba(255, 255, 255, .55);
    font-weight: 500;
    font-size: .76rem;
    text-transform: none;
    letter-spacing: 0;
    text-decoration: none;
    transition: background .15s, color .15s;
}

.myaccount-sub-nav .nav-sub-link .badge {
    margin-left: auto;
    font-size: .55rem;
}

.myaccount-sub-nav .nav-sub-link:hover {
    background: rgba(255, 255, 255, .06);
    color: #fff;
}

.myaccount-sub-nav .nav-sub-link.active {
    background: rgba(0, 160, 223, .18);
    color: #fff;
    font-weight: 700;
}

/* Dashboard member summary card's left-hand widget embed — the athlete
   widget is a fixed 600x430 non-responsive document (see
   wws-widgets/athlete-profile-widget.php's header comment), scaled to fill
   whatever width the column actually has via JS (part-member-summary-card.php). */
.wws-widget-embed-wrap { position: relative; overflow: hidden; }
.wws-widget-embed-wrap iframe { position: absolute; top: 0; left: 0; transform-origin: top left; }

/* Dashboard member summary card's right-hand info panel — see
   my-account/includes/part-member-summary-card.php. */
.member-summary-section + .member-summary-section { margin-top: 0; }
.member-summary-divider { margin: 1.1rem 0; border-color: rgba(0, 0, 0, .08); }
.member-summary-label {
    display: flex;
    align-items: center;
    gap: .45rem;
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: #94a3b8;
    margin-bottom: .5rem;
}
.member-summary-label i { color: var(--wws-blue); font-size: .9rem; }
.member-summary-since { font-size: 1.15rem; font-weight: 600; color: #1a2332; }
.member-summary-fields { display: flex; flex-direction: column; gap: 0; }
.member-summary-field-row {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    padding: .5rem 0;
    border-bottom: 1px dashed #e9ecef;
    font-size: .88rem;
}
.member-summary-field-row:last-child { border-bottom: none; padding-bottom: 0; }
.member-summary-field-row dt { color: #8a94a3; font-weight: 500; margin: 0; }
.member-summary-field-row dd { color: #1a2332; font-weight: 600; margin: 0; text-align: right; }
.member-summary-license {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    background: #f1f5f9;
    border: 1px solid #e2e8f0;
    border-radius: 999px;
    padding: .3rem .3rem .3rem .3rem;
    font-size: .78rem;
    font-weight: 600;
    color: #1a2332;
}
.member-summary-license-fed {
    background: var(--wws-navy);
    color: #fff;
    border-radius: 999px;
    padding: .2rem .6rem;
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: .03em;
}
.member-summary-plan-badge {
    background: rgba(0, 160, 223, .12);
    color: var(--wws-blue);
    border-radius: 999px;
    padding: .3rem .8rem;
    font-size: .82rem;
    font-weight: 700;
}
.member-summary-status-dot {
    display: inline-block;
    width: .5rem;
    height: .5rem;
    border-radius: 50%;
    background: #22c55e;
}

/* ── Segmented pill tabs (Bootstrap .nav-tabs override) ──────────────────
   Ported from Clubs.worldwaterskiers.com/new-build's app.css (their global
   .nav-tabs override, itself copied from LocalBuilderPro's .contract-tab) —
   default Bootstrap underlined tabs replaced everywhere with rounded pills,
   active pill filled in the brand blue instead of clubs' --wsc-primary. */
.nav-tabs { border-bottom: none; flex-wrap: wrap; gap: .5rem; }
.nav-tabs .nav-item { margin-bottom: 0; }
.nav-tabs .nav-link {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    border: 2px solid #e2e8f0;
    border-radius: 20px;
    background: #fff;
    color: #64748b;
    padding: .28rem .9rem;
    font-weight: 500;
    font-size: .82rem;
    transition: background-color .15s, color .15s, border-color .15s;
}
.nav-tabs .nav-link:hover { background: #f1f5f9; color: #0f172a; }
.nav-tabs .nav-link.active,
.nav-tabs .nav-link.active:hover {
    background: var(--wws-blue);
    border-color: var(--wws-blue);
    color: #fff;
}
.nav-tabs .nav-link.disabled,
.nav-tabs .nav-link.disabled:hover {
    background: #fff;
    color: #a0aec0;
    border-color: #e2e8f0;
}

/* ── Bare icon buttons (edit / delete) — ported from clubs' app.css ─────────
   Usage: <button class="btn-edit" title="Edit"><i class="bi bi-pencil"></i></button>
          <button class="btn-delete" title="Delete"><i class="bi bi-trash"></i></button> */
.btn-edit,
.btn-delete {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    color: #adb5bd;
    padding: .25rem .35rem;
    border-radius: 5px;
    line-height: 1;
    cursor: pointer;
    text-decoration: none;
    transition: color .15s;
    font-size: 1rem;
}
.btn-edit:hover   { color: var(--wws-blue); }
.btn-delete:hover { color: #dc3545; }

/* Masked password dots render cramped at the browser default letter-spacing
   — sitewide, every input[type=password], not just ones using the
   .wws-password-field toggle below. */
input[type="password"] { letter-spacing: .15em; }

/* ── Password show/hide toggle (assets/js/password-toggle.js) ────────────
   Usage: <div class="wws-password-field">
            <input type="password" class="form-control">
            <i class="bi bi-eye wws-password-toggle"></i>
          </div>
   The script delegates on .wws-password-toggle and toggles the sibling
   input found via .wws-password-field, so any number of these can exist on
   one page with no per-field IDs to keep in sync. */
.wws-password-field { position: relative; }
.wws-password-field .form-control { padding-right: 2.5rem; }
.wws-password-toggle {
    position: absolute;
    right: 12px;
    top: 50%;
    transform: translateY(-50%);
    cursor: pointer;
    color: #6c757d;
    user-select: none;
}

/* ── Athlete Profile: video cards + lightbox — ported from clubs'
   site-profile.php (club gallery videos), same markup/behavior. ────────── */
.video-card { display: flex; gap: 1rem; align-items: flex-start; padding: .875rem; border: 1px solid #e9ecef; border-radius: 10px; background: #fff; margin-bottom: .75rem; cursor: default; }
.video-drag-handle { cursor: grab; color: #ccc; padding-top: .35rem; }
.video-card.sortable-ghost { opacity: .35; }
.video-thumb { flex-shrink: 0; width: 140px; height: 80px; border-radius: 6px; overflow: hidden; background: #e9ecef; position: relative; cursor: pointer; }
.video-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.video-thumb .play-icon { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; background: rgba(0, 0, 0, .3); color: #fff; font-size: 1.5rem; pointer-events: none; }
.video-meta { flex: 1; min-width: 0; }
.video-meta .video-title { font-weight: 600; font-size: .9rem; margin-bottom: .2rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; border-radius: 5px; padding: 2px 6px; margin-left: -6px; outline: none; cursor: text; border: 1px solid transparent; transition: border-color .15s; }
.video-meta .video-title:hover { border-color: #d0d5dd; }
.video-meta .video-title:focus { border-color: #86b7fe; box-shadow: 0 0 0 3px rgba(13, 110, 253, .15); white-space: normal; overflow: visible; text-overflow: unset; }
.video-meta .video-url-display { display: inline-block; font-size: .75rem; color: #888; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.video-meta .video-url-display:hover { color: var(--wws-blue); text-decoration: underline; }
.video-add-row { display: flex; gap: .5rem; align-items: center; }
.video-add-row input { flex: 1; }
.video-spinner { display: none; }

#videoLightbox { display: none; position: fixed; inset: 0; z-index: 10000; background: rgba(0, 0, 0, .92); align-items: center; justify-content: center; }
#videoLightbox.active { display: flex; }
#videoLightbox .lb-frame-wrap { width: 80vw; max-width: 960px; aspect-ratio: 16/9; background: #000; }
#videoLightbox iframe { width: 100%; height: 100%; border: 0; }
#videoLightbox .lb-close { position: fixed; top: 16px; right: 20px; background: none; border: none; color: #fff; font-size: 2rem; cursor: pointer; line-height: 1; opacity: .8; }
#videoLightbox .lb-close:hover { opacity: 1; }
#videoLightbox .lb-nav { position: fixed; top: 50%; transform: translateY(-50%); width: 48px; height: 48px; display: flex; align-items: center; justify-content: center; background: rgba(255, 255, 255, .12); border: none; color: #fff; font-size: 1.8rem; padding: 0; border-radius: 50%; cursor: pointer; transition: background .15s; line-height: 1; }
#videoLightbox .lb-nav:hover { background: rgba(255, 255, 255, .25); }
#videoLightbox .lb-prev { left: 12px; }
#videoLightbox .lb-next { right: 12px; }
#videoLightbox .lb-counter { position: fixed; bottom: 18px; left: 50%; transform: translateX(-50%); color: rgba(255, 255, 255, .6); font-size: .82rem; }

/* ── Athlete Profile: photo gallery grid ─────────────────────────────────── */
.gallery-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: .75rem; }
.gallery-tile { position: relative; aspect-ratio: 1; border-radius: 8px; overflow: hidden; background: #e9ecef; }
.gallery-tile img { width: 100%; height: 100%; object-fit: cover; display: block; }
.gallery-tile .btn-delete { position: absolute; top: 4px; right: 4px; background: rgba(0, 0, 0, .55); color: #fff; }
.gallery-tile .btn-delete:hover { background: rgba(220, 53, 69, .85); color: #fff; }

/* ── Public athlete profile page (/athlete/{wwsID}) ──────────────────────
   Ported pixel-for-pixel from the live site's single-athlete desktop
   template (athletes/views/views-athlete/view-desktop-athlete.php +
   parts-desktop/parts-ajax/*.php) — same colors/spacing/class shapes as
   assets/css/desktop.css, confirmed by direct extraction from that file.
   Scoped under dedicated .athlete-* class names (not the generic
   .nav-pills/.card-columns Bootstrap hooks) so the global pill-tab theme
   ported elsewhere in this file can't collide with this page's own navy/
   #eeeeee active-pill scheme, which the live site's CSS specificity happens
   to win with on the real site too. */
@import url('https://fonts.googleapis.com/css2?family=Lobster&display=swap');

.theme-color-background { background: var(--wws-navy); }
.font-theme-color { color: var(--wws-blue); }
.lobster { font-family: 'Lobster', cursive; }

.athlete-hero {
    position: relative;
    min-height: 500px;
    aspect-ratio: 21 / 9;
    background: #1a2332 center/cover no-repeat;
}
.athlete-hero .photo-credit {
    position: absolute;
    top: 30px;
    left: 30px;
    font-size: .8rem;
    opacity: .7;
    color: #fff;
    z-index: 2;
}
.athlete-hero .photo-credit a { color: #fff; }
.athlete-hero-overlay {
    position: absolute;
    left: 0; right: 0; bottom: 0;
    padding-top: 100px;
    background: linear-gradient(180deg, rgba(0, 22, 43, 0) 20%, #00162b 100%);
}
.athlete-hero-inner {
    display: flex;
    align-items: center;
    padding: 0 3rem 2.5rem;
    color: #fff;
}
.athlete-headshot-col { flex: 0 0 auto; min-width: 250px; display: flex; align-items: center; }
.athlete-headshot-frame { width: 180px; height: 180px; }
.athlete-headshot-frame .headshots {
    background: #eee;
    border: 4px solid #fff;
    border-radius: 50%;
    width: 100%; height: 100%;
    object-fit: cover;
    display: block;
}
.athlete-hero-divider { width: 5px; height: 150px; background: #fff; margin: 0 2rem; flex-shrink: 0; }
.athlete-hero-text h1 { font-size: 4.5rem; line-height: 3.5rem; margin-bottom: 1rem; font-weight: 700; }
.athlete-hero-text h3 { margin-bottom: 1rem; }
.athlete-hero-caption { opacity: .7; }
.athlete-hero-flag { width: 20px; margin-right: 10px; margin-top: -3px; }

/* Athlete-of-the-Year rank badge, overlapping the headshot's bottom-right
   edge — ported pixel-for-pixel from the live plugin's own inline styles
   (views/aotm/view-athlete-rank.php + its wrapper in the theme's hero view).
   right:55px (not the live markup's literal 40px) because live's headshot
   circle sits with a 15px inset inside its 250px column (Bootstrap grid
   gutter) while this build's flex-based .athlete-headshot-col has the
   circle flush at the column's edge — confirmed by measuring both pages'
   actual getBoundingClientRect() output, then offsetting by that 15px so
   the badge overlaps the circle by the same 45px/15px split as production. */
.athlete-rank-badge-wrap { position: absolute; right: 55px; bottom: 0; }
.athlete-rank-badge { width: 60px; height: 60px; }

/* ── WWS Polls (lib/polls.php's poll_render_card()) ───────────────────────
   Ported from the live wws-polls plugin's own assets/css/wws-polls.css —
   the not-yet-voted state is a list of circle+text rows (not styled
   buttons, which a prior pass used instead of actually checking the
   plugin's CSS), circle fills solid blue and spins briefly on hover. */
.wws-poll-option { display: flex; align-items: center; padding: 10px 0; cursor: pointer; border-bottom: 1px solid #f0f0f0; }
.wws-poll-option:last-child { border-bottom: none; }
.wws-poll-option-circle { width: 20px; height: 20px; min-width: 20px; border: 2px solid var(--wws-blue); border-radius: 50%; transition: all .3s ease; }
.wws-poll-option-text { margin-left: 12px; font-size: 14px; color: #333; transition: color .2s ease; }
.wws-poll-option:hover .wws-poll-option-circle { background: var(--wws-blue); border-color: transparent; border-top-color: var(--wws-blue); animation: wws-poll-spin .6s linear infinite; }
.wws-poll-option:hover .wws-poll-option-text { color: var(--wws-blue); }
@keyframes wws-poll-spin { to { transform: rotate(360deg); } }
.wws-poll-progress-fill { background: linear-gradient(90deg, var(--wws-blue), #0077b6); transition: width .4s ease; }
.athlete-rank-badge-num { display: flex; align-items: center; justify-content: center; width: 36px; height: 36px; margin: 0 auto; font-size: 22px; font-weight: 700; }
.athlete-rank-badge-num sup { font-size: 10px; font-weight: 600; }
.athlete-rank-badge-label { font-size: 6px; text-transform: uppercase; letter-spacing: .3px; line-height: 1.2; position: relative; bottom: 5px; }

.athlete-sub-nav {
    padding: 10px 15px;
    position: sticky;
    /* header.header is position:fixed at exactly 50px tall with z-index:1030
       (see app.css's header.header rule) — at top:0 this stuck directly
       behind the fixed header (z-index:900 loses), completely hiding the
       tab bar the instant it went sticky, on both /tournament and
       /tournament/{id} (live). top:50px sits it flush against the header's
       bottom edge — no gap, no overlap. (.myaccount-sidebar's 70px isn't a
       relevant reference here — that sidebar wants breathing room below the
       header; this bar should sit flush against it.) */
    top: 50px;
    /* The live page's own sticky "Results" heading and live-scoring iframe
       (both plain Bootstrap .sticky-top, z-index:1020 by default) scroll
       past this same band before reaching their own lower stick points
       (top:150/170px) — at the old z-index:900 they cut visibly on top of
       this nav bar during that transition. This nav is the page's primary
       navigation, so it should win: above Bootstrap's .sticky-top default,
       below the site's main fixed header (1030). */
    z-index: 1025;
}
.athlete-pill-nav {
    overflow-x: auto;
    scrollbar-width: none; /* no visible scrollbar under the pills (it scrolls by swipe) */
    flex-wrap: nowrap;
    margin: 0;
    padding: 0 20px;
}
.athlete-pill-nav::-webkit-scrollbar { display: none; }
.athlete-pill-nav .nav-link {
    border-radius: 100px;
    font-size: 16px;
    background: transparent;
    color: #fff;
    border: 0;
    padding: .5rem 1rem;
    cursor: pointer;
    white-space: nowrap;
}
.athlete-pill-nav .nav-link.active { background: #eeeeee; color: #00162b; }

.athlete-social-links a { color: inherit; }
.athlete-story-body { text-align: justify; color: #cfd3df; }

.athlete-summary-thumb {
    position: relative;
    aspect-ratio: 16 / 9;
    background: #e9ecef center/cover no-repeat;
    border-radius: 6px;
    cursor: pointer;
    overflow: hidden;
}


.card-columns-5 { column-count: 5; column-gap: 1rem; }
.card-columns-5 > a { display: block; break-inside: avoid; margin-bottom: 20px; }
.card-columns-5 img { width: 100%; display: block; }
@media (max-width: 1200px) { .card-columns-5 { column-count: 3; } }
@media (max-width: 768px) { .card-columns-5 { column-count: 2; } }

/* Mobile tournament Photos tab's own masonry class (live theme's real
   parts-mobile/parts-ajax/photos.php uses "card-columns card-columns-2"
   literally, a fixed 2-column layout regardless of viewport width — not
   just .card-columns-5's own responsive collapse to 2 columns under
   768px, which is viewport-width-driven rather than a deliberate mobile-
   view choice). */
.card-columns-2 { column-count: 2; column-gap: 1rem; }
.card-columns-2 > a { display: block; break-inside: avoid; margin-bottom: 20px; }
.card-columns-2 img { width: 100%; display: block; }

/* Video thumbnail-grid + lightbox — ported from Clubs.worldwaterskiers.com/
   new-build's public/event-promotion.php video lightbox (same vanilla-JS
   pattern, no library), adapted for read-only display instead of an admin
   editor: a play-button thumbnail opens a fixed full-screen player with
   prev/next arrows cycling through every video card on the page, matching
   the existing .t-photo-lightbox's fixed/inset-0/rgba(0,0,0,.9) convention
   already used for the Photos tab. Rounded corners applied to both the grid
   thumbnails and the lightbox's own frame per explicit request.
   Named .t-video-* (not .video-thumb/.play-icon) — a plain `.video-thumb`
   collided with my-account/profile/photos.php's own small fixed-size
   140x80 admin list-row thumbnail (public/assets/css/app.css:549), which
   silently won the cascade on `width` since this block never redeclared it
   — same class-collision shape as the earlier .tournament-card/.score-card
   fix on this same page. */
.t-video-thumb { position: relative; display: block; width: 100%; cursor: pointer; border-radius: 12px; overflow: hidden; aspect-ratio: 16/9; background: #000; }
.t-video-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Standalone (not a .t-video-thumb descendant selector) — the Intro tab's
   Latest Videos preview block reuses this same icon on its own
   position-relative wrappers, not the .t-video-thumb class, so scoping it
   to ".t-video-thumb .t-video-play-icon" silently dropped every style here
   (position/centering/color/size) on that block, leaving the bare <i> to
   render inline at browser-default size/color (small, blue, top-left) —
   exactly the bug the user spotted. */
.t-video-play-icon { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; background: rgba(0,0,0,.3); color: #fff; font-size: 3rem; transition: background .15s; }
.t-video-thumb:hover .t-video-play-icon { background: rgba(0,0,0,.5); }
.t-video-lightbox { display: none; position: fixed; inset: 0; background: rgba(0,0,0,.92); z-index: 2000; align-items: center; justify-content: center; }
.t-video-lightbox.active { display: flex; }
.t-video-lightbox .lb-frame-wrap { width: 80vw; max-width: 960px; aspect-ratio: 16/9; background: #000; border-radius: 12px; overflow: hidden; }
.t-video-lightbox iframe { width: 100%; height: 100%; border: 0; }

/* Shared lightbox chrome (close/prev/next/counter) — used by both
   .t-photo-lightbox and .t-video-lightbox so the Photos tab's lightbox
   (originally just a close button, no navigation) and the Videos tab's
   lightbox get identical forward/back controls per explicit request. */
.t-photo-lightbox .lb-close, .t-video-lightbox .lb-close { position: fixed; top: 20px; right: 20px; background: none; border: none; color: #fff; font-size: 2rem; cursor: pointer; line-height: 1; opacity: .8; z-index: 1; }
.t-photo-lightbox .lb-close:hover, .t-video-lightbox .lb-close:hover { opacity: 1; }
.t-photo-lightbox .lb-nav, .t-video-lightbox .lb-nav { position: fixed; top: 50%; transform: translateY(-50%); width: 48px; height: 48px; display: flex; align-items: center; justify-content: center; background: rgba(255,255,255,.12); border: none; color: #fff; font-size: 1.8rem; padding: 0; border-radius: 50%; cursor: pointer; transition: background .15s; line-height: 1; z-index: 1; }
.t-photo-lightbox .lb-nav:hover, .t-video-lightbox .lb-nav:hover { background: rgba(255,255,255,.25); }
.t-photo-lightbox .lb-prev, .t-video-lightbox .lb-prev { left: 12px; }
.t-photo-lightbox .lb-next, .t-video-lightbox .lb-next { right: 12px; }
.t-photo-lightbox .lb-counter, .t-video-lightbox .lb-counter { position: fixed; bottom: 18px; left: 50%; transform: translateX(-50%); color: rgba(255,255,255,.6); font-size: .82rem; }

/* Tournament Results tab's master-detail card list (ajax/tournament/
   results.php) — moved here from a <style> block injected via that AJAX
   partial's own HTML (fetch()+innerHTML), which this session's preview
   tooling was NOT reliably applying (confirmed via direct curl on an
   isolated, freshly-started server showing the correct rule served, while
   the same content rendered in the Browser preview showed neither the rule
   registered in document.styleSheets nor its visual effect) — moving these
   to the always-loaded static stylesheet sidesteps the whole class of
   problem regardless of whether it was a real browser quirk or a preview-
   tool-only artifact. The active-card margin-right rule is the real
   "this card is selected" indicator on the live site (NOT the chevron color
   alone — every leaderboard card already shares the same #e0f6ff background
   regardless of active state, so the chevron tint alone was too subtle to
   register, confirmed via user report "does not show the active tab" on
   first load): live's `.active { margin-right: 0 !important }` (verified
   computed style: active card's margin-right is 0px vs 16px on every
   inactive sibling) makes the selected card visibly WIDER, expanding to
   fill the space its own right margin would otherwise leave. */
.t-results-card { cursor: pointer; }
.t-results-card .bi-chevron-right { transition: color .2s; }
.t-results-card.active .bi-chevron-right { color: #00a0df; }
.t-results-card.active { margin-right: 0 !important; }

/* Live-mode ("/tournament/{id}/live") Results tab: no side-by-side
   master-detail split (the live-scoring iframe already occupies the right
   ~1/3 of the page) — the list is full-width and a card click drills
   through in place, reusing the old theme's own mobile narrow-viewport
   drill-down mechanism (.live-results / desktop-drill-active there,
   .t-live-results / .t-drill-active here). #t-results-detail-col is hidden
   until a card is clicked (see tournament.php's click handler). */
#t-results-back-btn { display: none; }
.t-live-results #t-results-detail-col { display: none; }
.t-live-results.t-drill-active #t-results-list-col { display: none; }
.t-live-results.t-drill-active #t-results-detail-col { display: block; }
.t-live-results.t-drill-active #t-results-back-btn { display: inline-block; }

/* Scores tab's per-tournament result card — named .score-card (not
   .tournament-card) to avoid colliding with the unrelated homepage/calendar
   .tournament-card widget styles further down this file. */
.score-card { background: #fff; border-radius: 12px; box-shadow: var(--wws-card-shadow); padding: 1.5rem; margin-bottom: 1.5rem; }
.score-card-header { border-bottom: 1px solid #e9ecef; padding-bottom: 1rem; margin-bottom: 1rem; }
.score-card-header h3 { margin-bottom: .35rem; }
.score-card-header h3 a.color { color: var(--wws-navy); text-decoration: none; }
.score-card-header h3 a.color:hover { color: var(--wws-blue); }
.score-card-meta { display: flex; align-items: center; gap: .6rem; }
.score-card-meta .tournament-country { font-size: .7rem; color: #6c757d; text-transform: uppercase; letter-spacing: .04em; }
.score-card-meta .tournament-division { font-size: .85rem; font-weight: bold; color: #999; }
.score-card-disciplines .col { border-left: 1px solid #e9ecef; padding: 0 1.5rem; }
.score-card-disciplines .col:first-child { border-left: none; padding-left: 0; }
.score-card-disciplines .discipline-label { font-weight: bold; text-transform: uppercase; font-size: .7rem; letter-spacing: .04em; color: #6c757d; margin-bottom: .75rem; }
@media (max-width: 767.98px) {
    .score-card-disciplines .col { flex: 0 0 100%; max-width: 100%; border-left: none; padding: 1rem 0 0; border-top: 1px solid #e9ecef; margin-top: 1rem; }
    .score-card-disciplines .col:first-child { border-top: none; margin-top: 0; padding-top: 0; }
}

/* Computed athlete stats (Scores tab's season snapshot + Career Highlights'
   career stats) — Chart.js canvases driven by ajax/athlete/scores.php and
   ajax/athlete/career-stats.php, styled here so both blocks match. Win vs.
   podium is always the same two brand tones (--wws-blue / a darker shade of
   it, --win below) — never a third hue — since a podium finish already
   includes wins, they're nested tiers of one measure, not separate categories. */
/* --blue-text is a slightly deeper shade of --wws-blue, used only where the
   brand blue sits as small/bold text directly on white — --wws-blue itself
   is ~3:1 there, under the 4.5:1 text threshold (fine for the buttons/links
   it's normally used for, not fine for a stat number). */
:root { --win: #116da0; --win-dim: #e4eef4; --blue-text: #007cb0; }

h3.stats-label {
    font-size: .72rem; text-transform: uppercase; letter-spacing: .08em; font-weight: 800;
    color: #93a1ac; margin: 0 0 12px;
}

.stat-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-bottom: 20px; }
@media (max-width: 720px) { .stat-row { grid-template-columns: repeat(2, 1fr); } }
.stat-tile { border-radius: 14px; padding: 16px 18px; background: #fff; box-shadow: var(--wws-card-shadow); }
.stat-tile .n { font-size: 1.9rem; font-weight: 800; line-height: 1; color: #14232f; }
.stat-tile .l { font-size: .74rem; color: #93a1ac; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; margin-top: 6px; }
.stat-tile.accent .n { color: var(--blue-text); }
.stat-tile.win .n { color: var(--win); }

.chart-grid { display: grid; grid-template-columns: 260px 1fr; gap: 16px; margin-bottom: 8px; }
@media (max-width: 820px) { .chart-grid { grid-template-columns: 1fr; } }
.chart-card { border-radius: 14px; padding: 18px; background: #fff; box-shadow: var(--wws-card-shadow); }
.chart-card h4 { margin: 0 0 4px; font-size: .88rem; font-weight: 700; }
.chart-card .sub { font-size: .74rem; color: #93a1ac; margin-bottom: 10px; }

.doughnut-wrap { position: relative; width: 100%; max-width: 210px; margin: 6px auto 4px; }
.doughnut-center { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; pointer-events: none; }
.doughnut-center b { font-size: 1.6rem; font-weight: 800; }
.doughnut-center span { font-size: .66rem; color: #93a1ac; text-transform: uppercase; letter-spacing: .05em; }
.doughnut-legend { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
.doughnut-legend .row { display: flex; align-items: center; gap: 8px; font-size: .8rem; }
.doughnut-legend i { width: 10px; height: 10px; border-radius: 3px; flex-shrink: 0; }
.doughnut-legend i.swatch-blue { background: var(--wws-blue); }
.doughnut-legend i.swatch-mute { background: #e6ebf0; }
.doughnut-legend .val { margin-left: auto; font-weight: 800; }
.win-callout { display: flex; align-items: center; gap: 10px; margin-top: 14px; padding: 10px 12px; background: var(--win-dim); border-radius: 10px; }
.win-callout b { font-size: 1.15rem; font-weight: 800; color: var(--win); }
.win-callout span { font-size: .76rem; color: #5a6b78; }

.disc-charts { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
@media (max-width: 560px) { .disc-charts { grid-template-columns: 1fr; } }
.disc-chart-card { background: #f6f8fa; border-radius: 12px; padding: 14px 14px 6px; }   /* inside a card: tint, not another box */
.disc-chart-head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 6px; }
.disc-chart-head h5 { margin: 0; font-size: .82rem; font-weight: 700; }
.disc-chart-head .best { font-size: .78rem; color: var(--win); font-weight: 800; }
.disc-chart-empty { grid-column: 1 / -1; border: 1px dashed #e6ebf0; border-radius: 12px; padding: 18px; text-align: center; color: #93a1ac; font-size: .82rem; }

.trend-card { border: 1px solid #e6ebf0; border-radius: 14px; padding: 20px; margin-bottom: 22px; }
.trend-card h4 { margin: 0 0 10px; font-size: .95rem; }

.milestone-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-bottom: 22px; }
@media (max-width: 720px) { .milestone-row { grid-template-columns: repeat(2, 1fr); } }
.milestone { border: 1px solid #e6ebf0; border-radius: 14px; padding: 16px 18px; }
.milestone .l { font-size: .68rem; text-transform: uppercase; letter-spacing: .06em; color: #93a1ac; font-weight: 700; margin-bottom: 8px; }
.milestone .v { font-size: 1.15rem; font-weight: 800; }
.milestone .v small { display: block; font-size: .72rem; font-weight: 600; color: #5a6b78; margin-top: 3px; }

.pb-strip { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-bottom: 10px; }
@media (max-width: 720px) { .pb-strip { grid-template-columns: 1fr; } }
.pb-card { border: 1px solid #e6ebf0; border-radius: 14px; padding: 16px 18px; display: flex; gap: 12px; align-items: center; }
.pb-card.empty { border-style: dashed; color: #93a1ac; font-size: .84rem; }
.pb-icon { width: 40px; height: 40px; border-radius: 11px; background: var(--win-dim); color: var(--win); display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: .72rem; flex-shrink: 0; }
.pb-card.empty .pb-icon { background: #f6f8fa; color: #93a1ac; }
.pb-body b { display: block; font-size: 1.1rem; font-weight: 800; }
.pb-body span { font-size: .76rem; color: #93a1ac; }

.award { float: left; width: 54px; height: 60px; position: relative; }   /* 40px badge slot + room before the "Rnd." label */
.award div {
    position: absolute; top: 5px; left: 5px;
    width: 30px; height: 30px; line-height: 30px;
    text-align: center; font-size: 16px; font-weight: bold;
    border-radius: 50%;
}
.award div small { font-size: 8px; }
.gold { background: #958867 !important; }
.silver { background: #a8a8a8 !important; }
.bronze { background: #9a7461 !important; }

.career-award {
    width: 100%;
    max-width: 120px;
    aspect-ratio: 1;
    border-radius: 50%;
    background: #6c757d;
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 50px;
    font-weight: bold;
    margin: 0 auto 1rem;
}
.career-award small { font-size: 30px; }

.athlete-tabs-bar { display: none; } /* superseded by .athlete-sub-nav above */

.athlete-video-tile { cursor: pointer; }
.athlete-video-play {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-size: 2.2rem;
    text-shadow: 0 2px 6px rgba(0, 0, 0, .5);
    pointer-events: none;
}

/* ── Tour page (/tour/{year}) ─────────────────────────────────────────────
   Ported from the live site's wws-world-overall-tour view — looping bg
   video (hotlinked, same file the live site uses every year), dark overlay,
   per-year logo, prev/next year nav, stops grid overlapping the hero,
   themed rankings section below. */
.tour-hero-bg-video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center center;
}
.tour-hero-overlay {
    position: absolute;
    inset: 0;
    background: rgba(9, 50, 81, .84);
}
.tour-hero-nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    color: #fff;
    font-weight: 600;
    text-decoration: none;
    display: flex;
    align-items: center;
    gap: .3rem;
    z-index: 3;
}
.tour-hero-nav-prev { left: 2rem; }
.tour-hero-nav-next { right: 2rem; }
.tour-hero-nav:hover { color: var(--wws-blue); }
.tour-hero-logo { max-height: 120px; width: auto; }
.tour-hero-logo-single { max-height: 140px; width: auto; }

/* Live theme's own light-grey alternate section background (confirmed via
   getComputedStyle on the live page: rgb(234,234,234) = #eaeaea — NOT
   Bootstrap's bg-light #f8f9fa, which is visibly a shade lighter). Used for
   the stops grid, "Watch it again", About the Tour, and the anchor-nav pill
   strip — everywhere the live theme's own `.background` class appears on
   this page. */
.tour-bg-alt { background: #eaeaea; }

/* Anchor-nav pill number badge — matches the live theme's `.order` class
   (defined inline per view-{platform}-{year}.php) combined with Bootstrap's
   own .bg-secondary/.rounded-circle utilities, confirmed via computed
   style: 30x30, line-height 30px, font-size 1rem, normal weight, white
   text, 10px right margin. */
.order {
    display: inline-block;
    width: 30px;
    height: 30px;
    line-height: 30px;
    border-radius: 10px;
    text-align: center;
    margin-right: 10px;
    font-size: 1rem;
    color: #fff;
}

/* Stop card — matches the live theme's card exactly: a thick near-white
   "frame" border via background-clip:content-box (not a drop shadow, which
   an earlier pass added and the live site doesn't have). */
.tour-stop-card {
    border-radius: 4px;
    border: 10px solid #f9f9f9;
    background-clip: content-box;
    box-shadow: none;
    /* Bootstrap 5's .card sets its own color via --bs-body-color (#212529),
       overriding this site's body { color: #444 } default — confirmed via
       computed-style diff against the live page, which shows #444 here.
       Scoped to this card only, not a global .card override, since that
       would touch every other card sitewide (athlete/tournament/
       marketplace cards) well beyond what was asked. */
    color: #444;
}
.tour-stop-photo { height: 160px; background: #e2e8f0 center/cover no-repeat; }

/* /tour hub — matches the live theme's .bg-theme-color (confirmed via
   computed style: rgb(0,22,43) = --wws-navy) and its translucent white
   section dividers (Bootstrap's default .border-bottom color doesn't
   apply against a dark background). */
.bg-theme-color { background: var(--wws-navy); }
.bg-theme-color.border-bottom { border-color: rgba(255, 255, 255, .2) !important; }
.bg-theme-color .btn-outline-light { --bs-btn-color: #fff; --bs-btn-hover-color: var(--wws-navy); }

.tour-rankings-section { background: var(--wws-navy); padding: 3rem 0; }
.tour-rank-badge {
    /* Live site reuses the same .order class here (no .rounded-circle
       override, unlike the anchor-nav pills) — a rounded square, not a
       circle. Confirmed against a live screenshot: an earlier pass had
       this at border-radius:50%. */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border-radius: 10px;
    font-weight: 700;
    font-size: 1rem;
    color: #fff;
    background: rgba(255, 255, 255, .15);
}
.tour-rank-gold { background: #d4af37; }
.tour-rank-silver { background: #a8a9ad; }
.tour-rank-bronze { background: #cd7f32; }
.tour-rank-points { font-size: 1.7rem; font-weight: 700; }

/* ── Athlete of the Year rankings (public/rankings/athlete-of-the-year.php) ──
   Matches plugins/wws-voting/assets/css/wws-voting.css's `.wws-voting-rankings
   .order` rules exactly (circular gradient medals, not the rounded-square
   .tour-rank-badge used elsewhere) — a distinct class since this page's
   badges are genuinely styled differently on live, not a fidelity slip. */
.wws-voting-order {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    font-weight: 700;
    font-size: 13px;
    color: #fff;
    background: #f0f0f0;
}
.wws-voting-order.text-dark { background: #f0f0f0; color: #333; }
/* Not .gold/.silver/.bronze — this theme already ported those as global
   !important utility classes (app.css:1153) that would otherwise win over
   these gradients regardless of selector specificity. */
.wws-voting-order.wws-voting-gold { background: linear-gradient(135deg, #ffd700, #daa520); }
.wws-voting-order.wws-voting-silver { background: linear-gradient(135deg, #c0c0c0, #a0a0a0); }
.wws-voting-order.wws-voting-bronze { background: linear-gradient(135deg, #cd7f32, #a0652f); }
.wws-voting-points { font-size: 1.4rem; font-weight: 700; color: #333; }
.wws-voting-points small { font-size: 10px; font-weight: 400; color: #999; }

/* ── Tournament calendar widget (public/includes/part-calendar-widget.php) ──
   Ported pixel-for-pixel from the live theme's calendar-widget CSS (assets/
   css/desktop.css's .wws-calendar-widget rules), read directly from source. */
/* Not scoped under .wws-calendar-widget — also used by the Quickview modal
   (#tournamentDetailsModal), which renders as a sibling of the widget's own
   wrapper div, not a descendant of it. */
.badge-wws {
    color: #fff !important;
    background-color: #c5beec !important;
    padding-right: 1em;
    padding-left: 1em;
    line-height: inherit;
    margin-right: 10px;
    text-transform: uppercase;
}
.wws-calendar-widget .dropdown { font-size: 12px; }
.wws-calendar-widget .wwsw-month-nav { height: 80px; }
.wws-calendar-widget .wwsw-month-track::-webkit-scrollbar { display: none; }
.wws-calendar-widget .wwsw-month-pill {
    display: inline-block;
    line-height: 70px;
    width: 150px;
    text-align: center;
    border: 1px solid #dee2e6;
    border-radius: .25rem;
    color: #333;
    text-decoration: none;
    flex-shrink: 0;
}
.wws-calendar-widget .wwsw-month-pill:hover { text-decoration: none; border-color: #adb5bd; color: #333; }
.wws-calendar-widget .wwsw-month-pill.active { font-weight: bold; color: var(--wws-blue) !important; border: 2px solid var(--wws-blue) !important; }
.wws-calendar-widget .border-5 { border-width: 5px !important; }
.wws-calendar-widget .btn-default { color: #333; background-color: #fff; border-color: #ccc; }
.wws-calendar-widget .event-row:hover {
    box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .15) !important;
    z-index: 1;
    position: relative;
    color: inherit;
    text-decoration: none;
}
.wws-calendar-widget .btn-xs { padding: 1px 5px; font-size: .75rem; }
/* Not scoped under .wws-calendar-widget — also used by the Pro Events
   page's "View the Highlights" pill. */
.rounded-lg { border-radius: .3rem; }
/* Bootstrap 4's $border-radius-sm — BS5 dropped .rounded-sm for a numbered
   scale, but the homepage feed's "time ago" badge (every card type) was
   ported verbatim with this class name, so it needs the same BS4->BS5 shim
   treatment as .rounded-lg above rather than a one-off fix per card. */
.rounded-sm { border-radius: .2rem; }
.wws-calendar-widget h3 { font-size: 1.2rem; font-weight: 700; color: #444; }

/* BS4 -> BS5 compat shims for markup ported verbatim from the live theme —
   both classes existed in Bootstrap 4 and were removed/renamed in 5, but
   showed up enough in ported source (calendar rows, athlete scores, more to
   come) that a global shim is less error-prone than hunting every instance. */
.font-weight-bold { font-weight: 700 !important; }
.color { color: var(--wws-blue) !important; }
.color:hover { color: #005779 !important; }
.btn-block { display: block; width: 100%; }

/* ── Featured Tournaments page (/tournaments) ─────────────────────────────
   Ported pixel-for-pixel from the live theme's tournaments/page-tournaments.php
   + views/views-tournaments/parts/content-tournament.php, cross-checked
   against the live rendered page's computed styles directly. */
.tournaments-hero h1 { font-size: 2.3rem; font-weight: 700; color: #444; }

.rounded-xl { border-radius: .5rem !important; }
.rounded-xxl { border-radius: .8rem !important; }

/* ── Pro Events page (/pro-events) ────────────────────────────────────────
   Ported pixel-for-pixel from the live theme's pro-events/views/
   view-desktop-pro-events.php. */
/* overflow:hidden matters here — .pro-event-gradient and the absolutely-
   positioned dates/logo rows inside are children of this rounded-xl box,
   and without clipping they bleed past its rounded corners, showing a
   flat/square bottom edge instead of a rounded one. */
.pro-event-hero { aspect-ratio: 21 / 9; min-height: 500px; overflow: hidden; }
.pro-event-hero .countdown-timer { color: #fff; }
.pro-event-gradient {
    padding-top: 100px;
    background: linear-gradient(180deg, rgba(0, 22, 43, 0) 20%, #00162b 100%);
}

.tournament-card {
    background: #fff;
    border-radius: .3rem;
    box-shadow: var(--wws-card-shadow);
    overflow: hidden;
}
.tournament-card-logo {
    width: 60px;
    aspect-ratio: 4 / 3;
    z-index: 1;
    border-radius: 13px;
    overflow: hidden;
    box-shadow: 0 .125rem .25rem rgba(0, 0, 0, .1);
}
.tournament-card-image {
    position: relative;
    aspect-ratio: 16 / 9;
    background: linear-gradient(120deg, #d6d6d6 0%, #f0f0f0 100%) center/cover no-repeat;
}
.tournament-card-date { width: 50px; }

/* Countdown timer (inline <style> block on the live page's template) */
.countdown-timer { color: #000; }
.countdown-timer .countdown-unit { font-size: .8rem; }
.countdown-timer .digit {
    display: inline-block;
    margin: 0 1px;
    background: #fff;
    border-radius: 4px;
    line-height: 40px;
    min-height: 40px;
    width: 28px;
    min-width: 28px;
    text-align: center;
    color: #000;
    font-weight: bold;
    font-size: 20px;
}

/* ── Athletes directory (/athletes) ───────────────────────────────────────
   1:1 port of the live theme's athletes/views/views-athletes/parts/
   content-athlete.php, using the exact pixel values from the live site's
   actual compiled desktop.css (not the SCSS source, not computed-style
   guesses). The whole header+stats block is ONE sliding unit:
   .athlete-card-main (90px, normal flow, so it's what the card's height is
   actually measured by) + .athlete-card-content (150px tall, position:
   absolute, sliding bottom:-60px -> 10px on hover) — clipped by .athlete-
   card's own overflow:hidden, since .athlete-card-content isn't in flow so
   it doesn't grow the anchor's box. By default the bottom ~60px of that
   150px block (the stats row) sits past the anchor's own height and gets
   clipped off; hovering slides the whole block up 70px, which both reveals
   the stats row AND increases the headshot's overlap into the banner photo
   — that combined motion is "the whole footer sliding" look.
   Earlier attempt at this literal port clipped the name/country text
   because it copied only the CSS class's `bottom:10px` for .details —
   the live markup ALSO has an inline `style="top:10px"` on that div, and
   with both top and bottom set on an absolutely-positioned box, the browser
   stretches it to fill the space between (150-10-10=130px) rather than
   sizing it to content, with the text landing top-aligned near the top of
   that box — comfortably inside the visible band regardless of slide state.
   Name/stats have no color of their own in the live CSS — they inherit the
   surrounding `<a>`'s color (black by default, the site's blue on hover,
   matching this project's --wws-blue); since this project's global `a`
   color is always --wws-blue, they need an explicit default color here to
   reproduce that default-black state. */
.athletes-directory-sub { font-size: 50%; }

.athlete-card { overflow: hidden; background: #fff; }
.athlete-card-banner-wrap { aspect-ratio: 16 / 9; overflow: hidden; position: relative; }
.athlete-card-banner {
    width: 100%;
    height: 100%;
    background: #1a2332 center/cover no-repeat;
    transition: transform 1s ease;
}
.athlete-card:hover .athlete-card-banner { transform: scale(1.2); }

.athlete-card-main { height: 90px; width: 100%; position: relative; background: #fff; }
.athlete-card-content {
    position: absolute;
    left: 0;
    right: 0;
    bottom: -60px;
    height: 150px;
    background: #fff;
    transition: bottom .25s ease;
}
.athlete-card:hover .athlete-card-content,
.athlete-card.hover .athlete-card-content { bottom: 10px; }

.athlete-card-headshot { position: absolute; left: 15px; top: -20px; width: 100px; height: 100px; }
.athlete-card-headshot img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    background: #eee;
    border: 4px solid #fff;
    display: block;
}
.athlete-card-details { position: absolute; left: 130px; right: 20px; top: 10px; }
.athlete-card-name { display: block; font-size: 1rem; font-weight: 700; line-height: 18px; margin-bottom: 8px; color: #212529; transition: color .15s ease; }
.athlete-card:hover .athlete-card-name { color: var(--wws-blue); }
.athlete-card-country { font-size: 1rem; color: #999; display: block; }
.athlete-card-country img { width: 20px; height: auto; border-radius: 2px; vertical-align: -2px; }

.athlete-card-stats { position: absolute; left: 0; right: 0; top: 90px; padding: 10px 20px; font-size: .8rem; color: #212529; border-top: 1px solid #eee; transition: color .15s ease; }
.athlete-card:hover .athlete-card-stats { color: var(--wws-blue); }
.athlete-card-times { background: #fff; font-size: .8rem; width: 100%; margin-top: 4px; padding: 4px 0; color: #ccc; border-top: 1px solid #eee; }

.athletes-search-wrap input.athletes-search { height: 38px; }

/* ── Homepage (/) ──────────────────────────────────────────────────────────
   Framework rebuild of the live theme's page-home.php — see public/includes/
   part-home-*.php for what's real vs. placeholder. Pro Events and Tours are
   real Swiper 5.4.5 instances (matching live's own version) — an earlier
   pass used a native CSS scroll-snap substitute (.hscroll) for both instead,
   since dropped once checking live's actual rendered carousels directly
   (not just their JS source) turned up real behavior worth matching exactly
   — see each part-home-*.php's own header comment. */
.home-hero-placeholder {
    background: linear-gradient(135deg, var(--wws-navy), #003a5c);
}
.home-hero-logo { height: 64px; }
.home-hero-tagline { color: rgba(255, 255, 255, .75); font-size: 1rem; letter-spacing: .02em; }

.coming-soon-tile {
    border: 1px dashed #dee2e6;
    box-shadow: none;
}
.coming-soon-badge {
    display: inline-block;
    margin-top: .35rem;
    padding: .15rem .55rem;
    font-size: .65rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: #6c757d;
    background: #f1f3f5;
    border-radius: 20px;
}

.tour-card-banner {
    /* overflow:hidden matters here too — the navy overlay div inside is an
       absolutely-positioned child with square corners of its own; without
       clipping it bleeds past this box's rounded-xl/rounded-top-0 corners
       and shows a flat bottom edge instead of a rounded one. */
    aspect-ratio: 16 / 9;
    overflow: hidden;
    /* Flat top edge where it meets the white title area (live's
       .rounded-top-0) — .rounded-xl's !important radius was overriding
       BS5's .rounded-top-0 and rounding the top corners too. */
    border-top-left-radius: 0 !important;
    border-top-right-radius: 0 !important;
}

/* Every single-width feed card on the live homepage uses the same
   min-height:450px floor (confirmed across part-youtube.php, part-rtb.php,
   part-marketplace-listing.php, part-rankings.php, part-iwwf-protour-
   rankings.php, part-site.php — every desktop card template but
   part-athlete.php, which sizes itself off its own footer instead) — an
   earlier pass only ever applied this to .news-card, leaving every other
   card type free-height and visually inconsistent row to row. */
.yt-card,
.rtb-card,
.marketplace-card,
.feed-athlete-card,
.feed-sponsor-ad-card,
.feed-join-up-card,
.feed-donate-card,
.site-card {
    min-height: 450px;
}
.yt-card-thumb {
    aspect-ratio: 16 / 9;
    background-color: #e9ecef;
    background-size: cover;
    background-position: center center;
    border-radius: .3rem .3rem 0 0;
}
.rtb-card-thumb {
    aspect-ratio: 4 / 3;
    background-color: #e9ecef;
    background-size: cover;
    background-position: center center;
    border-radius: .3rem .3rem 0 0;
}
.yt-card-icon {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 60px;
    color: #fff;
}
.rtb-card-badge {
    position: absolute;
    top: 15px;
    left: 15px;
    width: 45px;
    height: auto;
}

/* Ski Site feed card (part-home-feed-card.php's 'site' branch) — matches
   the live theme's part-site.php, which sizes its photo area with h-100
   against a flex-column .card (fills whatever's left after the footer, no
   fixed ratio). A fixed aspect-ratio thumb here (this project's usual
   pattern — see .rtb-card-thumb etc above) only filled ~220px against this
   card's short 3-line footer, leaving a ~130px blank gap before the
   min-height:450 floor kicked in — every OTHER card type here escapes that
   gap only because its own footer (excerpt text, etc.) happens to run
   longer. flex:1 reproduces live's fill-the-rest behavior without live's
   row-height-dependent fragility (confirmed live's own thumb height isn't
   fixed either — it varies with whatever tallest sibling shares that row). */
.site-card {
    display: flex;
    flex-direction: column;
}
.site-card-thumb {
    flex: 1 1 auto;
    min-height: 180px;
    background-color: #e9ecef;
    background-size: cover;
    background-position: center center;
    border-radius: .3rem .3rem 0 0;
}
.site-card-badge {
    position: absolute;
    top: 16px;
    left: 16px;
    width: 80px;
    height: 60px;
    border-radius: 13px;
    padding: 8px;
}

/* Homepage combined feed (part-home-feed.php) — pro_event cards run
   double-width (col-xl-6) among the single-width youtube/rtb cards
   (.yt-card/.rtb-card above), matching the live feed's uneven grid. */
.feed-pro-event-card {
    min-height: 450px;
    background-color: #00152a;
}
.feed-pro-event-inner {
    min-height: 380px;
    background-color: #00152a;
    background-size: cover;
    background-position: center center;
}
.feed-pro-event-card-mobile { min-height: 0; }
.feed-pro-event-card-mobile .feed-pro-event-inner { min-height: 0; aspect-ratio: 1 / 1; }
.feed-pro-event-gradient {
    background: linear-gradient(180deg, rgba(0, 22, 43, 0) 20%, #00162b 100%);
}
.btn-xl {
    font-size: 18px;
    padding: 11px 35px;
    border-radius: 6px;
}

/* ── News (/news, /news/{slug}) ──────────────────────────────────────────
   .news-card mirrors the same image+badge+title+excerpt+time-ago language
   as .yt-card/.rtb-card above (homepage feed). .news-post-content styles
   the block-rendered output from lib/news.php's news_render_block(). The
   "N ago" badge is absolutely positioned (bottom:10px;left:15px in the
   markup) rather than inline in the footer text, with a fixed min-height so
   it never overlaps the excerpt — confirmed against the live site's actual
   homepage feed card, which uses the same min-height:450px + absolute-badge
   pattern. */
.news-card {
    min-height: 450px;
}

/* Homepage feed > IWWF ranking card's discipline-panel rotation — matches
   the live theme's mechanism (part-rankings.php's jQuery): every panel is
   stacked position:absolute and cross-fades via opacity, with JS locking
   the wrapper's height to the tallest panel, so switching discipline never
   jumps the card's layout. A naive d-flex/d-none toggle (this card's first
   pass) doesn't have that guarantee — height follows whichever panel is
   currently shown. */
.iwwf-panels-wrap,
.protour-panels-wrap { position: relative; overflow: hidden; transition: height .3s ease; }
.iwwf-disc-panel,
.protour-disc-panel {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    opacity: 0;
    pointer-events: none;
    transition: opacity .6s ease;
}
.iwwf-disc-panel.active,
.protour-disc-panel.active { opacity: 1; pointer-events: auto; }
.news-card-thumb {
    aspect-ratio: 16 / 9;
    background-color: #e9ecef;
    background-size: cover;
    background-position: center center;
    border-radius: .3rem .3rem 0 0;
}

/* Homepage feed > athlete card (part-home-feed-card.php) — banner with a
   circular headshot overlapping it, matches the live theme's
   views-homepage/part-athlete.php exactly (banner, -65px overlap, 130px
   headshot with a white ring). */
.feed-athlete-banner {
    aspect-ratio: 4 / 3;
    background-color: #e9ecef;
    background-size: cover;
    background-position: center center;
}
.feed-athlete-headshot {
    width: 130px;
    height: 130px;
    object-fit: cover;
    border: 3px solid #fff;
}

/* /news archive tiles — a different, simpler card than .news-card above:
   square image, title pinned to the bottom edge in a white bar, no excerpt,
   no time-ago badge. Confirmed against the live site's actual /news/ page
   (embed-responsive-1by1 + a position:absolute "fixed-bottom" title bar). */
.news-archive-card { position: relative; border-radius: .5rem; overflow: hidden; }
.news-archive-card-thumb { aspect-ratio: 1 / 1; background-color: #e9ecef; background-size: cover; background-position: center center; }
.news-archive-card-title {
    position: absolute; bottom: 0; left: 0; right: 0;
    background: #fff; padding: .85rem 1rem;
    font-size: 1.05rem; font-weight: 700; color: #333; line-height: 1.3;
}

.news-post-featured-thumb { aspect-ratio: 16 / 9; background-color: #e9ecef; background-size: cover; background-position: center center; }

.news-post-content { font-size: 1.05rem; line-height: 1.8; color: #334155; }
.news-post-content p { margin-bottom: 1.25rem; }
.news-block-rich-text h2, .news-block-rich-text h3 { margin-top: 2rem; margin-bottom: 1rem; font-weight: 700; color: #333; }
.news-block-heading { font-size: 2rem; font-weight: 700; color: #333; line-height: 1.2; margin: 0; }

/* Grid layout — .news-grid-row/.news-grid-cell are rendered by
   lib/news.php's news_render_rows() for content_format=blocks posts, a
   fixed-width (matches .news-post-content's 800px article container) canvas
   of rows built in wws-admin's grid editor (1, 1:1, 1:2, 2:1 or 1:1:1
   columns). Per-cell flex-grow weight is set inline by news_render_rows()
   rather than fixed CSS classes, since a row's column count/ratio varies. */
.news-grid-row { display: flex; gap: 1.5rem; margin-bottom: 1.5rem; }
.news-grid-cell { min-width: 0; }

.news-block-image { margin: 0; }
.news-block-image img { max-width: 100%; border-radius: .5rem; display: block; margin: 0 auto; }
.news-block-image figcaption { font-size: .82rem; color: #888; margin-top: .5rem; text-align: center; }

.news-block-button { margin: 1.5rem 0; }

/* Gallery — a CSS Grid mosaic, not a uniform thumbnail grid: portrait
   images get a taller tile (grid-row span 2), landscape images get a wider
   one (grid-column span 2), square-ish images stay 1x1 — grid-auto-flow:
   dense packs the mix so different-shaped tiles fit together without
   leaving gaps ("like tetris"). Tile shape is decided once, server-side,
   from the stored width/height (news_gallery_tile_class() in lib/news.php)
   rather than measured in the browser. */
/* grid-auto-rows is tuned to roughly match the rendered column width (3
   columns over the ~600px post content width, minus gaps ≈ 195px/column) —
   NOT an arbitrary smaller value — so a 1-row tile is close to square and a
   landscape tile (column:span 2, still 1 row tall) lands around a 2:1
   rectangle instead of a thin sliver; a mismatched (too-short) row unit was
   exactly what made landscape tiles look squashed before. */
.news-block-gallery { display: grid; grid-template-columns: repeat(3, 1fr); grid-auto-rows: 190px; grid-auto-flow: dense; gap: 6px; margin: 1.5rem 0; }
.news-block-gallery .gallery-item { position: relative; overflow: hidden; border-radius: .5rem; background: #eee; }
.news-block-gallery .gallery-item img { width: 100%; height: 100%; object-fit: cover; display: block; }
.news-block-gallery .gallery-item.g-portrait { grid-row: span 2; }
.news-block-gallery .gallery-item.g-landscape { grid-column: span 2; }

/* Tournament Gallery — a distinct block from the manually-curated Gallery
   above (news_render_tournament_gallery_block() in lib/news.php), auto-
   populated from the tournament's own photos. True column-stacked masonry
   (Pinterest-style), not the row-packed mosaic above: each image keeps its
   own natural aspect ratio and the browser's own CSS multi-column layout
   stacks items down each column, wrapping once a column fills — matching
   the reference screenshot (4 independent photo columns of varying
   heights) directly, no per-image tile classification needed. */
.news-block-tournament-gallery { column-count: 4; column-gap: 8px; margin: 1.5rem 0; }
.news-block-tournament-gallery .gallery-item { break-inside: avoid; margin-bottom: 8px; border-radius: .5rem; overflow: hidden; background: #eee; }
.news-block-tournament-gallery .gallery-item img { width: 100%; display: block; }

.news-block-placeholder {
    padding: 1.25rem;
    background: #f8f9fa;
    border: 1px dashed #dee2e6;
    border-radius: .5rem;
    color: #6c757d;
    font-size: .9rem;
    margin: 1.5rem 0;
}
/* Logo grid, not just a title-sponsor name — see lib/news.php's
   news_render_tournament_sponsors_block() header comment. Plain wrapping
   row (not tournament.php's Swiper carousel) since this sits inline inside
   an article. */
.news-block-sponsors-grid { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 1.5rem; padding: 1.5rem; margin: 1.5rem 0; }
.news-block-sponsor-logo { display: flex; align-items: center; justify-content: center; }
.news-block-sponsor-logo img { max-width: 90px; max-height: 45px; display: block; }

/* ── Mobile ───────────────────────────────────────────────────────────── */

body.platform-mobile #main.site-main {
    padding-top: 50px;
    /* Room for the fixed bottom tab bar (part-footer.php's
       .mobile-footer-nav, 60px tall) so page content doesn't render behind
       it — matches the live theme's own footer.scss padding-bottom:100px
       trick (padding on the plain <footer>, kept here on #main instead
       since main.site-main is what actually scrolls under the fixed bar). */
    padding-bottom: 60px;
}

body.platform-mobile header.header {
    position: fixed;
}

/* Mobile header — back-chevron + centered logo + settings dropdown, no
   .nav-pills menu at all (real primary nav lives in the bottom tab bar
   below, opened via the off-canvas panel here). */
header.header .back-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 50px;
    color: #fff;
    font-size: 26px;
}
header.header .logo-plain img { display: block; }

/* "More" menu bottom sheet (nav.mobile-nav in includes/mobile/part-nav.php).
   Replaces live's left slide-in panel at the user's request, modelled on the
   LocalBuilderPro project's .mobile-sheet (backdrop + translateY slide-up,
   20px rounded top, drag handle, swipe-down to close). Leaves the 60px
   bottom tab bar visible/tappable beneath it. Toggled by `.menushow` on the
   <nav> (assets/js/app.js). */
nav.mobile-nav {
    position: fixed;
    top: 0; left: 0; right: 0; bottom: 0;
    background: rgba(0, 0, 0, .4);
    z-index: 1045;
    visibility: hidden;
    opacity: 0;
    transition: opacity .25s ease, visibility 0s linear .3s;
}
nav.mobile-nav.menushow { visibility: visible; opacity: 1; transition: opacity .25s ease; }
nav.mobile-nav .mobile-menu-bg { position: absolute; inset: 0; }
nav.mobile-nav .mobile-menu {
    position: absolute;
    left: 0; right: 0; bottom: 60px;
    background: #fff;
    border-radius: 20px 20px 0 0;
    max-height: calc(85vh - 60px);
    overflow-y: auto;
    padding-bottom: 12px;
    transform: translateY(calc(100% + 60px));
    transition: transform .3s cubic-bezier(.32, .72, 0, 1);
    box-shadow: 0 -4px 24px rgba(0, 0, 0, .12);
}
nav.mobile-nav.menushow .mobile-menu { transform: translateY(0); }
.mm-handle { width: 40px; height: 4px; border-radius: 2px; background: #e2e8f0; margin: 10px auto 6px; }
.mm-account { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 8px 20px 12px; border-bottom: 1px solid #eee; }
.mm-user { display: flex; align-items: center; gap: 10px; color: #222; font-weight: bold; min-width: 0; }
.mm-user .avatar-initials { width: 40px; height: 40px; font-size: .95rem; background: var(--wws-blue); color: #fff; flex-shrink: 0; }
.mm-user-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mm-logout { color: #6c757d; font-size: .85rem; font-weight: 600; text-decoration: none; white-space: nowrap; }
.mm-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; padding: 16px 16px 8px; }
.mm-tile {
    position: relative;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
    background: #f4f4f4; border: 0; border-radius: 14px;
    padding: 16px 6px 12px;
    color: #222; text-decoration: none; font-size: .8rem; font-weight: 600;
    -webkit-tap-highlight-color: transparent;
}
.mm-tile > .bi:first-child { font-size: 1.6rem; color: var(--wws-blue); }
.mm-tile:active { background: #e9ecef; }
.mm-tile-more { position: absolute; top: 8px; right: 8px; font-size: .6rem; color: #adb5bd; }
.mm-view[hidden] { display: none; }
.mm-back { display: flex; align-items: center; gap: 6px; width: 100%; background: none; border: 0; padding: 14px 20px; font-size: 1.05rem; font-weight: 700; color: #222; text-align: left; }
.mm-sublink { display: flex; align-items: center; justify-content: space-between; padding: 14px 20px; border-top: 1px solid #f1f3f5; color: #222; text-decoration: none; font-size: 1rem; }
.mm-sublink .bi { font-size: .8rem; color: #adb5bd; }
.mm-sublink:active { background: #f4f4f4; }

/* Fixed bottom tab bar — the live theme's actual primary mobile nav
   (part-footer.php's .mobileFooterNav, ported here with a project-
   consistent class name). Icon-over-label pills, active state on the
   current section, "More" opens the off-canvas panel above. */
.mobile-footer-nav {
    background: #f4f4f4;
    border-radius: 15px 15px 0 0;
    box-shadow: 0 -2px 8px rgba(0, 0, 0, .08);
    z-index: 1050; /* above the "More" sheet's backdrop (nav.mobile-nav, 1045) so the tab bar stays visible */
}
.mobile-footer-nav .nav {
    height: 60px;
    padding-top: 5px;
    /* Bootstrap's .nav defaults to flex-wrap:wrap — with 6 icon+label items
       and .nav-fill's flex-grow, that let the 6th ("More") wrap onto its
       own full-width row below the other 5 instead of sharing the one
       row. Real bug, confirmed via getBoundingClientRect() (More's own
       rect was left:0/width:375, i.e. its own line) before this fix. */
    flex-wrap: nowrap;
}
.mobile-footer-nav .nav-link {
    color: #888;
    line-height: 16px;
    border-radius: 0;
    padding-left: .25rem;
    padding-right: .25rem;
    min-width: 0;
}
.mobile-footer-nav .nav-link i { font-size: 1.1rem; }
.mobile-footer-nav .nav-link small { font-size: 9.5px; display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mobile-footer-nav .nav-link.active { color: var(--wws-blue); background: transparent; }

/* ── Sponsor logo carousel (tournament page) ─────────────────────────────
   Swiper 5.4.5's own CDN CSS doesn't define overflow:hidden on a bare
   `.swiper` container reliably — the live theme adds this explicit rule
   for its sponsor carousel specifically (assets/scss/common.scss), ported
   verbatim; without it every slide lays out in one un-clipped row instead
   of a proper carousel. */
.swiper.sponsor-logos { overflow: hidden; }
.swiper.sponsor-logos .swiper-slide a {
    display: block;
    height: 100px;
    line-height: 100px;
    vertical-align: middle;
}
.swiper.sponsor-logos .swiper-slide img {
    max-width: 70%;
    max-height: 100px;
}

/* ── YouTube Shorts (tournament live page grid tab + sidebar carousel) ───
   Ported verbatim from the live theme's own wws-youtube-shorts.css — byte-
   diffed against the production copy (zero diff) before porting, per the
   user's explicit "match the live site exactly" call. Class names kept
   identical (wws-shorts-*) rather than renamed, so this stays a literal,
   checkable port. */
.wws-shorts-thumb {
    border-radius: 12px;
    aspect-ratio: 9 / 16;
    cursor: pointer;
}
.wws-shorts-thumb img {
    object-fit: cover;
    object-position: center;
}
.wws-shorts-play {
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    font-size: 44px;
    color: rgba(255, 255, 255, .9);
    text-shadow: 0 2px 8px rgba(0, 0, 0, .5);
    transition: transform .2s ease, color .2s ease;
    pointer-events: none;
}
.wws-shorts-thumb:hover .wws-shorts-play {
    color: #ff0000;
    transform: translate(-50%, -50%) scale(1.15);
}
.wws-shorts-label {
    bottom: 0;
    left: 0;
    right: 0;
    padding: 20px 8px 8px;
    background: linear-gradient(to top, rgba(0, 0, 0, .7), transparent);
    line-height: 1.3;
}
.wws-shorts-label small { font-size: 11px; }
.wws-shorts-new {
    top: 8px;
    right: 8px;
    font-size: 10px;
    letter-spacing: .5px;
    z-index: 2;
}
.wws-shorts-carousel {
    position: relative;
    overflow: hidden;
    padding: 0 35px;
}
.wws-shorts-carousel .swiper-slide { width: auto; }
.wws-shorts-carousel .swiper-button-prev,
.wws-shorts-carousel .swiper-button-next {
    color: #333;
    top: 50%;
}
.wws-shorts-carousel .swiper-button-prev::after,
.wws-shorts-carousel .swiper-button-next::after { font-size: 18px; }
.wws-shorts-carousel .swiper-button-prev { left: 2px; }
.wws-shorts-carousel .swiper-button-next { right: 2px; }

/* ── Schedule tab's My Time/Event Time pill nav (tournament page) — ported
   verbatim from the inline <style> block in the real theme's own
   view-desktop-tournament-live.php (scoped there to #schedule; scoped here
   to this project's #t-tab-schedule container id instead). Bootstrap 5's
   own .nav-pills default (solid color active bg) doesn't match this. ── */
#t-tab-schedule .nav-pills .nav-link {
    border-radius: 50px;
    color: #999;
    border: 2px solid #ccc;
    margin-right: 5px;
}
#t-tab-schedule .nav-pills .nav-link.active {
    background-color: #eee;
    color: #111;
    border-color: #111;
}

/* Bootstrap 5's .table sets an opaque white --bs-table-bg on every cell by
   default, which fights the day card's own .bg-light background (shows as
   a white box per row inside the grey card) — force it transparent so the
   card's own background reads through cleanly. */
#t-tab-schedule .table > :not(caption) > * > * {
    background-color: transparent;
}

/* Same Bootstrap 5 --bs-table-bg issue as above, on the Tour Rankings table
   (public/includes/part-tour-rankings-table.php) — white cell backgrounds
   made the white ranking text unreadable. */
.tour-rankings-section .table > :not(caption) > * > * {
    background-color: transparent;
}

/* Intro tab's collapsed "The Event" description — verbatim port of the real
   theme's own #about:after (view-desktop-tournament-live.php's inline
   <style> block): a fade-to-background gradient masking the hard clip at
   the bottom of the 400px collapsed height, so truncated text fades out
   instead of being cut off mid-line. Hidden once expanded (.t-about-
   expanded, toggled by the Read More/Less JS) since there's nothing being
   truncated at that point. */
#t-about-desc::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: 0;
    width: 100%;
    height: 50px;
    background: linear-gradient(to top, #00162b, transparent);
    z-index: 2;
    pointer-events: none;
}
#t-about-desc.t-about-expanded::after {
    display: none;
}

/* "Enter Now" pulsing glow while registration is open — verbatim port of
   the real theme's own .btn.enter-now/@keyframes glowing (view-desktop-
   tournament.php's inline <style> block), applied via
   inc-participant-register-button.php only to the real actionable
   "Enter Now"/"Login & Enter" link, never to the disabled "Registration
   Opens"/"Entry Closed" states — matches this project's own $regLink
   (registration open) vs. $entryClosed condition exactly. */
.btn.enter-now {
    animation: glowing 1500ms infinite;
}
@keyframes glowing {
    0% { box-shadow: 0 0 3px #00a0df; }
    50% { box-shadow: 0 0 40px #00a0df; }
    100% { box-shadow: 0 0 3px #00a0df; }
}

/* ── Media Manager pattern background (tournament page, WWS Tour stops) ── */
.bg-theme-pattern {
    background: url('/assets/graphics/abstract-shapes-20.svg');
    background-color: #3a444c;
    color: #fff;
}

/* ── Cookie consent banner (assets/js/consent.js) ───────────────────────── */
.wws-cookie-banner {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1080;
    background: var(--wws-navy);
    color: #fff;
    padding: 1rem 1.25rem;
    box-shadow: 0 -4px 16px rgba(0, 0, 0, .25);
}
.wws-cookie-banner a { color: #fff; text-decoration: underline; }
.wws-cookie-banner-inner {
    max-width: 1100px;
    margin: 0 auto;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}
.wws-cookie-banner-inner p { font-size: .85rem; max-width: 760px; }

/* ── Photo-upload hover overlay (my-account > Athlete Profile's Banner
   Photo/Headshot) — an always-present full-cover <button> whose overlay
   styling only reveals on hover/focus, replacing a separate "Upload" button
   below the image. Parent needs position:relative + overflow:hidden (already
   true of both preview boxes) so this clips to the same rounded/circle shape. */
.wws-photo-edit-overlay {
    position: absolute;
    inset: 0;
    width: 100%;
    border: none;
    background: rgba(0, 0, 0, .55);
    color: #fff;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .25rem;
    text-align: center;
    padding: .5rem;
    font-size: .8rem;
    font-weight: 600;
    line-height: 1.3;
    opacity: 0;
    transition: opacity .15s;
    cursor: pointer;
}
.wws-photo-edit-overlay i { font-size: 1.4rem; }

/* Small "x" in a circle in the corner of a headshot/banner preview that removes the photo. Sits on the
   wrapper (outside the overflow:hidden preview box) so the circular headshot doesn't clip it. */
.wws-photo-remove {
    position: absolute;
    z-index: 3;
    width: 26px;
    height: 26px;
    padding: 0;
    border: 1px solid #cbd5e1;
    border-radius: 50%;
    background: #fff;
    color: #475569;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: .7rem;
    line-height: 1;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .25);
    cursor: pointer;
}
.wws-photo-remove:hover { background: #dc3545; border-color: #dc3545; color: #fff; }
.wws-photo-edit-overlay:hover,
.wws-photo-edit-overlay:focus-visible {
    opacity: 1;
}

/* ── Shared pill search field (assets/js/search-field.js) ─────────────────
   Usage: <div class="wws-search-field">
            <i class="bi bi-search"></i>
            <input type="text" class="form-control" placeholder="...">
            <i class="bi bi-x-circle-fill wws-search-clear" style="display:none"></i>
          </div>
   Matches the pre-existing pill+icon-inside+circular-clear look already used
   by the athlete directory search and the calendar/tournament widget search
   (both bespoke/inline-styled) — this is the same look as a proper reusable
   component for anywhere new. The script only owns the clear button (toggle
   visibility, clear + refocus + dispatch a real 'input' event on click) —
   the "search as you type" behavior itself (debounced page reload, debounced
   AJAX, etc.) stays page-specific since it depends on what the field drives. */
.wws-search-field { position: relative; }
.wws-search-field .form-control {
    border-radius: 50rem !important;
    padding-left: 2.5rem;
    padding-right: 2.5rem;
}
.wws-search-field > .bi-search {
    position: absolute;
    left: 15px;
    top: 50%;
    transform: translateY(-50%);
    color: #6c757d;
    z-index: 3;
    pointer-events: none;
}
.wws-search-clear {
    position: absolute;
    right: 15px;
    top: 50%;
    transform: translateY(-50%);
    color: #ccc;
    cursor: pointer;
    z-index: 3;
}
.wws-search-clear:hover { color: #999; }

/* Athletes directory, mobile — live's `.athletes.athlete-search` fixed bar
   (assets/scss/mobile/_athletes-page.scss). */
.athlete-search-bar-mobile {
    width: 100%;
    border-bottom: 1px solid #CCC;
    background: #EEE;
    padding: 5px 10px;
    position: fixed;
    top: 50px;
    z-index: 999;
}

/* Calendar widget, mobile — live's view-mobile.php inline <style>: smaller
   month pills/nav, 22px season selector. */
.wws-cal-mobile .wwsw-month-nav { height: 40px; }
.wws-cal-mobile .wwsw-month-pill { line-height: 30px; width: 100px; border-radius: 50rem; font-size: .8rem; }
.wws-cal-mobile #season-selector { font-size: 22px !important; }

/* My Account, mobile — profile sub-page pill strip (live's part-myaccount-profile-nav.php,
   fixed under the header) + collapse of the now-empty sidebar column. */
body.platform-mobile .col-md-3:has(> .mm-empty-nav) { display: none; }
.wws-profile-pills-spacer { height: 46px; }
.wws-profile-pills {
    position: fixed; top: 50px; left: 0; right: 0; z-index: 1020;
    display: flex; flex-wrap: nowrap; gap: 8px; overflow-x: auto;
    background: #fff; padding: 8px 12px; box-shadow: 0 1px 4px rgba(0, 0, 0, .12);
    scrollbar-width: none;
}
.wws-profile-pills::-webkit-scrollbar { display: none; }
.wws-profile-pill {
    flex: 0 0 auto; padding: .3rem .8rem; border: 1px solid #dee2e6; border-radius: 100px;
    color: #444; text-decoration: none; font-size: .85rem; white-space: nowrap;
}
.wws-profile-pill.active { border-color: var(--wws-blue); color: var(--wws-blue); font-weight: 700; }

/* Mobile header settings dropdown — icon column so the icons line up. */
body.platform-mobile header.header .dropdown-menu .dropdown-item { display: flex; align-items: center; padding-top: .55rem; padding-bottom: .55rem; }
body.platform-mobile header.header .dropdown-menu .dropdown-item .bi { width: 1.25rem; text-align: center; color: var(--wws-blue); flex-shrink: 0; }
body.platform-mobile header.header .dropdown-menu .dropdown-item .bi-box-arrow-right { color: #6c757d; }

/* My Account dashboard, mobile — the Membership card and the member-since /
   federation / license card read as ONE card (user request): no gap, shared
   corners, a hairline between them. The "Edit Profile" button next to Manage
   Membership already covers the lower card's own Edit Profile, so that one is
   hidden here. */
body.platform-mobile .member-summary-first { margin-bottom: 0 !important; }
body.platform-mobile .member-summary-membership { border-radius: .5rem .5rem 0 0 !important; }
body.platform-mobile .member-summary-details { border-radius: 0 0 .5rem .5rem !important; margin-bottom: 1.5rem; }
body.platform-mobile .member-summary-details .card-body { padding-top: 1.25rem !important; }
body.platform-mobile .member-summary-details { border-top: 1px solid #f1f3f5 !important; }
body.platform-mobile .member-summary-edit-bottom { display: none; }

/* My Account (mobile): the three account tabs stay on ONE row and scroll sideways instead of wrapping onto a second line. */
body.platform-mobile .wws-account-tabs { flex-wrap: nowrap; overflow-x: auto; white-space: nowrap; scrollbar-width: none; }
body.platform-mobile .wws-account-tabs::-webkit-scrollbar { display: none; }
body.platform-mobile .wws-account-tabs .nav-item { flex: 0 0 auto; }

/* Sponsors checklist (2 columns on phones): slightly smaller label text so "WorldWaterSkiers" fits on one line instead of breaking mid-word. */
@media (max-width: 575.98px) { .wws-company-check { font-size: .75rem; } }

/* Tournament Results tab, mobile — the "active" card normally runs flush into the detail
   panel beside it (desktop split view). On phones results are a list that swaps for a detail
   view, so the pre-selected first card must keep the same right margin and look as the rest. */
body.platform-mobile .t-results-card.active { margin-right: 0 !important; }
body.platform-mobile .t-results-card.active .bi-chevron-right { color: inherit; }

/* Hide-on-scroll header + bottom bar (mobile) — port of the old theme's main.js
   "wws-scroll-hide" behaviour: scrolling down slides the header up and the tab bar
   down off-screen, scrolling up brings them back (assets/js/app.js toggles
   body.wws-bars-hidden). Anything pinned just under the header (section pill bars,
   filter/search bars, sticky title bars) moves up to the top edge while the header
   is away so no gap is left, like live's .sticky-sub-nav.wws-header-hidden {top:0}. */
body.platform-mobile header.header,
body.platform-mobile .mobile-footer-nav { transition: transform .3s ease; will-change: transform; }
body.platform-mobile.wws-bars-hidden header.header { transform: translateY(-100%); }
body.platform-mobile.wws-bars-hidden .mobile-footer-nav { transform: translateY(100%); }
body.platform-mobile .athlete-sub-nav,
body.platform-mobile .wws-site-mnav,
body.platform-mobile .sticky-top[style*="top:50px"],
body.platform-mobile .iwwf-mobile-filter-bar,
body.platform-mobile .athlete-search-bar-mobile,
body.platform-mobile .wws-profile-pills { transition: top .3s ease; }
body.platform-mobile.wws-bars-hidden .athlete-sub-nav,
body.platform-mobile.wws-bars-hidden .wws-site-mnav,
body.platform-mobile.wws-bars-hidden .sticky-top[style*="top:50px"],
body.platform-mobile.wws-bars-hidden .iwwf-mobile-filter-bar,
body.platform-mobile.wws-bars-hidden .athlete-search-bar-mobile,
body.platform-mobile.wws-bars-hidden .wws-profile-pills { top: 0 !important; }

/* Mobile section/tab pill bar — ONE spec for every page that has it (tournament tabs, athlete
   tabs, ski-site sections): the old theme's mobile .sticky-sub-nav (mobile.scss) — bar padding
   5px 10px, pills font-size 14px / padding .4rem 1rem / fully rounded, active = light grey pill,
   one non-wrapping row that swipes sideways with no scrollbar. Desktop keeps its own sizing. */
body.platform-mobile .athlete-sub-nav { padding: 5px 10px; }
body.platform-mobile .athlete-sub-nav .container { padding-left: 0; padding-right: 0; max-width: none; }
body.platform-mobile .athlete-pill-nav { padding: 0; flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
body.platform-mobile .athlete-pill-nav::-webkit-scrollbar { display: none; }
body.platform-mobile .athlete-pill-nav .nav-item { flex: 0 0 auto; }
/* whole-pixel height (6 + 22 + 6 + 5 + 5 = 44px) so the sticky bar never lands on a fractional pixel, and a
   1px same-colour shadow under it covers the hairline of page background that could flash between the bar
   and the content below while scrolling / when the header slides away. */
body.platform-mobile .athlete-pill-nav .nav-link { font-size: 14px; padding: 6px 1rem; line-height: 22px; color: #fff; }
body.platform-mobile .athlete-sub-nav { box-shadow: 0 1px 0 0 #00162b; }
body.platform-mobile .athlete-pill-nav .nav-link.active { background: #eee; color: #00162b; }
/* tapping a pill left Bootstrap's blue focus ring around it (a dark halo on the navy bar) */
.athlete-pill-nav .nav-link:focus, .athlete-pill-nav .nav-link:focus-visible { box-shadow: none; outline: 0; }

/* ONE mobile "card" spec for every page (was copy-pasted into each mobile view's own <style> block:
   athlete + tournament; the site page, rankings etc. had their own variants). White card, 10px
   corners, soft shadow, 1rem inner padding, centred 1rem bold heading — the heading is deliberately
   smaller than desktop's section headings (live's mobile h3 is 12px vs desktop 14px). */
.athlete-mobile-card { margin-bottom: .85rem; background: #fff; border-radius: 10px; box-shadow: var(--wws-card-shadow); }
.athlete-mobile-card > .inner { padding: 1rem; }
.athlete-mobile-card h3 { text-align: center; font-size: 1rem; font-weight: 700; margin-bottom: 1rem; color: #444; }

/* WWS Overall Tour stop navigator (includes/part-tour-stop-nav.php) — shared by the desktop and
   mobile tournament pages. Navy header, year pills, numbered stop timeline. */
.wws-tournav { background: #f4f6f9; padding: 1.25rem 1rem; color: #14202e; }
.wws-tournav-card { max-width: 720px; margin: 0 auto; background: #fff; border-radius: 16px; box-shadow: var(--wws-card-shadow); overflow: hidden; }
.wws-tournav-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 1.1rem 1.25rem; color: #fff; background: linear-gradient(135deg, #00162b 0%, #093251 100%); }
.wws-tournav-eyebrow { font-size: .7rem; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: #6fc4ee; }
.wws-tournav-title { font-size: 1.35rem; font-weight: 700; line-height: 1.2; }
.wws-tournav-all { flex-shrink: 0; color: #fff; font-size: .85rem; font-weight: 600; text-decoration: none; padding: .4rem .8rem; border: 1px solid rgba(255, 255, 255, .35); border-radius: 100px; white-space: nowrap; }
.wws-tournav-all:hover { background: rgba(255, 255, 255, .12); color: #fff; }
.wws-tournav-years { display: flex; gap: 6px; padding: .75rem 1rem; overflow-x: auto; scrollbar-width: none; background: #f8fafc; border-bottom: 1px solid #e8edf3; }
.wws-tournav-years::-webkit-scrollbar { display: none; }
.wws-tournav-year { flex: 1 1 0; text-align: center; border: 0; background: transparent; color: #4a5a6e; font-weight: 600; font-size: .9rem; padding: .35rem .5rem; border-radius: 100px; cursor: pointer; }
.wws-tournav-year:hover { background: #e8edf3; }
.wws-tournav-year.active { background: var(--wws-blue); color: #fff; }
.wws-tournav-stops { list-style: none; margin: 0; padding: .5rem 0; position: relative; }
.wws-tournav-stops[hidden] { display: none; }
.wws-tournav-stop { position: relative; }
/* the connecting line between the numbered circles */
.wws-tournav-stop:not(:last-child)::after { content: ""; position: absolute; left: calc(1.25rem + 17px); top: 3.1rem; bottom: -.1rem; width: 2px; background: #dbe3ec; }
.wws-tournav-stop.done:not(:last-child)::after { background: var(--wws-blue); }
.wws-tournav-stop a { display: flex; align-items: center; gap: 14px; padding: .8rem 1.25rem; color: inherit; text-decoration: none; position: relative; z-index: 1; }
.wws-tournav-stop a:hover { background: #f4f8fc; }
.wws-tournav-num { flex: 0 0 36px; width: 36px; height: 36px; border-radius: 50%; display: flex; align-items: center; justify-content: center; background: #e8edf3; color: #4a5a6e; font-weight: 700; font-size: .95rem; }
.wws-tournav-stop.done .wws-tournav-num { background: var(--wws-blue); color: #fff; }
.wws-tournav-stop.here .wws-tournav-num { background: #00162b; color: #fff; box-shadow: 0 0 0 4px rgba(0, 160, 223, .25); }
.wws-tournav-stop.here a { background: #eef7fc; }
.wws-tournav-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.wws-tournav-name { font-weight: 700; font-size: 1.05rem; line-height: 1.25; }
.wws-tournav-meta { font-size: .85rem; color: #6b7a8d; margin-top: 2px; }
.wws-tournav-meta .bi { font-size: .8rem; margin-right: 2px; }
.wws-tournav-dot { margin: 0 .35rem; }
.wws-tournav-chev { color: #b4c0ce; flex-shrink: 0; }
.wws-tournav-here { flex-shrink: 0; font-size: .7rem; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: #fff; background: var(--wws-blue); padding: .25rem .6rem; border-radius: 100px; }
@media (max-width: 575.98px) {
    .wws-tournav { padding: .85rem .75rem; }
    .wws-tournav-title { font-size: 1.15rem; }
    .wws-tournav-name { font-size: 1rem; }
}

/* Tournament Results list cards — compact + borderless, in the tour-navigator design language.
   Used by BOTH desktop (left column) and mobile (list view) so the two stay in sync. */
.wws-rescard-group { font-size: .75rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: #6b7a8d; margin: 1.25rem 0 .9rem; display: flex; align-items: center; gap: .75rem; }
.wws-rescard-group::after { content: ""; flex: 1; height: 1px; background: #e3e9f0; }
.wws-rescard { --rc-bg: #f3f5f8; display: flex; align-items: center; gap: 12px; position: relative; background: var(--rc-bg); border-radius: 14px; padding: .55rem .9rem .55rem .7rem; margin: 0 1rem .95rem 0; cursor: pointer; transition: background .15s, box-shadow .15s; }
.wws-rescard.is-lb { --rc-bg: #e3f4fd; border-left: 4px solid var(--wws-blue); padding-left: calc(.7rem - 4px); }
.wws-rescard:hover { box-shadow: 0 3px 12px rgba(0, 22, 43, .10); }
.wws-rescard.active { --rc-bg: #cfeafa; margin-right: 0; }
.wws-rescard.active:not(.is-lb) { --rc-bg: #e1e8f0; }
.wws-rescard-icon { flex: 0 0 42px; width: 42px; height: 42px; border-radius: 50%; background: #e1e7ef; display: flex; align-items: center; justify-content: center; overflow: hidden; }
.wws-rescard.is-lb .wws-rescard-icon { background: #cdeaf9; }
.wws-rescard-icon img, .wws-rescard-icon > div { width: 30px !important; height: 30px !important; }
.wws-rescard-main { flex: 1 1 auto; min-width: 0; }
.wws-rescard-title { font-weight: 700; font-size: .92rem; line-height: 1.2; color: #14202e; }
.wws-rescard-chips { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 3px; }
.wws-rescard-chips span { font-size: .66rem; font-weight: 700; line-height: 1.35; color: #4a5a6e; background: rgba(255, 255, 255, .85); border-radius: 100px; padding: .02rem .5rem; }
.wws-rescard-chev { flex-shrink: 0; color: #9aa8b8; }
.wws-rescard.active .wws-rescard-chev { color: var(--wws-blue); }
/* the Leaderboard / Results tab on the card's top-right edge — same fill as the card so it reads as part of it */
.wws-rescard-tag { position: absolute; top: -11px; right: 16px; padding: .05rem .65rem 0; border-radius: 8px 8px 0 0; background: var(--rc-bg); font-size: .78rem; font-weight: 700; line-height: 1.3; color: #5a6a7e; }
.wws-rescard.is-lb .wws-rescard-tag { color: #0e78ab; }
body.platform-mobile .wws-rescard, body.platform-mobile .wws-rescard.active { margin-right: 0; }
body.platform-mobile .wws-rescard.active { --rc-bg: #f3f5f8; }
body.platform-mobile .wws-rescard.is-lb.active { --rc-bg: #e3f4fd; }
body.platform-mobile .wws-rescard.active .wws-rescard-chev,
body.platform-mobile .t-results-card.active .wws-rescard-chev { color: #b4c0ce; }

/* Tournament info tabs on phones (Athletes Info, Spectators Info, PDFs & Links): everything inside the
   cards reads left-aligned — headings included (the shared card heading is centred elsewhere, e.g.
   the Latest News/Videos/Photos cards, which keep that). */
#t-tab-athletes-info .athlete-mobile-card h3,
#t-tab-spectators-info .athlete-mobile-card h3,
#t-tab-pdfs .athlete-mobile-card h3,
#athlete-tab-profile .athlete-mobile-card h3 { text-align: left; }

/* Tournament Photos tab, mobile — square rounded thumbnails, two per row. */
.t-photo-grid-m { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.t-photo-grid-m > a { display: block; aspect-ratio: 1 / 1; overflow: hidden; border-radius: 14px; background: #1a2b3c; margin: 0; }
.t-photo-grid-m > a img { width: 100%; height: 100%; object-fit: cover; display: block; margin: 0 !important; border-radius: 0; box-shadow: none !important; }

/* Tournament Videos tab, mobile — rounded thumbnails to match the Photos grid. */
body.platform-mobile .t-video-grid .t-video-thumb { border-radius: 14px; overflow: hidden; }

/* last pill gets breathing room so it isn't clipped against the bar's right edge when scrolled to the end */
body.platform-mobile .athlete-pill-nav .nav-item:last-child { margin-right: 10px; }

/* Tournament Schedule — tour-navigator design language (desktop + mobile share it) */
.wws-seg { display: flex; gap: 4px; padding: 4px; background: #eef2f7; border-radius: 14px; }
.wws-seg .nav-item { flex: 1 1 0; min-width: 0; }
.wws-seg .nav-link { display: flex; flex-direction: column; align-items: center; text-align: center; border-radius: 11px; padding: .45rem .5rem; color: #4a5a6e; font-weight: 700; font-size: .95rem; line-height: 1.2; background: transparent; }
.wws-seg .nav-link small { font-size: .68rem; font-weight: 600; color: #8a97a8; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wws-seg .nav-link.active { background: #fff; color: #14202e; box-shadow: 0 1px 4px rgba(0, 22, 43, .12); }
.wws-seg .nav-link.active small { color: var(--wws-blue); }
.wws-sched-day { background: #f4f7fb; border-radius: 14px; padding: .35rem .9rem .5rem; margin-bottom: .9rem; }
.wws-sched-dayhead { font-size: .72rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--wws-blue); padding: .6rem 0 .2rem; }
.wws-sched-row { display: flex; align-items: baseline; gap: 12px; padding: .55rem 0; border-top: 1px solid #e4eaf1; }
.wws-sched-dayhead + .wws-sched-row { border-top: 0; }
.wws-sched-time { flex: 0 0 4.4rem; font-weight: 700; font-size: .95rem; color: #14202e; white-space: nowrap; }
.wws-sched-name { flex: 1 1 auto; min-width: 0; font-weight: 600; font-size: .95rem; color: #263646; line-height: 1.3; }
.wws-sched-tag { flex-shrink: 0; align-self: center; font-size: .68rem; font-weight: 700; color: #0e78ab; background: #dff1fb; border-radius: 100px; padding: .15rem .55rem; white-space: nowrap; }
@media (max-width: 575.98px) { .wws-sched-row { flex-wrap: wrap; } .wws-sched-time { flex-basis: 4rem; } .wws-sched-tag { margin-left: calc(4rem + 12px); } }

/* Mobile results detail: "Back to Results" is a pill sitting ABOVE the white card (not inside it).
   #t-tab-content gets .results-detail-open while a detail is showing (tournament.php click handler). */
body.platform-mobile #t-tab-content { position: relative; }
body.platform-mobile #t-tab-content > .t-tab-pane { border-radius: inherit; } /* square bottom corners on the white card */
body.platform-mobile #t-tab-content.results-detail-open { margin-top: 52px; }
body.platform-mobile #t-tab-content.results-detail-open .mobile-results-back {
    position: absolute; top: -44px; left: 0; padding: 7px 14px 7px 10px; margin: 0 !important;
    background: #fff; color: #00a0df !important; border-radius: 100px; font-size: 13px; font-weight: 600; line-height: 1;
    box-shadow: 0 2px 8px rgba(0,22,43,.12); text-decoration: none;
}

/* Photo + video lightboxes (athlete page, tournament page): WWS navy with some see-through so the page
   shows faintly behind. Mobile: media goes edge to edge and the prev / next arrows sit in a fixed row at
   the bottom (counter between them) so they never move with the size of the photo or video. */
.t-photo-lightbox, .t-video-lightbox { background: rgba(0, 22, 43, .84) !important; -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px); }
body.platform-mobile .t-photo-lightbox, body.platform-mobile .t-video-lightbox { padding-bottom: 110px; }
body.platform-mobile .t-photo-lightbox img { width: 100% !important; max-width: 100vw !important; max-height: calc(100vh - 230px) !important; object-fit: contain; border-radius: 0 !important; }
body.platform-mobile .t-video-lightbox .lb-frame-wrap { width: 100vw; max-width: none; border-radius: 0; }
body.platform-mobile .t-photo-lightbox .lb-nav, body.platform-mobile .t-video-lightbox .lb-nav { top: auto; bottom: 28px; transform: none; }
body.platform-mobile .t-photo-lightbox .lb-prev, body.platform-mobile .t-video-lightbox .lb-prev { left: calc(50% - 110px); }
body.platform-mobile .t-photo-lightbox .lb-next, body.platform-mobile .t-video-lightbox .lb-next { left: auto; right: calc(50% - 110px); }
body.platform-mobile .t-photo-lightbox .lb-counter, body.platform-mobile .t-video-lightbox .lb-counter { bottom: 42px; font-size: .9rem; }

/* Translucent "find" control that expands into a search field (athlete page hero, ski-sites map).
   Markup: .wws-find > button.wws-find-btn + .wws-find-panel (.wws-find-field input + .wws-find-close, results box). */
.wws-find { position: absolute; top: 12px; right: 12px; z-index: 6; }
.wws-find-btn { width: 40px; height: 40px; border-radius: 50%; border: 1px solid rgba(255,255,255,.35); background: rgba(0,22,43,.35); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); color: #fff; font-size: 16px; display: flex; align-items: center; justify-content: center; padding: 0; transition: opacity .2s; }
.wws-find-btn:active { background: rgba(0,22,43,.6); }
.wws-find-panel { display: none; position: absolute; top: 0; right: 0; width: calc(100vw - 24px); max-width: 520px; }
.wws-find.open .wws-find-btn { opacity: 0; pointer-events: none; }
.wws-find.open .wws-find-panel { display: block; }
.wws-find-field { position: relative; }
.wws-find-field .form-control { height: 40px; border: 1px solid rgba(255,255,255,.3); border-radius: 25px !important; background: rgba(0,22,43,.55); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); color: #fff; text-indent: 26px; padding-right: 44px; box-shadow: none !important; }
.wws-find-field .form-control:focus { background: rgba(0,22,43,.65); border-color: rgba(255,255,255,.55); color: #fff; }
.wws-find-field .form-control::placeholder { color: rgba(255,255,255,.65); }
.wws-find-field .bi-search { position: absolute; left: 15px; top: 50%; transform: translateY(-50%); z-index: 3; color: rgba(255,255,255,.8); font-size: 15px; line-height: 1; }
.wws-find-close { position: absolute; right: 14px; top: 50%; transform: translateY(-50%); z-index: 3; color: rgba(255,255,255,.8); cursor: pointer; font-size: 16px; line-height: 1; background: none; border: 0; padding: 0; }
.wws-find.open { left: 12px; }
.wws-find.open .wws-find-panel { width: 100%; }
.wws-find-spinner { position: absolute; right: 8px; top: 6px; width: 28px; height: 28px; border: 2px solid rgba(255,255,255,.9); border-right-color: transparent; display: none; z-index: 2; pointer-events: none; }
.wws-find .athletes-search-results, .wws-find .wws-find-results { border: 0; box-shadow: 0 3px 12px rgba(0,0,0,.35); margin: 6px 0 0; color: #444; max-height: 55vh; overflow-y: auto; border-radius: 14px; }
.wws-find .wws-find-results { background: #fff; overflow-y: auto; }

/* IWWF Weekly Rankings (mobile) — tour-navigator design language: navy header card, pill filters,
   rounded white cards per division with ranked rows (no <table>, so no white-cell-bg gotcha). */
.iwwf-mobile-filter-bar { position: fixed; top: 50px; left: 0; right: 0; z-index: 1030; background: #00162b; box-shadow: 0 1px 0 0 #00162b; padding: 8px 10px 8px; transition: top .3s ease; }
body.platform-mobile.wws-bars-hidden .iwwf-mobile-filter-bar { top: 0; }
.iwwf-mobile-filter-bar .form-select { border: 0; border-radius: 100px; background-color: rgba(255,255,255,.14); color: #fff; font-size: 14px; padding-left: 14px; --bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e"); }
.iwwf-mobile-filter-bar .form-select option, .iwwf-mobile-filter-bar .form-select optgroup { color: #222; }
.iwwf-mobile-divisions { overflow-x: auto; white-space: nowrap; -webkit-overflow-scrolling: touch; scrollbar-width: none; padding-top: 8px; }
.iwwf-mobile-divisions::-webkit-scrollbar { display: none; }
.iwwf-division-pill { display: inline-block; margin-right: 6px; padding: 5px 14px; border-radius: 100px; font-size: 13px; font-weight: 600; line-height: 20px; color: #fff; text-decoration: none; background: rgba(255,255,255,.14); }
.iwwf-division-pill.is-women { background: rgba(214,170,205,.38); }
.iwwf-division-pill:active { background: #eee; color: #00162b; }
.wws-iwwf-page { background: #f4f6f9; padding-left: 12px; padding-right: 12px; padding-bottom: 12px; min-height: 100vh; }
.wws-iwwf-head { background: linear-gradient(135deg, #00162b, #093251); color: #fff; border-radius: 16px; padding: 18px 20px; margin-bottom: 14px; box-shadow: 0 4px 18px rgba(0,22,43,.10); }
.wws-iwwf-eyebrow { font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: #6fc4ee; font-weight: 700; }
.wws-iwwf-title { font-size: 1.5rem; font-weight: 700; line-height: 1.15; margin: 2px 0 6px; }
.wws-iwwf-sub { font-size: 13px; opacity: .85; line-height: 1.5; }
.wws-iwwf-sub span { font-size: 11px; opacity: .7; }
.wws-iwwf-card { background: #fff; border-radius: 16px; box-shadow: var(--wws-card-shadow); margin-bottom: 14px; overflow: hidden; }
.wws-iwwf-anchor { position: absolute; top: -150px; }
.wws-iwwf-cardhead { background: #f8fafc; border-bottom: 1px solid #eef1f4; padding: 12px 16px; font-weight: 700; font-size: 1.05rem; color: #00162b; }
.wws-iwwf-row { display: flex; gap: 12px; padding: 9px 14px; border-top: 1px solid #f0f3f6; }
.wws-iwwf-cardhead + .wws-iwwf-row { border-top: 0; }
.wws-iwwf-rank { flex: 0 0 30px; width: 30px; height: 30px; border-radius: 50%; background: #eef1f4; color: #55616e; font-size: 13px; font-weight: 700; display: flex; align-items: center; justify-content: center; margin-top: 1px; }
.wws-iwwf-rank.top { color: #fff; }
.wws-iwwf-rank.top-1 { background: #c9a227; }
.wws-iwwf-rank.top-2 { background: #8d98a5; }
.wws-iwwf-rank.top-3 { background: #b0733b; }
.wws-iwwf-main { flex: 1; min-width: 0; }
.wws-iwwf-name { font-weight: 700; font-size: 15px; line-height: 1.2; }
.wws-iwwf-name a { color: var(--wws-blue, #00a0df); text-decoration: none; }
.wws-iwwf-country { font-size: 12px; color: #8a96a3; margin-top: 2px; }
.wws-iwwf-country img { width: 16px; height: 12px; object-fit: cover; margin-right: 3px; vertical-align: -1px; }
.wws-iwwf-scores { flex: 0 0 auto; display: flex; flex-direction: column; gap: 3px; text-align: right; align-self: center; }
.wws-iwwf-score { min-width: 0; line-height: 1.15; }
.wws-iwwf-score .lbl { display: block; font-size: 9px; color: #8a96a3; letter-spacing: .03em; white-space: nowrap; }
.wws-iwwf-score .val { display: block; font-size: 12.5px; font-weight: 600; color: #222; white-space: nowrap; }

/* ── Waterski Games (hidden feature: /wsg-info, /wsg-league, /my-account/waterski-games) ── */
.wsg-banner { background: url(/assets/img/wsg/wsg-banner-bg.jpg) no-repeat center / cover; text-align: center; }
.wsg-banner-inner { background: rgba(255,255,255,.56); }
.wsg-banner-logo { width: 80px; }
.wsg-banner-title { font-size: 22px; }
.wsg-event-btn { min-width: 200px; }
.wsg-event-btn-text { font-size: 1.3rem; font-weight: 200; vertical-align: middle; display: inline-block; margin-top: 5px; }
@media (min-width: 992px) {
    .wsg-banner-logo { width: 200px; }
    .wsg-banner-title { font-size: 2rem; }
    .wsg-event-btn-text { font-size: 2.5rem; }
}
.wsg-filters { background: #00162b; color: #fff; }
@media (min-width: 992px) { .wsg-filters { width: 300px; min-width: 300px; } }
.wsg-filters .form-select { background-color: transparent; color: #fff; border: 3px solid #fff; border-radius: 50rem; }
.wsg-filters .form-select option { color: #222; }
.wsg-subnav { background: #fff; z-index: 5; top: 0; }
.wsg-league .order { display: inline-block; width: 40px; height: 20px; line-height: 20px; border-radius: 10px; text-align: center; font-size: 1rem; }
.wsg-league table.tournament-results td, .wsg-league table.tournament-results th { vertical-align: middle; }
.wsg-league td.name { min-width: 150px; }
.wsg-league td.score { min-width: 120px; }
.wsg-league .headshots { height: 40px; width: 40px; margin-right: 12px; border-radius: 50%; object-fit: cover; flex: none; }
.wsg-athlete-name { font-size: 1rem; }
.wsg-flag { height: 13px; width: auto; margin-right: 6px; vertical-align: -1px; }
.wsg-rope-dot { font-size: 12px; font-weight: bold; margin-left: 4px; }
.wsg-board-tabs .nav-link { border: 1px solid #222; color: #222; border-radius: 50rem; margin: 0 4px; min-width: 90px; }
.wsg-board-tabs .nav-link.active { background: #222; color: #fff; }
@media (min-width: 1500px) {
    .wsg-board-tabs { display: none !important; }
    .wsg-board-panes { display: grid; grid-template-columns: 1fr 1fr; }
    .wsg-board-panes > .tab-pane { display: block !important; opacity: 1 !important; }
}
@media (max-width: 767.98px) {
    .wsg-league table.tournament-results th, .wsg-league table.tournament-results td { font-size: 12px; padding: 5px .3rem; }
    .wsg-league .order { width: 25px; font-size: 11px; }
    .wsg-league .headshots { margin-right: 8px; }
}
.wsg-rope-strip .rope-color { font-size: 9px; color: #555; padding-top: 5px; height: 26px; }
.wsg-entry-row + .wsg-entry-row { border-top: 1px solid var(--bs-border-color); }
.wsg-waiver { height: 200px; overflow: auto; border: 1px solid #ced4da; background: #f4f4f4; padding: 20px; font-size: 11px; }
.wsg-board { overflow-x: hidden; }


/* ── Athlete Profile tab, desktop (V2): cards that match the mobile Profile tab ──────────────────────────
   Built by wws_desktop_profile_cards() in view-desktop-athlete.php. Cards flow into columns (masonry). */
.wws-pgrid { column-count: 3; column-gap: 24px; padding: 1.5rem 0; }
@media (max-width: 1199.98px) { .wws-pgrid { column-count: 2; } }
@media (max-width: 767.98px)  { .wws-pgrid { column-count: 1; } }
.wws-pcard { break-inside: avoid; background: #fff; border-radius: 14px; box-shadow: var(--wws-card-shadow); padding: 1.1rem 1.35rem; margin: 0 0 24px; }
.wws-pcard-h { font-size: 1.05rem; font-weight: 700; border-left: 3px solid var(--wws-blue); padding-left: .6rem; line-height: 1.1; margin: 0 0 .5rem; color: #14232f; }
.wws-pcard .wws-prow { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; padding: .55rem 0; border-top: 1px solid #eef1f4; font-size: .88rem; }
.wws-pcard .wws-prow:first-of-type { border-top: 0; }
.wws-pcard .wws-plabel { color: var(--wws-blue); text-transform: uppercase; font-size: .72rem; letter-spacing: .03em; flex-shrink: 0; max-width: 55%; }
.wws-pcard .wws-pval { text-align: right; }
.wws-pcard .wws-prow-long { flex-direction: column; align-items: stretch; gap: .15rem; }
.wws-pcard .wws-prow-long .wws-pval { text-align: left; }

/* ── Tour stop navigator, desktop (V2): a horizontal timeline ───────────────────────────────────────────
   Same markup as mobile (public/includes/part-tour-stop-nav.php); from 992px up the stops sit in a row along a
   connecting line instead of a vertical list. Mobile keeps the vertical card. */
@media (min-width: 992px) {
    .wws-tournav { padding: 2rem 1rem; }
    .wws-tournav-card { max-width: 1140px; }
    .wws-tournav-head { padding: 1.25rem 2rem; }
    .wws-tournav-title { font-size: 1.6rem; }
    .wws-tournav-years { justify-content: center; gap: 10px; padding: .85rem 1rem; }
    .wws-tournav-year { flex: 0 0 auto; min-width: 96px; padding: .4rem 1.4rem; }

    .wws-tournav-stops { display: flex; padding: 1.5rem 1.5rem 1.75rem; }
    .wws-tournav-stop { flex: 1 1 0; min-width: 0; }
    .wws-tournav-stop a { flex-direction: column; align-items: center; text-align: center; gap: 10px; padding: .9rem .75rem; margin: 0 .25rem; border-radius: 14px; }
    .wws-tournav-main { align-items: center; flex: 0 1 auto; }
    .wws-tournav-meta { margin-top: 4px; }
    .wws-tournav-chev { display: none; }
    .wws-tournav-here { margin-top: 2px; }
    /* connecting line: from the right edge of this circle to the left edge of the next one */
    .wws-tournav-stop:not(:last-child)::after { top: calc(.9rem + 17px); bottom: auto; left: calc(50% + 28px); right: calc(-50% + 28px); width: auto; height: 3px; border-radius: 2px; }
}


/* ── Calendar "Quickview" modal (V2) — compact, scannable event details ─────────────────────────────────
   Body built by public/ajax/calendar/details.php. Panels inside the white modal are tinted (no borders);
   text is 13px so a whole event fits without scrolling much. */
#tournamentDetailsModal .modal-header { padding: .7rem 1.1rem; }
#tournamentDetailsModal .modal-title { font-size: .95rem; font-weight: 700; }
#tournamentDetailsModal .modal-footer { padding: .6rem 1.1rem; }
.wws-qv { font-size: .8125rem; line-height: 1.4; padding: 1rem 1.25rem 1.1rem; max-height: 74vh; overflow-y: auto; color: #14232f; }
.wws-qv a { text-decoration: none; }
.wws-qv .qv-muted { color: #8593a0; }
.wws-qv .qv-k { font-size: .66rem; text-transform: uppercase; letter-spacing: .06em; font-weight: 700; color: #7a8a97; }
.qv-head { margin-bottom: .85rem; }
.qv-title { font-size: 1.1rem; font-weight: 800; line-height: 1.25; }
.qv-meta { display: flex; flex-wrap: wrap; gap: .25rem 1rem; align-items: center; color: #5a6b78; margin-top: .2rem; }
.qv-meta .bi { margin-right: .2rem; }
.qv-status { font-size: .68rem; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; padding: .12rem .55rem; border-radius: 100px; background: #e4eef4; color: #116da0; }
.qv-status-on { background: #fde8e8; color: #c0392b; }
.qv-status-finished { background: #eceff2; color: #6b7a87; }
.qv-status-cancelled { background: #fde8e8; color: #c0392b; }
.qv-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(135px, 1fr)); gap: .65rem 1rem; background: #f6f8fa; border-radius: 12px; padding: .8rem 1rem; margin-bottom: 1rem; }
.qv-fact-wide { grid-column: 1 / -1; }
.qv-v { font-weight: 600; margin-top: .05rem; }
.qv-comps { display: grid; grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); gap: .85rem; }
.qv-comp { background: #f6f8fa; border-radius: 12px; padding: .85rem 1rem; }
.qv-comp-head { display: flex; justify-content: space-between; align-items: center; gap: .5rem; margin-bottom: .5rem; }
.qv-comp-title { font-weight: 800; font-size: .92rem; }
.qv-rows { display: grid; grid-template-columns: 96px 1fr; gap: .4rem .75rem; margin: 0; }
.qv-rows dt { color: #7a8a97; font-weight: 600; font-size: .75rem; padding-top: .1rem; }
.qv-rows dd { margin: 0; min-width: 0; }
.qv-pill { display: inline-block; font-size: .7rem; font-weight: 700; padding: .08rem .55rem; border-radius: 100px; background: #dfe8ef; color: #2b4256; margin: 0 .25rem .2rem 0; }
.qv-pill-class { background: #00162b; color: #fff; margin: 0 0 0 .25rem; }
.qv-pill-men { background: #c9dcee; color: #1d4466; }
.qv-pill-women { background: #f6d5e0; color: #7a2f4b; }
.qv-fee { margin-bottom: .2rem; }
.qv-fee span { display: inline-block; margin-left: .6rem; }
.qv-rounds-wrap { margin-top: .6rem; padding-top: .55rem; border-top: 1px solid #e3e9ee; }
/* the shared rounds renderer (lib/tournament_details.php) emits <br> spacing and 2 big columns — tighten it here only */
.qv-rounds { font-size: .78rem; margin-top: .2rem; }
.qv-rounds > br, .qv-rounds .col-6 > br:last-child { display: none; }
.qv-rounds small { display: block; margin-bottom: .35rem; color: #7a8a97; }
.qv-rounds .row { --bs-gutter-x: .5rem; --bs-gutter-y: .45rem; }
.qv-rounds .col-6 { width: 33.3333%; }
.qv-rounds strong { display: block; font-size: .75rem; }
.qv-rounds strong + br { display: none; }
.qv-rounds .row { row-gap: .6rem; }
.qv-nodata { padding: .5rem 0; }
.qv-desc { background: #f6f8fa; border-radius: 12px; padding: .8rem 1rem; margin-bottom: .8rem; }
@media (max-width: 575.98px) {
    .wws-qv { padding: .85rem .9rem; }
    .qv-comps { grid-template-columns: 1fr; }
    .qv-rows { grid-template-columns: 82px 1fr; }
    .qv-rounds .col-6 { width: 50%; }
}

/* ── Photos: white behind transparent images (V2) ────────────────────────────────────────────────────────
   A transparent PNG (a cut-out athlete, a logo) used to show the dark page through it. Photo grids and the
   lightboxes now put white behind every image; ordinary JPEGs cover it completely, so nothing else changes. */
.card-columns-5 img,
.t-photo-grid-m > a img,
[class*="lightbox"] img,
img[id*="lightbox"] { background-color: #fff; }


/* ── Waterski Companies page: the old site's bordered logo grid (copied from the live theme's .waterski-companies) ─
   Each logo sits in a 1px grey cell; the -1px margins make neighbouring borders overlap into one clean grid line.
   Logos are capped at 50px tall so every one has a similar weight. */
.waterski-companies .logo-grid-item { border: 1px solid #ccc; margin-right: -1px; margin-bottom: -1px; padding-left: 1px; min-height: 100px; }
.waterski-companies .logo-grid-item img { max-width: 100%; max-height: 50px; }
.waterski-companies p a { color: inherit; text-decoration: none; }   /* the old page showed the address in plain text colour */


/* ── Marketplace archive: the old site's layout (public/marketplace.php) ────────────────────────────────────── */
.marketplace-archive h3 { font-size: 1.2rem; font-weight: 700; }
.marketplace-archive .listing a:hover > div { box-shadow: var(--bs-box-shadow) !important; }
.marketplace-card-img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: .5rem; display: block; }
.marketplace-card-noimg { background: #eef1f4; color: #b4bfca; display: flex; align-items: center; justify-content: center; font-size: 2rem; }

/* Marketplace listing page: the old site's gallery (square main slide, 100px thumbnails) */
.marketplace-listing-title { font-size: 2.2rem; }
@media (max-width: 767.98px) { .marketplace-listing-title { font-size: 1.5rem; } }
.marketplace-listing h4 { font-size: 1.15rem; font-weight: 700; }
.market-slide-main { width: 100%; aspect-ratio: 1 / 1; background-size: cover; background-position: center; background-repeat: no-repeat; border-radius: 10px; }
.market-thumbs { gap: .6rem !important; }
.market-slide-thumb { width: 100px; max-width: calc(25% - .5rem); aspect-ratio: 1 / 1; background-size: cover; background-position: center; background-repeat: no-repeat; border-radius: 6px; opacity: .6; cursor: pointer; border: 2px solid transparent; }
.market-slide-thumb.active { opacity: 1; border-color: var(--wws-blue); }
.market-arrow { width: 48px; color: var(--wws-blue); font-size: 2rem; opacity: 1; background: none; border: 0; top: 40%; bottom: auto; height: 48px; }
@media (max-width: 767.98px) { .marketplace-archive .listing h3 { font-size: 1rem; } }   /* phones keep the photo-left card, just smaller */

/* Marketplace Guidelines page (public/marketplace-guidelines.php): roomy bullets like the old page */
.marketplace-guidelines li { margin-bottom: .75rem; }
.marketplace-guidelines h3 { font-size: 1.3rem; font-weight: 700; }


/* ── Home feed: every card in a row is the same height (V2) ─────────────────────────────────────────────────
   Cards have a 450px minimum and grow with long titles; the pro-event card did not, so a row mixing them looked
   uneven. Each feed column is now a flex box and its card fills it, so the whole row matches its tallest card. */
.wws-feed-col { display: flex; }
.wws-feed-col > * { flex: 1 1 100%; min-width: 0; }
.feed-pro-event-card.d-block { display: flex !important; flex-direction: column; }
.feed-pro-event-card .feed-pro-event-inner { flex: 1 1 auto; }

/* Athlete tabs: a short tab (a sparse About, no scores yet) leaves the page too short to scroll the pinned tab bar
   to the top when a tab is clicked (athlete.php scrollToSubNav). A minimum height gives that scroll room. */
.athlete-tab-pane { min-height: calc(100vh - 80px); }

/* Tab content never shorter than the screen under the pinned tab bar (mobile). A tab with only a little
   content (Results, News, PDFs, a short athlete tab) otherwise can't scroll far enough to pin the bar, so the
   click-scroll slid all the way down to the footer. The pane keeps its own background, so no stripe shows.
   Not in tournament live mode, where the panes sit inside one white card. */
body.platform-mobile #t-tab-content:not(.rounded-xl) > .t-tab-pane,
body.platform-mobile #athlete-tab-content > .athlete-tab-pane { min-height: calc(100vh - 44px); min-height: calc(100svh - 44px); }
