/* 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; }
.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); }
